1 /* Provide relocatable programs.
2 Copyright (C) 2003-2019 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 <https://www.gnu.org/licenses/>. */
19 #define _GL_USE_STDLIB_ALLOC 1
34 /* Get declaration of _NSGetExecutablePath on Mac OS X 10.2 or newer. */
35 #if HAVE_MACH_O_DYLD_H
36 # include <mach-o/dyld.h>
39 #if defined _WIN32 && !defined __CYGWIN__
40 # define WINDOWS_NATIVE
44 # define WIN32_LEAN_AND_MEAN
53 #include "relocatable.h"
56 # include "areadlink.h"
57 # define xreadlink areadlink
59 # include "xreadlink.h"
63 # define xmalloc malloc
64 # define xstrdup strdup
70 # define O_EXEC O_RDONLY /* This is often close enough in older systems. */
73 /* Declare canonicalize_file_name.
74 The <stdlib.h> included above may be the system's one, not the gnulib
76 extern char * canonicalize_file_name (const char *name
);
79 ISSLASH(C) tests whether C is a directory separator character.
80 IS_PATH_WITH_DIR(P) tests whether P contains a directory specification.
82 #if (defined _WIN32 && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__
83 /* Native Windows, OS/2, DOS */
84 # define ISSLASH(C) ((C) == '/' || (C) == '\\')
85 # define HAS_DEVICE(P) \
86 ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
88 # define IS_PATH_WITH_DIR(P) \
89 (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
90 # define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
93 # define ISSLASH(C) ((C) == '/')
94 # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
95 # define FILE_SYSTEM_PREFIX_LEN(P) 0
98 /* Use the system functions, not the gnulib overrides in this file. */
101 #undef set_program_name
104 #if ENABLE_RELOCATABLE
108 /* Helper function, from gnulib module 'safe-read'. */
110 safe_read (int fd
, void *buf
, size_t count
)
114 ssize_t result
= read (fd
, buf
, count
);
116 if (0 <= result
|| errno
!= EINTR
)
121 /* Helper function, from gnulib module 'full-read'. */
123 full_read (int fd
, void *buf
, size_t count
)
126 const char *ptr
= (const char *) buf
;
130 size_t n
= safe_read (fd
, ptr
, count
);
131 if (n
== (size_t) -1)
148 #if defined __linux__ || defined __CYGWIN__
149 /* File descriptor of the executable.
150 (Only used to verify that we find the correct executable.) */
151 static int executable_fd
= -1;
154 /* Define this function only when it's needed. */
155 #if !(defined WINDOWS_NATIVE || defined __EMX__)
157 /* Tests whether a given pathname may belong to the executable. */
159 maybe_executable (const char *filename
)
161 /* The native Windows API lacks the access() function. */
162 # if !defined WINDOWS_NATIVE
163 if (access (filename
, X_OK
) < 0)
167 # if defined __linux__ || defined __CYGWIN__
168 if (executable_fd
>= 0)
170 /* If we already have an executable_fd, check that filename points to
173 struct stat statfile
;
175 if (fstat (executable_fd
, &statexe
) >= 0)
177 if (stat (filename
, &statfile
) < 0)
179 if (!(statfile
.st_dev
180 && statfile
.st_dev
== statexe
.st_dev
181 && statfile
.st_ino
== statexe
.st_ino
))
192 /* Determine the full pathname of the current executable, freshly allocated.
193 Return NULL if unknown.
194 Guaranteed to work on Linux and native Windows. Likely to work on the
195 other Unixes (maybe except BeOS), under most conditions. */
197 find_executable (const char *argv0
)
199 #if defined WINDOWS_NATIVE
200 /* Native Windows only.
201 On Cygwin, it is better to use the Cygwin provided /proc interface, than
202 to use native Windows API and cygwin_conv_to_posix_path, because it
203 supports longer file names
204 (see <https://cygwin.com/ml/cygwin/2011-01/msg00410.html>). */
205 char location
[MAX_PATH
];
206 int length
= GetModuleFileName (NULL
, location
, sizeof (location
));
209 if (!IS_PATH_WITH_DIR (location
))
210 /* Shouldn't happen. */
212 return xstrdup (location
);
213 #elif defined __EMX__
215 char location
[CCHMAXPATH
];
217 /* See http://cyberkinetica.homeunix.net/os2tk45/cp1/619_L2H_DosGetInfoBlocksSynt.html
218 for specification of DosGetInfoBlocks(). */
219 if (DosGetInfoBlocks (NULL
, &ppib
))
222 /* See http://cyberkinetica.homeunix.net/os2tk45/cp1/1247_L2H_DosQueryModuleNameSy.html
223 for specification of DosQueryModuleName(). */
224 if (DosQueryModuleName (ppib
->pib_hmte
, sizeof (location
), location
))
227 _fnslashify (location
);
229 return xstrdup (location
);
231 # if defined __linux__
232 /* The executable is accessible as /proc/<pid>/exe. In newer Linux
233 versions, also as /proc/self/exe. Linux >= 2.1 provides a symlink
234 to the true pathname; older Linux versions give only device and ino,
235 enclosed in brackets, which we cannot use here. */
239 link
= xreadlink ("/proc/self/exe");
240 if (link
!= NULL
&& link
[0] != '[')
242 if (executable_fd
< 0)
243 executable_fd
= open ("/proc/self/exe", O_EXEC
, 0);
247 sprintf (buf
, "/proc/%d/exe", getpid ());
248 link
= xreadlink (buf
);
249 if (link
!= NULL
&& link
[0] != '[')
251 if (executable_fd
< 0)
252 executable_fd
= open (buf
, O_EXEC
, 0);
256 # if defined __ANDROID__ || defined __FreeBSD_kernel__
257 /* On Android and GNU/kFreeBSD, the executable is accessible as
258 /proc/<pid>/exe and /proc/self/exe. */
262 link
= xreadlink ("/proc/self/exe");
267 # if defined __FreeBSD__ || defined __DragonFly__
268 /* In FreeBSD >= 5.0, the executable is accessible as /proc/<pid>/file and
269 /proc/curproc/file. */
273 link
= xreadlink ("/proc/curproc/file");
276 if (strcmp (link
, "unknown") != 0)
282 # if defined __NetBSD__
283 /* In NetBSD >= 4.0, the executable is accessible as /proc/<pid>/exe and
284 /proc/curproc/exe. */
288 link
= xreadlink ("/proc/curproc/exe");
294 /* On Solaris >= 11.4, /proc/<pid>/execname and /proc/self/execname contains
295 the name of the executable, either as an absolute file name or relative to
296 the current directory. */
299 int fd
= open ("/proc/self/execname", O_RDONLY
, 0);
302 size_t len
= full_read (fd
, namebuf
, sizeof (namebuf
));
304 if (len
> 0 && len
< sizeof (namebuf
))
307 return canonicalize_file_name (namebuf
);
312 # if defined __CYGWIN__
313 /* The executable is accessible as /proc/<pid>/exe, at least in
318 link
= xreadlink ("/proc/self/exe");
321 if (executable_fd
< 0)
322 executable_fd
= open ("/proc/self/exe", O_EXEC
, 0);
325 # if HAVE_MACH_O_DYLD_H && HAVE__NSGETEXECUTABLEPATH
326 /* On Mac OS X 10.2 or newer, the function
327 int _NSGetExecutablePath (char *buf, uint32_t *bufsize);
328 can be used to retrieve the executable's full path. */
330 unsigned int length
= sizeof (location
);
331 if (_NSGetExecutablePath (location
, &length
) == 0
332 && location
[0] == '/')
333 return canonicalize_file_name (location
);
335 /* Guess the executable's full path. We assume the executable has been
336 called via execlp() or execvp() with properly set up argv[0]. The
337 login(1) convention to add a '-' prefix to argv[0] is not supported. */
339 bool has_slash
= false;
342 for (p
= argv0
; *p
; p
++)
351 /* exec searches paths without slashes in the directory list given
353 const char *path
= getenv ("PATH");
360 for (p
= path
; *p
; p
= p_next
)
370 p_next
= (*q
== '\0' ? q
: q
+ 1);
372 /* We have a path item at p, of length p_len.
373 Now concatenate the path item and argv0. */
374 concat_name
= (char *) xmalloc (p_len
+ strlen (argv0
) + 2);
376 if (concat_name
== NULL
)
380 /* An empty PATH element designates the current directory. */
381 strcpy (concat_name
, argv0
);
384 memcpy (concat_name
, p
, p_len
);
385 concat_name
[p_len
] = '/';
386 strcpy (concat_name
+ p_len
+ 1, argv0
);
388 if (maybe_executable (concat_name
))
389 return canonicalize_file_name (concat_name
);
393 /* Not found in the PATH, assume the current directory. */
395 /* exec treats paths containing slashes as relative to the current
397 if (maybe_executable (argv0
))
398 return canonicalize_file_name (argv0
);
400 /* No way to find the executable. */
405 /* Full pathname of executable, or NULL. */
406 static char *executable_fullname
;
409 prepare_relocate (const char *orig_installprefix
, const char *orig_installdir
,
414 /* Determine the full pathname of the current executable. */
415 executable_fullname
= find_executable (argv0
);
417 /* Determine the current installation prefix from it. */
418 curr_prefix
= compute_curr_prefix (orig_installprefix
, orig_installdir
,
419 executable_fullname
);
420 if (curr_prefix
!= NULL
)
422 /* Now pass this prefix to all copies of the relocate.c source file. */
423 set_relocation_prefix (orig_installprefix
, curr_prefix
);
429 /* Set program_name, based on argv[0], and original installation prefix and
430 directory, for relocatability. */
432 set_program_name_and_installdir (const char *argv0
,
433 const char *orig_installprefix
,
434 const char *orig_installdir
)
436 const char *argv0_stripped
= argv0
;
438 /* Relocatable programs are renamed to .bin by install-reloc. Or, more
439 generally, their suffix is changed from $exeext to .bin$exeext.
440 Remove the ".bin" here. */
442 size_t argv0_len
= strlen (argv0
);
443 const size_t exeext_len
= sizeof (EXEEXT
) - sizeof ("");
444 if (argv0_len
> 4 + exeext_len
)
445 if (memcmp (argv0
+ argv0_len
- exeext_len
- 4, ".bin", 4) == 0)
447 if (sizeof (EXEEXT
) > sizeof (""))
449 /* Compare using an inlined copy of c_strncasecmp(), because
450 the filenames may have undergone a case conversion since
451 they were packaged. In other words, EXEEXT may be ".exe"
452 on one system and ".EXE" on another. */
453 static const char exeext
[] = EXEEXT
;
454 const char *s1
= argv0
+ argv0_len
- exeext_len
;
455 const char *s2
= exeext
;
456 for (; *s1
!= '\0'; s1
++, s2
++)
458 unsigned char c1
= *s1
;
459 unsigned char c2
= *s2
;
460 if ((c1
>= 'A' && c1
<= 'Z' ? c1
- 'A' + 'a' : c1
)
461 != (c2
>= 'A' && c2
<= 'Z' ? c2
- 'A' + 'a' : c2
))
465 /* Remove ".bin" before EXEEXT or its equivalent. */
467 char *shorter
= (char *) xmalloc (argv0_len
- 4 + 1);
472 memcpy (shorter
, argv0
, argv0_len
- exeext_len
- 4);
473 if (sizeof (EXEEXT
) > sizeof (""))
474 memcpy (shorter
+ argv0_len
- exeext_len
- 4,
475 argv0
+ argv0_len
- exeext_len
- 4,
477 shorter
[argv0_len
- 4] = '\0';
478 argv0_stripped
= shorter
;
485 set_program_name (argv0_stripped
);
487 prepare_relocate (orig_installprefix
, orig_installdir
, argv0
);
490 /* Return the full pathname of the current executable, based on the earlier
491 call to set_program_name_and_installdir. Return NULL if unknown. */
493 get_full_program_name (void)
495 return executable_fullname
;