1 /* Provide relocatable programs.
2 Copyright (C) 2003-2024 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
33 /* Get declaration of _NSGetExecutablePath on Mac OS X 10.2 or newer. */
34 #if HAVE_MACH_O_DYLD_H
35 # include <mach-o/dyld.h>
38 #if defined _WIN32 && !defined __CYGWIN__
39 # define WINDOWS_NATIVE
43 # define WIN32_LEAN_AND_MEAN
52 #include "relocatable.h"
55 # include "areadlink.h"
56 # define xreadlink areadlink
58 # include "xreadlink.h"
62 # define xmalloc malloc
63 # define xstrdup strdup
69 # define O_EXEC O_RDONLY /* This is often close enough in older systems. */
72 #if defined IN_RELOCWRAPPER && (!defined O_CLOEXEC || GNULIB_defined_O_CLOEXEC)
77 /* Declare canonicalize_file_name.
78 The <stdlib.h> included above may be the system's one, not the gnulib
80 extern char * canonicalize_file_name (const char *name
);
82 #if defined WINDOWS_NATIVE
83 /* Don't assume that UNICODE is not defined. */
84 # undef GetModuleFileName
85 # define GetModuleFileName GetModuleFileNameA
89 ISSLASH(C) tests whether C is a directory separator character.
90 IS_FILE_NAME_WITH_DIR(P) tests whether P contains a directory specification.
92 #if (defined _WIN32 && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__
93 /* Native Windows, OS/2, DOS */
94 # define ISSLASH(C) ((C) == '/' || (C) == '\\')
95 # define HAS_DEVICE(P) \
96 ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
98 # define IS_FILE_NAME_WITH_DIR(P) \
99 (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
100 # define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
103 # define ISSLASH(C) ((C) == '/')
104 # define IS_FILE_NAME_WITH_DIR(P) (strchr (P, '/') != NULL)
105 # define FILE_SYSTEM_PREFIX_LEN(P) 0
108 /* Use the system functions, not the gnulib overrides in this file. */
111 #undef set_program_name
114 #if ENABLE_RELOCATABLE
118 /* Helper function, from gnulib module 'safe-read'. */
120 safe_read (int fd
, void *buf
, size_t count
)
124 ssize_t result
= read (fd
, buf
, count
);
126 if (0 <= result
|| errno
!= EINTR
)
131 /* Helper function, from gnulib module 'full-read'. */
133 full_read (int fd
, void *buf
, size_t count
)
136 char *ptr
= (char *) buf
;
140 size_t n
= safe_read (fd
, ptr
, count
);
141 if (n
== (size_t) -1)
158 #if defined __linux__ || defined __CYGWIN__
159 /* File descriptor of the executable.
160 (Only used to verify that we find the correct executable.) */
161 static int executable_fd
= -1;
164 /* Define this function only when it's needed. */
165 #if !(defined WINDOWS_NATIVE || defined __EMX__)
167 /* Tests whether a given filename may belong to the executable. */
169 maybe_executable (const char *filename
)
171 /* The native Windows API lacks the access() function. */
172 # if !defined WINDOWS_NATIVE
173 if (access (filename
, X_OK
) < 0)
177 # if defined __linux__ || defined __CYGWIN__
178 if (executable_fd
>= 0)
180 /* If we already have an executable_fd, check that filename points to
183 struct stat statfile
;
185 if (fstat (executable_fd
, &statexe
) >= 0)
186 return (stat (filename
, &statfile
) >= 0
188 && statfile
.st_dev
== statexe
.st_dev
189 && statfile
.st_ino
== statexe
.st_ino
);
193 /* Check that the filename does not point to a directory. */
195 struct stat statfile
;
197 return (stat (filename
, &statfile
) >= 0
198 && ! S_ISDIR (statfile
.st_mode
));
204 /* Determine the full pathname of the current executable, freshly allocated.
205 Return NULL if unknown.
206 Guaranteed to work on Linux and native Windows. Likely to work on the
207 other Unixes (maybe except BeOS), under most conditions. */
209 find_executable (const char *argv0
)
211 #if defined WINDOWS_NATIVE
212 /* Native Windows only.
213 On Cygwin, it is better to use the Cygwin provided /proc interface, than
214 to use native Windows API and cygwin_conv_to_posix_path, because it
215 supports longer file names
216 (see <https://cygwin.com/ml/cygwin/2011-01/msg00410.html>). */
217 char location
[MAX_PATH
];
218 int length
= GetModuleFileName (NULL
, location
, sizeof (location
));
221 if (!IS_FILE_NAME_WITH_DIR (location
))
222 /* Shouldn't happen. */
224 return xstrdup (location
);
225 #elif defined __EMX__
227 char location
[CCHMAXPATH
];
229 /* See http://cyberkinetica.homeunix.net/os2tk45/cp1/619_L2H_DosGetInfoBlocksSynt.html
230 for specification of DosGetInfoBlocks(). */
231 if (DosGetInfoBlocks (NULL
, &ppib
))
234 /* See http://cyberkinetica.homeunix.net/os2tk45/cp1/1247_L2H_DosQueryModuleNameSy.html
235 for specification of DosQueryModuleName(). */
236 if (DosQueryModuleName (ppib
->pib_hmte
, sizeof (location
), location
))
239 _fnslashify (location
);
241 return xstrdup (location
);
243 # if defined __linux__
244 /* The executable is accessible as /proc/<pid>/exe. In newer Linux
245 versions, also as /proc/self/exe. Linux >= 2.1 provides a symlink
246 to the true pathname; older Linux versions give only device and ino,
247 enclosed in brackets, which we cannot use here. */
251 link
= xreadlink ("/proc/self/exe");
252 if (link
!= NULL
&& link
[0] != '[')
254 if (executable_fd
< 0)
255 executable_fd
= open ("/proc/self/exe", O_EXEC
| O_CLOEXEC
, 0);
259 sprintf (buf
, "/proc/%d/exe", getpid ());
260 link
= xreadlink (buf
);
261 if (link
!= NULL
&& link
[0] != '[')
263 if (executable_fd
< 0)
264 executable_fd
= open (buf
, O_EXEC
| O_CLOEXEC
, 0);
268 # if defined __ANDROID__ || defined __FreeBSD_kernel__
269 /* On Android and GNU/kFreeBSD, the executable is accessible as
270 /proc/<pid>/exe and /proc/self/exe. */
274 link
= xreadlink ("/proc/self/exe");
279 # if defined __FreeBSD__ || defined __DragonFly__
280 /* In FreeBSD >= 5.0, the executable is accessible as /proc/<pid>/file and
281 /proc/curproc/file. */
285 link
= xreadlink ("/proc/curproc/file");
288 if (strcmp (link
, "unknown") != 0)
294 # if defined __NetBSD__
295 /* In NetBSD >= 4.0, the executable is accessible as /proc/<pid>/exe and
296 /proc/curproc/exe. */
300 link
= xreadlink ("/proc/curproc/exe");
306 /* On Solaris >= 11.4, /proc/<pid>/execname and /proc/self/execname contains
307 the name of the executable, either as an absolute file name or relative to
308 the current directory. */
311 int fd
= open ("/proc/self/execname", O_RDONLY
| O_CLOEXEC
, 0);
314 size_t len
= full_read (fd
, namebuf
, sizeof (namebuf
));
316 if (len
> 0 && len
< sizeof (namebuf
))
319 return canonicalize_file_name (namebuf
);
324 # if defined __CYGWIN__
325 /* The executable is accessible as /proc/<pid>/exe, at least in
330 link
= xreadlink ("/proc/self/exe");
333 if (executable_fd
< 0)
334 executable_fd
= open ("/proc/self/exe", O_EXEC
| O_CLOEXEC
, 0);
337 # if HAVE_MACH_O_DYLD_H && HAVE__NSGETEXECUTABLEPATH
338 /* On Mac OS X 10.2 or newer, the function
339 int _NSGetExecutablePath (char *buf, uint32_t *bufsize);
340 can be used to retrieve the executable's full path. */
342 unsigned int length
= sizeof (location
);
343 if (_NSGetExecutablePath (location
, &length
) == 0
344 && location
[0] == '/')
345 return canonicalize_file_name (location
);
347 /* Guess the executable's full path. We assume the executable has been
348 called via execlp() or execvp() with properly set up argv[0]. The
349 login(1) convention to add a '-' prefix to argv[0] is not supported. */
351 bool has_slash
= false;
354 for (p
= argv0
; *p
; p
++)
363 /* exec searches paths without slashes in the directory list given
365 const char *path
= getenv ("PATH");
372 for (p
= path
; *p
; p
= p_next
)
382 p_next
= (*q
== '\0' ? q
: q
+ 1);
384 /* We have a path item at p, of length p_len.
385 Now concatenate the path item and argv0. */
386 concat_name
= (char *) xmalloc (p_len
+ strlen (argv0
) + 2);
388 if (concat_name
== NULL
)
392 /* An empty PATH element designates the current directory. */
393 strcpy (concat_name
, argv0
);
396 memcpy (concat_name
, p
, p_len
);
397 concat_name
[p_len
] = '/';
398 strcpy (concat_name
+ p_len
+ 1, argv0
);
400 if (maybe_executable (concat_name
))
401 return canonicalize_file_name (concat_name
);
405 /* Not found in the PATH, assume the current directory. */
407 /* exec treats paths containing slashes as relative to the current
409 if (maybe_executable (argv0
))
410 return canonicalize_file_name (argv0
);
412 /* No way to find the executable. */
417 /* Full pathname of executable, or NULL. */
418 static char *executable_fullname
;
421 prepare_relocate (const char *orig_installprefix
, const char *orig_installdir
,
426 /* Determine the full pathname of the current executable. */
427 executable_fullname
= find_executable (argv0
);
429 /* Determine the current installation prefix from it. */
430 curr_prefix
= compute_curr_prefix (orig_installprefix
, orig_installdir
,
431 executable_fullname
);
432 if (curr_prefix
!= NULL
)
434 /* Now pass this prefix to all copies of the relocate.c source file. */
435 set_relocation_prefix (orig_installprefix
, curr_prefix
);
441 /* Set program_name, based on argv[0], and original installation prefix and
442 directory, for relocatability. */
444 set_program_name_and_installdir (const char *argv0
,
445 const char *orig_installprefix
,
446 const char *orig_installdir
)
448 const char *argv0_stripped
= argv0
;
450 /* Relocatable programs are renamed to .bin by install-reloc. Or, more
451 generally, their suffix is changed from $exeext to .bin$exeext.
452 Remove the ".bin" here. */
454 size_t argv0_len
= strlen (argv0
);
455 const size_t exeext_len
= sizeof (EXEEXT
) - sizeof ("");
456 if (argv0_len
> 4 + exeext_len
)
457 if (memcmp (argv0
+ argv0_len
- exeext_len
- 4, ".bin", 4) == 0)
459 if (sizeof (EXEEXT
) > sizeof (""))
461 /* Compare using an inlined copy of c_strncasecmp(), because
462 the filenames may have undergone a case conversion since
463 they were packaged. In other words, EXEEXT may be ".exe"
464 on one system and ".EXE" on another. */
465 static const char exeext
[] = EXEEXT
;
466 const char *s1
= argv0
+ argv0_len
- exeext_len
;
467 const char *s2
= exeext
;
468 for (; *s1
!= '\0'; s1
++, s2
++)
470 unsigned char c1
= *s1
;
471 unsigned char c2
= *s2
;
472 if ((c1
>= 'A' && c1
<= 'Z' ? c1
- 'A' + 'a' : c1
)
473 != (c2
>= 'A' && c2
<= 'Z' ? c2
- 'A' + 'a' : c2
))
477 /* Remove ".bin" before EXEEXT or its equivalent. */
479 char *shorter
= (char *) xmalloc (argv0_len
- 4 + 1);
484 memcpy (shorter
, argv0
, argv0_len
- exeext_len
- 4);
485 if (sizeof (EXEEXT
) > sizeof (""))
486 memcpy (shorter
+ argv0_len
- exeext_len
- 4,
487 argv0
+ argv0_len
- exeext_len
- 4,
489 shorter
[argv0_len
- 4] = '\0';
490 argv0_stripped
= shorter
;
497 set_program_name (argv0_stripped
);
499 prepare_relocate (orig_installprefix
, orig_installdir
, argv0
);
502 /* Return the full pathname of the current executable, based on the earlier
503 call to set_program_name_and_installdir. Return NULL if unknown. */
505 get_full_program_name (void)
507 return executable_fullname
;