1 /* Provide relocatable programs.
2    Copyright (C) 2003-2020 Free Software Foundation, Inc.
3    Written by Bruno Haible <bruno@clisp.org>, 2003.
4 
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.
9 
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.
14 
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/>.  */
17 
18 
19 #define _GL_USE_STDLIB_ALLOC 1
20 #include <config.h>
21 
22 /* Specification.  */
23 #include "progname.h"
24 
25 #include <errno.h>
26 #include <stdbool.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <sys/stat.h>
33 
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>
37 #endif
38 
39 #if defined _WIN32 && !defined __CYGWIN__
40 # define WINDOWS_NATIVE
41 #endif
42 
43 #ifdef WINDOWS_NATIVE
44 # define WIN32_LEAN_AND_MEAN
45 # include <windows.h>
46 #endif
47 
48 #ifdef __EMX__
49 # define INCL_DOS
50 # include <os2.h>
51 #endif
52 
53 #include "relocatable.h"
54 
55 #ifdef NO_XMALLOC
56 # include "areadlink.h"
57 # define xreadlink areadlink
58 #else
59 # include "xreadlink.h"
60 #endif
61 
62 #ifdef NO_XMALLOC
63 # define xmalloc malloc
64 # define xstrdup strdup
65 #else
66 # include "xalloc.h"
67 #endif
68 
69 #ifndef O_EXEC
70 # define O_EXEC O_RDONLY /* This is often close enough in older systems.  */
71 #endif
72 
73 #if defined IN_RELOCWRAPPER && (!defined O_CLOEXEC || GNULIB_defined_O_CLOEXEC)
74 # undef O_CLOEXEC
75 # define O_CLOEXEC 0
76 #endif
77 
78 /* Declare canonicalize_file_name.
79    The <stdlib.h> included above may be the system's one, not the gnulib
80    one.  */
81 extern char * canonicalize_file_name (const char *name);
82 
83 #if defined WINDOWS_NATIVE
84 /* Don't assume that UNICODE is not defined.  */
85 # undef GetModuleFileName
86 # define GetModuleFileName GetModuleFileNameA
87 #endif
88 
89 /* Pathname support.
90    ISSLASH(C)                tests whether C is a directory separator character.
91    IS_FILE_NAME_WITH_DIR(P)  tests whether P contains a directory specification.
92  */
93 #if (defined _WIN32 && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__
94   /* Native Windows, OS/2, DOS */
95 # define ISSLASH(C) ((C) == '/' || (C) == '\\')
96 # define HAS_DEVICE(P) \
97     ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
98      && (P)[1] == ':')
99 # define IS_FILE_NAME_WITH_DIR(P) \
100     (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
101 # define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
102 #else
103   /* Unix */
104 # define ISSLASH(C) ((C) == '/')
105 # define IS_FILE_NAME_WITH_DIR(P) (strchr (P, '/') != NULL)
106 # define FILE_SYSTEM_PREFIX_LEN(P) 0
107 #endif
108 
109 /* Use the system functions, not the gnulib overrides in this file.  */
110 #undef sprintf
111 
112 #undef set_program_name
113 
114 
115 #if ENABLE_RELOCATABLE
116 
117 #ifdef __sun
118 
119 /* Helper function, from gnulib module 'safe-read'.  */
120 static size_t
safe_read(int fd,void * buf,size_t count)121 safe_read (int fd, void *buf, size_t count)
122 {
123   for (;;)
124     {
125       ssize_t result = read (fd, buf, count);
126 
127       if (0 <= result || errno != EINTR)
128         return result;
129     }
130 }
131 
132 /* Helper function, from gnulib module 'full-read'.  */
133 static size_t
full_read(int fd,void * buf,size_t count)134 full_read (int fd, void *buf, size_t count)
135 {
136   size_t total = 0;
137   const char *ptr = (const char *) buf;
138 
139   while (count > 0)
140     {
141       size_t n = safe_read (fd, ptr, count);
142       if (n == (size_t) -1)
143         break;
144       if (n == 0)
145         {
146           errno = 0;
147           break;
148         }
149       total += n;
150       ptr += n;
151       count -= n;
152     }
153 
154   return total;
155 }
156 
157 #endif
158 
159 #if defined __linux__ || defined __CYGWIN__
160 /* File descriptor of the executable.
161    (Only used to verify that we find the correct executable.)  */
162 static int executable_fd = -1;
163 #endif
164 
165 /* Define this function only when it's needed.  */
166 #if !(defined WINDOWS_NATIVE || defined __EMX__)
167 
168 /* Tests whether a given filename may belong to the executable.  */
169 static bool
maybe_executable(const char * filename)170 maybe_executable (const char *filename)
171 {
172   /* The native Windows API lacks the access() function.  */
173 # if !defined WINDOWS_NATIVE
174   if (access (filename, X_OK) < 0)
175     return false;
176 # endif
177 
178 # if defined __linux__ || defined __CYGWIN__
179   if (executable_fd >= 0)
180     {
181       /* If we already have an executable_fd, check that filename points to
182          the same inode.  */
183       struct stat statexe;
184       struct stat statfile;
185 
186       if (fstat (executable_fd, &statexe) >= 0)
187         return (stat (filename, &statfile) >= 0
188                 && statfile.st_dev
189                 && statfile.st_dev == statexe.st_dev
190                 && statfile.st_ino == statexe.st_ino);
191     }
192 # endif
193 
194   /* Check that the filename does not point to a directory.  */
195   {
196     struct stat statfile;
197 
198     return (stat (filename, &statfile) >= 0
199             && ! S_ISDIR (statfile.st_mode));
200   }
201 }
202 
203 #endif
204 
205 /* Determine the full pathname of the current executable, freshly allocated.
206    Return NULL if unknown.
207    Guaranteed to work on Linux and native Windows.  Likely to work on the
208    other Unixes (maybe except BeOS), under most conditions.  */
209 static char *
find_executable(const char * argv0)210 find_executable (const char *argv0)
211 {
212 #if defined WINDOWS_NATIVE
213   /* Native Windows only.
214      On Cygwin, it is better to use the Cygwin provided /proc interface, than
215      to use native Windows API and cygwin_conv_to_posix_path, because it
216      supports longer file names
217      (see <https://cygwin.com/ml/cygwin/2011-01/msg00410.html>).  */
218   char location[MAX_PATH];
219   int length = GetModuleFileName (NULL, location, sizeof (location));
220   if (length < 0)
221     return NULL;
222   if (!IS_FILE_NAME_WITH_DIR (location))
223     /* Shouldn't happen.  */
224     return NULL;
225   return xstrdup (location);
226 #elif defined __EMX__
227   PPIB ppib;
228   char location[CCHMAXPATH];
229 
230   /* See http://cyberkinetica.homeunix.net/os2tk45/cp1/619_L2H_DosGetInfoBlocksSynt.html
231      for specification of DosGetInfoBlocks().  */
232   if (DosGetInfoBlocks (NULL, &ppib))
233     return NULL;
234 
235   /* See http://cyberkinetica.homeunix.net/os2tk45/cp1/1247_L2H_DosQueryModuleNameSy.html
236      for specification of DosQueryModuleName().  */
237   if (DosQueryModuleName (ppib->pib_hmte, sizeof (location), location))
238     return NULL;
239 
240   _fnslashify (location);
241 
242   return xstrdup (location);
243 #else /* Unix */
244 # if defined __linux__
245   /* The executable is accessible as /proc/<pid>/exe.  In newer Linux
246      versions, also as /proc/self/exe.  Linux >= 2.1 provides a symlink
247      to the true pathname; older Linux versions give only device and ino,
248      enclosed in brackets, which we cannot use here.  */
249   {
250     char *link;
251 
252     link = xreadlink ("/proc/self/exe");
253     if (link != NULL && link[0] != '[')
254       return link;
255     if (executable_fd < 0)
256       executable_fd = open ("/proc/self/exe", O_EXEC | O_CLOEXEC, 0);
257 
258     {
259       char buf[6+10+5];
260       sprintf (buf, "/proc/%d/exe", getpid ());
261       link = xreadlink (buf);
262       if (link != NULL && link[0] != '[')
263         return link;
264       if (executable_fd < 0)
265         executable_fd = open (buf, O_EXEC | O_CLOEXEC, 0);
266     }
267   }
268 # endif
269 # if defined __ANDROID__ || defined __FreeBSD_kernel__
270   /* On Android and GNU/kFreeBSD, the executable is accessible as
271      /proc/<pid>/exe and /proc/self/exe.  */
272   {
273     char *link;
274 
275     link = xreadlink ("/proc/self/exe");
276     if (link != NULL)
277       return link;
278   }
279 # endif
280 # if defined __FreeBSD__ || defined __DragonFly__
281   /* In FreeBSD >= 5.0, the executable is accessible as /proc/<pid>/file and
282      /proc/curproc/file.  */
283   {
284     char *link;
285 
286     link = xreadlink ("/proc/curproc/file");
287     if (link != NULL)
288       {
289         if (strcmp (link, "unknown") != 0)
290           return link;
291         free (link);
292       }
293   }
294 # endif
295 # if defined __NetBSD__
296   /* In NetBSD >= 4.0, the executable is accessible as /proc/<pid>/exe and
297      /proc/curproc/exe.  */
298   {
299     char *link;
300 
301     link = xreadlink ("/proc/curproc/exe");
302     if (link != NULL)
303       return link;
304   }
305 # endif
306 # if defined __sun
307   /* On Solaris >= 11.4, /proc/<pid>/execname and /proc/self/execname contains
308      the name of the executable, either as an absolute file name or relative to
309      the current directory.  */
310   {
311     char namebuf[4096];
312     int fd = open ("/proc/self/execname", O_RDONLY | O_CLOEXEC, 0);
313     if (fd >= 0)
314       {
315         size_t len = full_read (fd, namebuf, sizeof (namebuf));
316         close (fd);
317         if (len > 0 && len < sizeof (namebuf))
318           {
319             namebuf[len] = '\0';
320             return canonicalize_file_name (namebuf);
321           }
322       }
323   }
324 # endif
325 # if defined __CYGWIN__
326   /* The executable is accessible as /proc/<pid>/exe, at least in
327      Cygwin >= 1.5.  */
328   {
329     char *link;
330 
331     link = xreadlink ("/proc/self/exe");
332     if (link != NULL)
333       return link;
334     if (executable_fd < 0)
335       executable_fd = open ("/proc/self/exe", O_EXEC | O_CLOEXEC, 0);
336   }
337 # endif
338 # if HAVE_MACH_O_DYLD_H && HAVE__NSGETEXECUTABLEPATH
339   /* On Mac OS X 10.2 or newer, the function
340        int _NSGetExecutablePath (char *buf, uint32_t *bufsize);
341      can be used to retrieve the executable's full path.  */
342   char location[4096];
343   unsigned int length = sizeof (location);
344   if (_NSGetExecutablePath (location, &length) == 0
345       && location[0] == '/')
346     return canonicalize_file_name (location);
347 # endif
348   /* Guess the executable's full path.  We assume the executable has been
349      called via execlp() or execvp() with properly set up argv[0].  The
350      login(1) convention to add a '-' prefix to argv[0] is not supported.  */
351   {
352     bool has_slash = false;
353     {
354       const char *p;
355       for (p = argv0; *p; p++)
356         if (*p == '/')
357           {
358             has_slash = true;
359             break;
360           }
361     }
362     if (!has_slash)
363       {
364         /* exec searches paths without slashes in the directory list given
365            by $PATH.  */
366         const char *path = getenv ("PATH");
367 
368         if (path != NULL)
369           {
370             const char *p;
371             const char *p_next;
372 
373             for (p = path; *p; p = p_next)
374               {
375                 const char *q;
376                 size_t p_len;
377                 char *concat_name;
378 
379                 for (q = p; *q; q++)
380                   if (*q == ':')
381                     break;
382                 p_len = q - p;
383                 p_next = (*q == '\0' ? q : q + 1);
384 
385                 /* We have a path item at p, of length p_len.
386                    Now concatenate the path item and argv0.  */
387                 concat_name = (char *) xmalloc (p_len + strlen (argv0) + 2);
388 # ifdef NO_XMALLOC
389                 if (concat_name == NULL)
390                   return NULL;
391 # endif
392                 if (p_len == 0)
393                   /* An empty PATH element designates the current directory.  */
394                   strcpy (concat_name, argv0);
395                 else
396                   {
397                     memcpy (concat_name, p, p_len);
398                     concat_name[p_len] = '/';
399                     strcpy (concat_name + p_len + 1, argv0);
400                   }
401                 if (maybe_executable (concat_name))
402                   return canonicalize_file_name (concat_name);
403                 free (concat_name);
404               }
405           }
406         /* Not found in the PATH, assume the current directory.  */
407       }
408     /* exec treats paths containing slashes as relative to the current
409        directory.  */
410     if (maybe_executable (argv0))
411       return canonicalize_file_name (argv0);
412   }
413   /* No way to find the executable.  */
414   return NULL;
415 #endif
416 }
417 
418 /* Full pathname of executable, or NULL.  */
419 static char *executable_fullname;
420 
421 static void
prepare_relocate(const char * orig_installprefix,const char * orig_installdir,const char * argv0)422 prepare_relocate (const char *orig_installprefix, const char *orig_installdir,
423                   const char *argv0)
424 {
425   char *curr_prefix;
426 
427   /* Determine the full pathname of the current executable.  */
428   executable_fullname = find_executable (argv0);
429 
430   /* Determine the current installation prefix from it.  */
431   curr_prefix = compute_curr_prefix (orig_installprefix, orig_installdir,
432                                      executable_fullname);
433   if (curr_prefix != NULL)
434     {
435       /* Now pass this prefix to all copies of the relocate.c source file.  */
436       set_relocation_prefix (orig_installprefix, curr_prefix);
437 
438       free (curr_prefix);
439     }
440 }
441 
442 /* Set program_name, based on argv[0], and original installation prefix and
443    directory, for relocatability.  */
444 void
set_program_name_and_installdir(const char * argv0,const char * orig_installprefix,const char * orig_installdir)445 set_program_name_and_installdir (const char *argv0,
446                                  const char *orig_installprefix,
447                                  const char *orig_installdir)
448 {
449   const char *argv0_stripped = argv0;
450 
451   /* Relocatable programs are renamed to .bin by install-reloc.  Or, more
452      generally, their suffix is changed from $exeext to .bin$exeext.
453      Remove the ".bin" here.  */
454   {
455     size_t argv0_len = strlen (argv0);
456     const size_t exeext_len = sizeof (EXEEXT) - sizeof ("");
457     if (argv0_len > 4 + exeext_len)
458       if (memcmp (argv0 + argv0_len - exeext_len - 4, ".bin", 4) == 0)
459         {
460           if (sizeof (EXEEXT) > sizeof (""))
461             {
462               /* Compare using an inlined copy of c_strncasecmp(), because
463                  the filenames may have undergone a case conversion since
464                  they were packaged.  In other words, EXEEXT may be ".exe"
465                  on one system and ".EXE" on another.  */
466               static const char exeext[] = EXEEXT;
467               const char *s1 = argv0 + argv0_len - exeext_len;
468               const char *s2 = exeext;
469               for (; *s1 != '\0'; s1++, s2++)
470                 {
471                   unsigned char c1 = *s1;
472                   unsigned char c2 = *s2;
473                   if ((c1 >= 'A' && c1 <= 'Z' ? c1 - 'A' + 'a' : c1)
474                       != (c2 >= 'A' && c2 <= 'Z' ? c2 - 'A' + 'a' : c2))
475                     goto done_stripping;
476                 }
477             }
478           /* Remove ".bin" before EXEEXT or its equivalent.  */
479           {
480             char *shorter = (char *) xmalloc (argv0_len - 4 + 1);
481 #ifdef NO_XMALLOC
482             if (shorter != NULL)
483 #endif
484               {
485                 memcpy (shorter, argv0, argv0_len - exeext_len - 4);
486                 if (sizeof (EXEEXT) > sizeof (""))
487                   memcpy (shorter + argv0_len - exeext_len - 4,
488                           argv0 + argv0_len - exeext_len - 4,
489                           exeext_len);
490                 shorter[argv0_len - 4] = '\0';
491                 argv0_stripped = shorter;
492               }
493           }
494          done_stripping: ;
495       }
496   }
497 
498   set_program_name (argv0_stripped);
499 
500   prepare_relocate (orig_installprefix, orig_installdir, argv0);
501 }
502 
503 /* Return the full pathname of the current executable, based on the earlier
504    call to set_program_name_and_installdir.  Return NULL if unknown.  */
505 char *
get_full_program_name(void)506 get_full_program_name (void)
507 {
508   return executable_fullname;
509 }
510 
511 #endif
512