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