1 /* Provide relocatable programs.
2 Copyright (C) 2003-2010 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2003.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
32 /* Get declaration of _NSGetExecutablePath on MacOS X 10.2 or newer. */
33 #if HAVE_MACH_O_DYLD_H
34 # include <mach-o/dyld.h>
37 #if defined _WIN32 || defined __WIN32__
41 #if defined WIN32_NATIVE || defined __CYGWIN__
42 # define WIN32_LEAN_AND_MEAN
46 #include "relocatable.h"
49 # include "areadlink.h"
50 # define xreadlink areadlink
52 # include "xreadlink.h"
56 # define xmalloc malloc
57 # define xstrdup strdup
63 # define O_EXEC O_RDONLY /* This is often close enough in older systems. */
66 /* Declare canonicalize_file_name.
67 The <stdlib.h> included above may be the system's one, not the gnulib
69 extern char * canonicalize_file_name (const char *name);
72 ISSLASH(C) tests whether C is a directory separator character.
73 IS_PATH_WITH_DIR(P) tests whether P contains a directory specification.
75 #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
76 /* Win32, Cygwin, OS/2, DOS */
77 # define ISSLASH(C) ((C) == '/' || (C) == '\\')
78 # define HAS_DEVICE(P) \
79 ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
81 # define IS_PATH_WITH_DIR(P) \
82 (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
83 # define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
86 # define ISSLASH(C) ((C) == '/')
87 # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
88 # define FILE_SYSTEM_PREFIX_LEN(P) 0
91 /* The results of open() in this file are not used with fchdir,
92 therefore save some unnecessary work in fchdir.c. */
96 /* Use the system functions, not the gnulib overrides in this file. */
100 #undef set_program_name
103 #if ENABLE_RELOCATABLE
106 /* File descriptor of the executable.
107 (Only used to verify that we find the correct executable.) */
108 static int executable_fd = -1;
111 /* Tests whether a given pathname may belong to the executable. */
113 maybe_executable (const char *filename)
115 /* Woe32 lacks the access() function, but Cygwin doesn't. */
116 #if !(defined WIN32_NATIVE && !defined __CYGWIN__)
117 if (access (filename, X_OK) < 0)
121 if (executable_fd >= 0)
123 /* If we already have an executable_fd, check that filename points to
126 struct stat statfile;
128 if (fstat (executable_fd, &statexe) >= 0)
130 if (stat (filename, &statfile) < 0)
132 if (!(statfile.st_dev
133 && statfile.st_dev == statexe.st_dev
134 && statfile.st_ino == statexe.st_ino))
144 /* Determine the full pathname of the current executable, freshly allocated.
145 Return NULL if unknown.
146 Guaranteed to work on Linux and Woe32. Likely to work on the other
147 Unixes (maybe except BeOS), under most conditions. */
149 find_executable (const char *argv0)
151 #if defined WIN32_NATIVE || defined __CYGWIN__
152 char location[MAX_PATH];
153 int length = GetModuleFileName (NULL, location, sizeof (location));
156 if (!IS_PATH_WITH_DIR (location))
157 /* Shouldn't happen. */
160 #if defined __CYGWIN__
161 /* cygwin-1.5.13 (2005-03-01) or newer would also allow a Linux-like
162 implementation: readlink of "/proc/self/exe". But using the
163 result of the Win32 system call is simpler and is consistent with the
164 code in relocatable.c. */
165 /* On Cygwin, we need to convert paths coming from Win32 system calls
166 to the Unix-like slashified notation. */
167 static char location_as_posix_path[2 * MAX_PATH];
168 /* There's no error return defined for cygwin_conv_to_posix_path.
169 See cygwin-api/func-cygwin-conv-to-posix-path.html.
170 Does it overflow the buffer of expected size MAX_PATH or does it
171 truncate the path? I don't know. Let's catch both. */
172 cygwin_conv_to_posix_path (location, location_as_posix_path);
173 location_as_posix_path[MAX_PATH - 1] = '\0';
174 if (strlen (location_as_posix_path) >= MAX_PATH - 1)
175 /* A sign of buffer overflow or path truncation. */
177 /* Call canonicalize_file_name, because Cygwin supports symbolic links. */
178 return canonicalize_file_name (location_as_posix_path);
180 return xstrdup (location);
183 #else /* Unix && !Cygwin */
185 /* The executable is accessible as /proc/<pid>/exe. In newer Linux
186 versions, also as /proc/self/exe. Linux >= 2.1 provides a symlink
187 to the true pathname; older Linux versions give only device and ino,
188 enclosed in brackets, which we cannot use here. */
192 link = xreadlink ("/proc/self/exe");
193 if (link != NULL && link[0] != '[')
195 if (executable_fd < 0)
196 executable_fd = open ("/proc/self/exe", O_EXEC, 0);
200 sprintf (buf, "/proc/%d/exe", getpid ());
201 link = xreadlink (buf);
202 if (link != NULL && link[0] != '[')
204 if (executable_fd < 0)
205 executable_fd = open (buf, O_EXEC, 0);
209 #if HAVE_MACH_O_DYLD_H && HAVE__NSGETEXECUTABLEPATH
210 /* On MacOS X 10.2 or newer, the function
211 int _NSGetExecutablePath (char *buf, uint32_t *bufsize);
212 can be used to retrieve the executable's full path. */
214 unsigned int length = sizeof (location);
215 if (_NSGetExecutablePath (location, &length) == 0
216 && location[0] == '/')
217 return canonicalize_file_name (location);
219 /* Guess the executable's full path. We assume the executable has been
220 called via execlp() or execvp() with properly set up argv[0]. The
221 login(1) convention to add a '-' prefix to argv[0] is not supported. */
223 bool has_slash = false;
226 for (p = argv0; *p; p++)
235 /* exec searches paths without slashes in the directory list given
237 const char *path = getenv ("PATH");
244 for (p = path; *p; p = p_next)
254 p_next = (*q == '\0' ? q : q + 1);
256 /* We have a path item at p, of length p_len.
257 Now concatenate the path item and argv0. */
258 concat_name = (char *) xmalloc (p_len + strlen (argv0) + 2);
260 if (concat_name == NULL)
264 /* An empty PATH element designates the current directory. */
265 strcpy (concat_name, argv0);
268 memcpy (concat_name, p, p_len);
269 concat_name[p_len] = '/';
270 strcpy (concat_name + p_len + 1, argv0);
272 if (maybe_executable (concat_name))
273 return canonicalize_file_name (concat_name);
277 /* Not found in the PATH, assume the current directory. */
279 /* exec treats paths containing slashes as relative to the current
281 if (maybe_executable (argv0))
282 return canonicalize_file_name (argv0);
284 /* No way to find the executable. */
289 /* Full pathname of executable, or NULL. */
290 static char *executable_fullname;
293 prepare_relocate (const char *orig_installprefix, const char *orig_installdir,
298 /* Determine the full pathname of the current executable. */
299 executable_fullname = find_executable (argv0);
301 /* Determine the current installation prefix from it. */
302 curr_prefix = compute_curr_prefix (orig_installprefix, orig_installdir,
303 executable_fullname);
304 if (curr_prefix != NULL)
306 /* Now pass this prefix to all copies of the relocate.c source file. */
307 set_relocation_prefix (orig_installprefix, curr_prefix);
313 /* Set program_name, based on argv[0], and original installation prefix and
314 directory, for relocatability. */
316 set_program_name_and_installdir (const char *argv0,
317 const char *orig_installprefix,
318 const char *orig_installdir)
320 const char *argv0_stripped = argv0;
322 /* Relocatable programs are renamed to .bin by install-reloc. Or, more
323 generally, their suffix is changed from $exeext to .bin$exeext.
324 Remove the ".bin" here. */
326 size_t argv0_len = strlen (argv0);
327 const size_t exeext_len = sizeof (EXEEXT) - sizeof ("");
328 if (argv0_len > 4 + exeext_len)
329 if (memcmp (argv0 + argv0_len - exeext_len - 4, ".bin", 4) == 0)
331 if (sizeof (EXEEXT) > sizeof (""))
333 /* Compare using an inlined copy of c_strncasecmp(), because
334 the filenames may have undergone a case conversion since
335 they were packaged. In other words, EXEEXT may be ".exe"
336 on one system and ".EXE" on another. */
337 static const char exeext[] = EXEEXT;
338 const char *s1 = argv0 + argv0_len - exeext_len;
339 const char *s2 = exeext;
340 for (; *s1 != '\0'; s1++, s2++)
342 unsigned char c1 = *s1;
343 unsigned char c2 = *s2;
344 if ((c1 >= 'A' && c1 <= 'Z' ? c1 - 'A' + 'a' : c1)
345 != (c2 >= 'A' && c2 <= 'Z' ? c2 - 'A' + 'a' : c2))
349 /* Remove ".bin" before EXEEXT or its equivalent. */
351 char *shorter = (char *) xmalloc (argv0_len - 4 + 1);
356 memcpy (shorter, argv0, argv0_len - exeext_len - 4);
357 if (sizeof (EXEEXT) > sizeof (""))
358 memcpy (shorter + argv0_len - exeext_len - 4,
359 argv0 + argv0_len - exeext_len - 4,
361 shorter[argv0_len - 4] = '\0';
362 argv0_stripped = shorter;
369 set_program_name (argv0_stripped);
371 prepare_relocate (orig_installprefix, orig_installdir, argv0);
374 /* Return the full pathname of the current executable, based on the earlier
375 call to set_program_name_and_installdir. Return NULL if unknown. */
377 get_full_program_name (void)
379 return executable_fullname;