1 1.1 christos /* Relocating wrapper program. 2 1.1 christos Copyright (C) 2003, 2005-2006 Free Software Foundation, Inc. 3 1.1 christos Written by Bruno Haible <bruno (at) clisp.org>, 2003. 4 1.1 christos 5 1.1 christos This program is free software; you can redistribute it and/or modify 6 1.1 christos it under the terms of the GNU General Public License as published by 7 1.1 christos the Free Software Foundation; either version 2, or (at your option) 8 1.1 christos any later version. 9 1.1 christos 10 1.1 christos This program is distributed in the hope that it will be useful, 11 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 12 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 1.1 christos GNU General Public License for more details. 14 1.1 christos 15 1.1 christos You should have received a copy of the GNU General Public License 16 1.1 christos along with this program; if not, write to the Free Software Foundation, 17 1.1 christos Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ 18 1.1 christos 19 1.1 christos /* Dependencies: 20 1.1 christos relocwrapper 21 1.1 christos -> progname 22 1.1 christos -> progreloc 23 1.1 christos -> xreadlink 24 1.1 christos -> readlink 25 1.1 christos -> canonicalize 26 1.1 christos -> allocsa 27 1.1 christos -> relocatable 28 1.1 christos -> setenv 29 1.1 christos -> allocsa 30 1.1 christos -> strerror 31 1.1 christos 32 1.1 christos Macros that need to be set while compiling this file: 33 1.1 christos - ENABLE_RELOCATABLE 1 34 1.1 christos - INSTALLPREFIX the base installation directory 35 1.1 christos - INSTALLDIR the directory into which this program is installed 36 1.1 christos - LIBPATHVAR the platform dependent runtime library path variable 37 1.1 christos - LIBDIRS a comma-terminated list of strings representing the list of 38 1.1 christos directories that contain the libraries at installation time 39 1.1 christos 40 1.1 christos We don't want to internationalize this wrapper because then it would 41 1.1 christos depend on libintl and therefore need relocation itself. So use only 42 1.1 christos libc functions, no gettext(), no error(), no xmalloc(), no xsetenv(). 43 1.1 christos */ 44 1.1 christos 45 1.1 christos #include <config.h> 46 1.1 christos 47 1.1 christos #include <stdio.h> 48 1.1 christos #include <stdlib.h> 49 1.1 christos #include <string.h> 50 1.1 christos #if HAVE_UNISTD_H 51 1.1 christos # include <unistd.h> 52 1.1 christos #endif 53 1.1 christos #include <errno.h> 54 1.1 christos 55 1.1 christos #include "progname.h" 56 1.1 christos #include "relocatable.h" 57 1.1 christos #include "setenv.h" 58 1.1 christos 59 1.1 christos /* Return a copy of the filename, with an extra ".bin" at the end. 60 1.1 christos More generally, it replaces "${EXEEXT}" at the end with ".bin${EXEEXT}". */ 61 1.1 christos static char * 62 1.1 christos add_dotbin (const char *filename) 63 1.1 christos { 64 1.1 christos size_t filename_len = strlen (filename); 65 1.1 christos char *result = (char *) malloc (filename_len + 4 + 1); 66 1.1 christos 67 1.1 christos if (result != NULL) 68 1.1 christos { 69 1.1 christos if (sizeof (EXEEXT) > sizeof ("")) 70 1.1 christos { 71 1.1 christos /* EXEEXT handling. */ 72 1.1 christos const size_t exeext_len = sizeof (EXEEXT) - sizeof (""); 73 1.1 christos static const char exeext[] = EXEEXT; 74 1.1 christos if (filename_len > exeext_len) 75 1.1 christos { 76 1.1 christos /* Compare using an inlined copy of c_strncasecmp(), because 77 1.1 christos the filenames may have undergone a case conversion since 78 1.1 christos they were packaged. In other words, EXEEXT may be ".exe" 79 1.1 christos on one system and ".EXE" on another. */ 80 1.1 christos const char *s1 = filename + filename_len - exeext_len; 81 1.1 christos const char *s2 = exeext; 82 1.1 christos for (; *s1 != '\0'; s1++, s2++) 83 1.1 christos { 84 1.1 christos unsigned char c1 = *s1; 85 1.1 christos unsigned char c2 = *s2; 86 1.1 christos if ((c1 >= 'A' && c1 <= 'Z' ? c1 - 'A' + 'a' : c1) 87 1.1 christos != (c2 >= 'A' && c2 <= 'Z' ? c2 - 'A' + 'a' : c2)) 88 1.1 christos goto simple_append; 89 1.1 christos } 90 1.1 christos /* Insert ".bin" before EXEEXT or its equivalent. */ 91 1.1 christos memcpy (result, filename, filename_len - exeext_len); 92 1.1 christos memcpy (result + filename_len - exeext_len, ".bin", 4); 93 1.1 christos memcpy (result + filename_len - exeext_len + 4, 94 1.1 christos filename + filename_len - exeext_len, 95 1.1 christos exeext_len + 1); 96 1.1 christos return result; 97 1.1 christos } 98 1.1 christos } 99 1.1 christos simple_append: 100 1.1 christos /* Simply append ".bin". */ 101 1.1 christos memcpy (result, filename, filename_len); 102 1.1 christos memcpy (result + filename_len, ".bin", 4 + 1); 103 1.1 christos return result; 104 1.1 christos } 105 1.1 christos else 106 1.1 christos { 107 1.1 christos fprintf (stderr, "%s: %s\n", program_name, "memory exhausted"); 108 1.1 christos exit (1); 109 1.1 christos } 110 1.1 christos } 111 1.1 christos 112 1.1 christos /* List of directories that contain the libraries. */ 113 1.1 christos static const char *libdirs[] = { LIBDIRS NULL }; 114 1.1 christos /* Verify that at least one directory is given. */ 115 1.1 christos typedef int verify1[2 * (sizeof (libdirs) / sizeof (libdirs[0]) > 1) - 1]; 116 1.1 christos 117 1.1 christos /* Relocate the list of directories that contain the libraries. */ 118 1.1 christos static void 119 1.1 christos relocate_libdirs () 120 1.1 christos { 121 1.1 christos size_t i; 122 1.1 christos 123 1.1 christos for (i = 0; i < sizeof (libdirs) / sizeof (libdirs[0]) - 1; i++) 124 1.1 christos libdirs[i] = relocate (libdirs[i]); 125 1.1 christos } 126 1.1 christos 127 1.1 christos /* Activate the list of directories in the LIBPATHVAR. */ 128 1.1 christos static void 129 1.1 christos activate_libdirs () 130 1.1 christos { 131 1.1 christos const char *old_value; 132 1.1 christos size_t total; 133 1.1 christos size_t i; 134 1.1 christos char *value; 135 1.1 christos char *p; 136 1.1 christos 137 1.1 christos old_value = getenv (LIBPATHVAR); 138 1.1 christos if (old_value == NULL) 139 1.1 christos old_value = ""; 140 1.1 christos 141 1.1 christos total = 0; 142 1.1 christos for (i = 0; i < sizeof (libdirs) / sizeof (libdirs[0]) - 1; i++) 143 1.1 christos total += strlen (libdirs[i]) + 1; 144 1.1 christos total += strlen (old_value) + 1; 145 1.1 christos 146 1.1 christos value = (char *) malloc (total); 147 1.1 christos if (value == NULL) 148 1.1 christos { 149 1.1 christos fprintf (stderr, "%s: %s\n", program_name, "memory exhausted"); 150 1.1 christos exit (1); 151 1.1 christos } 152 1.1 christos p = value; 153 1.1 christos for (i = 0; i < sizeof (libdirs) / sizeof (libdirs[0]) - 1; i++) 154 1.1 christos { 155 1.1 christos size_t len = strlen (libdirs[i]); 156 1.1 christos memcpy (p, libdirs[i], len); 157 1.1 christos p += len; 158 1.1 christos *p++ = ':'; 159 1.1 christos } 160 1.1 christos if (old_value[0] != '\0') 161 1.1 christos strcpy (p, old_value); 162 1.1 christos else 163 1.1 christos p[-1] = '\0'; 164 1.1 christos 165 1.1 christos if (setenv (LIBPATHVAR, value, 1) < 0) 166 1.1 christos { 167 1.1 christos fprintf (stderr, "%s: %s\n", program_name, "memory exhausted"); 168 1.1 christos exit (1); 169 1.1 christos } 170 1.1 christos } 171 1.1 christos 172 1.1 christos int 173 1.1 christos main (int argc, char *argv[]) 174 1.1 christos { 175 1.1 christos char *full_program_name; 176 1.1 christos 177 1.1 christos /* Set the program name and perform preparations for 178 1.1 christos get_full_program_name() and relocate(). */ 179 1.1 christos set_program_name_and_installdir (argv[0], INSTALLPREFIX, INSTALLDIR); 180 1.1 christos 181 1.1 christos /* Get the full program path. (Important if accessed through a symlink.) */ 182 1.1 christos full_program_name = get_full_program_name (); 183 1.1 christos if (full_program_name == NULL) 184 1.1 christos full_program_name = argv[0]; 185 1.1 christos 186 1.1 christos /* Invoke the real program, with suffix ".bin". */ 187 1.1 christos argv[0] = add_dotbin (full_program_name); 188 1.1 christos relocate_libdirs (); 189 1.1 christos activate_libdirs (); 190 1.1 christos execv (argv[0], argv); 191 1.1 christos fprintf (stderr, "%s: could not execute %s: %s\n", 192 1.1 christos program_name, argv[0], strerror (errno)); 193 1.1 christos exit (127); 194 1.1 christos } 195