relocwrapper.c revision 1.1 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