progreloc.c revision 1.1.1.1 1 1.1 christos /* Provide relocatable programs.
2 1.1 christos Copyright (C) 2003-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
20 1.1 christos #include <config.h>
21 1.1 christos
22 1.1 christos /* Specification. */
23 1.1 christos #include "progname.h"
24 1.1 christos
25 1.1 christos #include <stdbool.h>
26 1.1 christos #include <stdio.h>
27 1.1 christos #include <stdlib.h>
28 1.1 christos #include <string.h>
29 1.1 christos #include <fcntl.h>
30 1.1 christos #if HAVE_UNISTD_H
31 1.1 christos # include <unistd.h>
32 1.1 christos #endif
33 1.1 christos #include <sys/stat.h>
34 1.1 christos
35 1.1 christos /* Get declaration of _NSGetExecutablePath on MacOS X 10.2 or newer. */
36 1.1 christos #if HAVE_MACH_O_DYLD_H
37 1.1 christos # include <mach-o/dyld.h>
38 1.1 christos #endif
39 1.1 christos
40 1.1 christos #if defined _WIN32 || defined __WIN32__
41 1.1 christos # define WIN32_NATIVE
42 1.1 christos #endif
43 1.1 christos
44 1.1 christos #if defined WIN32_NATIVE || defined __CYGWIN__
45 1.1 christos # define WIN32_LEAN_AND_MEAN
46 1.1 christos # include <windows.h>
47 1.1 christos #endif
48 1.1 christos
49 1.1 christos #include "xreadlink.h"
50 1.1 christos #include "canonicalize.h"
51 1.1 christos #include "relocatable.h"
52 1.1 christos
53 1.1 christos #ifdef NO_XMALLOC
54 1.1 christos # define xmalloc malloc
55 1.1 christos # define xstrdup strdup
56 1.1 christos #else
57 1.1 christos # include "xalloc.h"
58 1.1 christos #endif
59 1.1 christos
60 1.1 christos /* Pathname support.
61 1.1 christos ISSLASH(C) tests whether C is a directory separator character.
62 1.1 christos IS_PATH_WITH_DIR(P) tests whether P contains a directory specification.
63 1.1 christos */
64 1.1 christos #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
65 1.1 christos /* Win32, Cygwin, OS/2, DOS */
66 1.1 christos # define ISSLASH(C) ((C) == '/' || (C) == '\\')
67 1.1 christos # define HAS_DEVICE(P) \
68 1.1 christos ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
69 1.1 christos && (P)[1] == ':')
70 1.1 christos # define IS_PATH_WITH_DIR(P) \
71 1.1 christos (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
72 1.1 christos # define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
73 1.1 christos #else
74 1.1 christos /* Unix */
75 1.1 christos # define ISSLASH(C) ((C) == '/')
76 1.1 christos # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
77 1.1 christos # define FILE_SYSTEM_PREFIX_LEN(P) 0
78 1.1 christos #endif
79 1.1 christos
80 1.1 christos #undef set_program_name
81 1.1 christos
82 1.1 christos
83 1.1 christos #if ENABLE_RELOCATABLE
84 1.1 christos
85 1.1 christos #ifdef __linux__
86 1.1 christos /* File descriptor of the executable.
87 1.1 christos (Only used to verify that we find the correct executable.) */
88 1.1 christos static int executable_fd = -1;
89 1.1 christos #endif
90 1.1 christos
91 1.1 christos /* Tests whether a given pathname may belong to the executable. */
92 1.1 christos static bool
93 1.1 christos maybe_executable (const char *filename)
94 1.1 christos {
95 1.1 christos /* Woe32 lacks the access() function, but Cygwin doesn't. */
96 1.1 christos #if !(defined WIN32_NATIVE && !defined __CYGWIN__)
97 1.1 christos if (access (filename, X_OK) < 0)
98 1.1 christos return false;
99 1.1 christos
100 1.1 christos #ifdef __linux__
101 1.1 christos if (executable_fd >= 0)
102 1.1 christos {
103 1.1 christos /* If we already have an executable_fd, check that filename points to
104 1.1 christos the same inode. */
105 1.1 christos struct stat statexe;
106 1.1 christos struct stat statfile;
107 1.1 christos
108 1.1 christos if (fstat (executable_fd, &statexe) >= 0)
109 1.1 christos {
110 1.1 christos if (stat (filename, &statfile) < 0)
111 1.1 christos return false;
112 1.1 christos if (!(statfile.st_dev
113 1.1 christos && statfile.st_dev == statexe.st_dev
114 1.1 christos && statfile.st_ino == statexe.st_ino))
115 1.1 christos return false;
116 1.1 christos }
117 1.1 christos }
118 1.1 christos #endif
119 1.1 christos #endif
120 1.1 christos
121 1.1 christos return true;
122 1.1 christos }
123 1.1 christos
124 1.1 christos /* Determine the full pathname of the current executable, freshly allocated.
125 1.1 christos Return NULL if unknown.
126 1.1 christos Guaranteed to work on Linux and Woe32. Likely to work on the other
127 1.1 christos Unixes (maybe except BeOS), under most conditions. */
128 1.1 christos static char *
129 1.1 christos find_executable (const char *argv0)
130 1.1 christos {
131 1.1 christos #if defined WIN32_NATIVE || defined __CYGWIN__
132 1.1 christos char location[MAX_PATH];
133 1.1 christos int length = GetModuleFileName (NULL, location, sizeof (location));
134 1.1 christos if (length < 0)
135 1.1 christos return NULL;
136 1.1 christos if (!IS_PATH_WITH_DIR (location))
137 1.1 christos /* Shouldn't happen. */
138 1.1 christos return NULL;
139 1.1 christos {
140 1.1 christos #if defined __CYGWIN__
141 1.1 christos /* cygwin-1.5.13 (2005-03-01) or newer would also allow a Linux-like
142 1.1 christos implementation: readlink of "/proc/self/exe". But using the
143 1.1 christos result of the Win32 system call is simpler and is consistent with the
144 1.1 christos code in relocatable.c. */
145 1.1 christos /* On Cygwin, we need to convert paths coming from Win32 system calls
146 1.1 christos to the Unix-like slashified notation. */
147 1.1 christos static char location_as_posix_path[2 * MAX_PATH];
148 1.1 christos /* There's no error return defined for cygwin_conv_to_posix_path.
149 1.1 christos See cygwin-api/func-cygwin-conv-to-posix-path.html.
150 1.1 christos Does it overflow the buffer of expected size MAX_PATH or does it
151 1.1 christos truncate the path? I don't know. Let's catch both. */
152 1.1 christos cygwin_conv_to_posix_path (location, location_as_posix_path);
153 1.1 christos location_as_posix_path[MAX_PATH - 1] = '\0';
154 1.1 christos if (strlen (location_as_posix_path) >= MAX_PATH - 1)
155 1.1 christos /* A sign of buffer overflow or path truncation. */
156 1.1 christos return NULL;
157 1.1 christos /* Call canonicalize_file_name, because Cygwin supports symbolic links. */
158 1.1 christos return canonicalize_file_name (location_as_posix_path);
159 1.1 christos #else
160 1.1 christos return xstrdup (location);
161 1.1 christos #endif
162 1.1 christos }
163 1.1 christos #else /* Unix && !Cygwin */
164 1.1 christos #ifdef __linux__
165 1.1 christos /* The executable is accessible as /proc/<pid>/exe. In newer Linux
166 1.1 christos versions, also as /proc/self/exe. Linux >= 2.1 provides a symlink
167 1.1 christos to the true pathname; older Linux versions give only device and ino,
168 1.1 christos enclosed in brackets, which we cannot use here. */
169 1.1 christos {
170 1.1 christos char *link;
171 1.1 christos
172 1.1 christos link = xreadlink ("/proc/self/exe");
173 1.1 christos if (link != NULL && link[0] != '[')
174 1.1 christos return link;
175 1.1 christos if (executable_fd < 0)
176 1.1 christos executable_fd = open ("/proc/self/exe", O_RDONLY, 0);
177 1.1 christos
178 1.1 christos {
179 1.1 christos char buf[6+10+5];
180 1.1 christos sprintf (buf, "/proc/%d/exe", getpid ());
181 1.1 christos link = xreadlink (buf);
182 1.1 christos if (link != NULL && link[0] != '[')
183 1.1 christos return link;
184 1.1 christos if (executable_fd < 0)
185 1.1 christos executable_fd = open (buf, O_RDONLY, 0);
186 1.1 christos }
187 1.1 christos }
188 1.1 christos #endif
189 1.1 christos #if HAVE_MACH_O_DYLD_H && HAVE__NSGETEXECUTABLEPATH
190 1.1 christos /* On MacOS X 10.2 or newer, the function
191 1.1 christos int _NSGetExecutablePath (char *buf, unsigned long *bufsize);
192 1.1 christos can be used to retrieve the executable's full path. */
193 1.1 christos char location[4096];
194 1.1 christos unsigned long length = sizeof (location);
195 1.1 christos if (_NSGetExecutablePath (location, &length) == 0
196 1.1 christos && location[0] == '/')
197 1.1 christos return canonicalize_file_name (location);
198 1.1 christos #endif
199 1.1 christos /* Guess the executable's full path. We assume the executable has been
200 1.1 christos called via execlp() or execvp() with properly set up argv[0]. The
201 1.1 christos login(1) convention to add a '-' prefix to argv[0] is not supported. */
202 1.1 christos {
203 1.1 christos bool has_slash = false;
204 1.1 christos {
205 1.1 christos const char *p;
206 1.1 christos for (p = argv0; *p; p++)
207 1.1 christos if (*p == '/')
208 1.1 christos {
209 1.1 christos has_slash = true;
210 1.1 christos break;
211 1.1 christos }
212 1.1 christos }
213 1.1 christos if (!has_slash)
214 1.1 christos {
215 1.1 christos /* exec searches paths without slashes in the directory list given
216 1.1 christos by $PATH. */
217 1.1 christos const char *path = getenv ("PATH");
218 1.1 christos
219 1.1 christos if (path != NULL)
220 1.1 christos {
221 1.1 christos const char *p;
222 1.1 christos const char *p_next;
223 1.1 christos
224 1.1 christos for (p = path; *p; p = p_next)
225 1.1 christos {
226 1.1 christos const char *q;
227 1.1 christos size_t p_len;
228 1.1 christos char *concat_name;
229 1.1 christos
230 1.1 christos for (q = p; *q; q++)
231 1.1 christos if (*q == ':')
232 1.1 christos break;
233 1.1 christos p_len = q - p;
234 1.1 christos p_next = (*q == '\0' ? q : q + 1);
235 1.1 christos
236 1.1 christos /* We have a path item at p, of length p_len.
237 1.1 christos Now concatenate the path item and argv0. */
238 1.1 christos concat_name = (char *) xmalloc (p_len + strlen (argv0) + 2);
239 1.1 christos #ifdef NO_XMALLOC
240 1.1 christos if (concat_name == NULL)
241 1.1 christos return NULL;
242 1.1 christos #endif
243 1.1 christos if (p_len == 0)
244 1.1 christos /* An empty PATH element designates the current directory. */
245 1.1 christos strcpy (concat_name, argv0);
246 1.1 christos else
247 1.1 christos {
248 1.1 christos memcpy (concat_name, p, p_len);
249 1.1 christos concat_name[p_len] = '/';
250 1.1 christos strcpy (concat_name + p_len + 1, argv0);
251 1.1 christos }
252 1.1 christos if (maybe_executable (concat_name))
253 1.1 christos return canonicalize_file_name (concat_name);
254 1.1 christos free (concat_name);
255 1.1 christos }
256 1.1 christos }
257 1.1 christos /* Not found in the PATH, assume the current directory. */
258 1.1 christos }
259 1.1 christos /* exec treats paths containing slashes as relative to the current
260 1.1 christos directory. */
261 1.1 christos if (maybe_executable (argv0))
262 1.1 christos return canonicalize_file_name (argv0);
263 1.1 christos }
264 1.1 christos /* No way to find the executable. */
265 1.1 christos return NULL;
266 1.1 christos #endif
267 1.1 christos }
268 1.1 christos
269 1.1 christos /* Full pathname of executable, or NULL. */
270 1.1 christos static char *executable_fullname;
271 1.1 christos
272 1.1 christos static void
273 1.1 christos prepare_relocate (const char *orig_installprefix, const char *orig_installdir,
274 1.1 christos const char *argv0)
275 1.1 christos {
276 1.1 christos const char *curr_prefix;
277 1.1 christos
278 1.1 christos /* Determine the full pathname of the current executable. */
279 1.1 christos executable_fullname = find_executable (argv0);
280 1.1 christos
281 1.1 christos /* Determine the current installation prefix from it. */
282 1.1 christos curr_prefix = compute_curr_prefix (orig_installprefix, orig_installdir,
283 1.1 christos executable_fullname);
284 1.1 christos if (curr_prefix != NULL)
285 1.1 christos /* Now pass this prefix to all copies of the relocate.c source file. */
286 1.1 christos set_relocation_prefix (orig_installprefix, curr_prefix);
287 1.1 christos }
288 1.1 christos
289 1.1 christos /* Set program_name, based on argv[0], and original installation prefix and
290 1.1 christos directory, for relocatability. */
291 1.1 christos void
292 1.1 christos set_program_name_and_installdir (const char *argv0,
293 1.1 christos const char *orig_installprefix,
294 1.1 christos const char *orig_installdir)
295 1.1 christos {
296 1.1 christos const char *argv0_stripped = argv0;
297 1.1 christos
298 1.1 christos /* Relocatable programs are renamed to .bin by install-reloc. Or, more
299 1.1 christos generally, their suffix is changed from $exeext to .bin$exeext.
300 1.1 christos Remove the ".bin" here. */
301 1.1 christos {
302 1.1 christos size_t argv0_len = strlen (argv0);
303 1.1 christos const size_t exeext_len = sizeof (EXEEXT) - sizeof ("");
304 1.1 christos if (argv0_len > 4 + exeext_len)
305 1.1 christos if (memcmp (argv0 + argv0_len - exeext_len - 4, ".bin", 4) == 0)
306 1.1 christos {
307 1.1 christos if (sizeof (EXEEXT) > sizeof (""))
308 1.1 christos {
309 1.1 christos /* Compare using an inlined copy of c_strncasecmp(), because
310 1.1 christos the filenames may have undergone a case conversion since
311 1.1 christos they were packaged. In other words, EXEEXT may be ".exe"
312 1.1 christos on one system and ".EXE" on another. */
313 1.1 christos static const char exeext[] = EXEEXT;
314 1.1 christos const char *s1 = argv0 + argv0_len - exeext_len;
315 1.1 christos const char *s2 = exeext;
316 1.1 christos for (; *s1 != '\0'; s1++, s2++)
317 1.1 christos {
318 1.1 christos unsigned char c1 = *s1;
319 1.1 christos unsigned char c2 = *s2;
320 1.1 christos if ((c1 >= 'A' && c1 <= 'Z' ? c1 - 'A' + 'a' : c1)
321 1.1 christos != (c2 >= 'A' && c2 <= 'Z' ? c2 - 'A' + 'a' : c2))
322 1.1 christos goto done_stripping;
323 1.1 christos }
324 1.1 christos }
325 1.1 christos /* Remove ".bin" before EXEEXT or its equivalent. */
326 1.1 christos {
327 1.1 christos char *shorter = (char *) xmalloc (argv0_len - 4 + 1);
328 1.1 christos #ifdef NO_XMALLOC
329 1.1 christos if (shorter != NULL)
330 1.1 christos #endif
331 1.1 christos {
332 1.1 christos memcpy (shorter, argv0, argv0_len - exeext_len - 4);
333 1.1 christos if (sizeof (EXEEXT) > sizeof (""))
334 1.1 christos memcpy (shorter + argv0_len - exeext_len - 4,
335 1.1 christos argv0 + argv0_len - exeext_len - 4,
336 1.1 christos exeext_len);
337 1.1 christos shorter[argv0_len - 4] = '\0';
338 1.1 christos argv0_stripped = shorter;
339 1.1 christos }
340 1.1 christos }
341 1.1 christos done_stripping: ;
342 1.1 christos }
343 1.1 christos }
344 1.1 christos
345 1.1 christos set_program_name (argv0_stripped);
346 1.1 christos
347 1.1 christos prepare_relocate (orig_installprefix, orig_installdir, argv0);
348 1.1 christos }
349 1.1 christos
350 1.1 christos /* Return the full pathname of the current executable, based on the earlier
351 1.1 christos call to set_program_name_and_installdir. Return NULL if unknown. */
352 1.1 christos char *
353 1.1 christos get_full_program_name (void)
354 1.1 christos {
355 1.1 christos return executable_fullname;
356 1.1 christos }
357 1.1 christos
358 1.1 christos #endif
359