Bump to 1.14.1
[platform/upstream/augeas.git] / lib / progreloc.c
1 /* Provide relocatable programs.
2    Copyright (C) 2003-2016 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 #ifdef __EMX__
48 # define INCL_DOS
49 # include <os2.h>
50 #endif
51
52 #include "relocatable.h"
53
54 #ifdef NO_XMALLOC
55 # include "areadlink.h"
56 # define xreadlink areadlink
57 #else
58 # include "xreadlink.h"
59 #endif
60
61 #ifdef NO_XMALLOC
62 # define xmalloc malloc
63 # define xstrdup strdup
64 #else
65 # include "xalloc.h"
66 #endif
67
68 #ifndef O_EXEC
69 # define O_EXEC O_RDONLY /* This is often close enough in older systems.  */
70 #endif
71
72 /* Declare canonicalize_file_name.
73    The <stdlib.h> included above may be the system's one, not the gnulib
74    one.  */
75 extern char * canonicalize_file_name (const char *name);
76
77 /* Pathname support.
78    ISSLASH(C)           tests whether C is a directory separator character.
79    IS_PATH_WITH_DIR(P)  tests whether P contains a directory specification.
80  */
81 #if ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__
82   /* Native Windows, OS/2, DOS */
83 # define ISSLASH(C) ((C) == '/' || (C) == '\\')
84 # define HAS_DEVICE(P) \
85     ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
86      && (P)[1] == ':')
87 # define IS_PATH_WITH_DIR(P) \
88     (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
89 # define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
90 #else
91   /* Unix */
92 # define ISSLASH(C) ((C) == '/')
93 # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
94 # define FILE_SYSTEM_PREFIX_LEN(P) 0
95 #endif
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 #elif defined __EMX__
166   PPIB ppib;
167   char location[CCHMAXPATH];
168
169   /* See http://cyberkinetica.homeunix.net/os2tk45/cp1/619_L2H_DosGetInfoBlocksSynt.html
170      for specification of DosGetInfoBlocks().  */
171   if (DosGetInfoBlocks (NULL, &ppib))
172     return NULL;
173
174   /* See http://cyberkinetica.homeunix.net/os2tk45/cp1/1247_L2H_DosQueryModuleNameSy.html
175      for specification of DosQueryModuleName().  */
176   if (DosQueryModuleName (ppib->pib_hmte, sizeof (location), location))
177     return NULL;
178
179   _fnslashify (location);
180
181   return xstrdup (location);
182 #else /* Unix */
183 # ifdef __linux__
184   /* The executable is accessible as /proc/<pid>/exe.  In newer Linux
185      versions, also as /proc/self/exe.  Linux >= 2.1 provides a symlink
186      to the true pathname; older Linux versions give only device and ino,
187      enclosed in brackets, which we cannot use here.  */
188   {
189     char *link;
190
191     link = xreadlink ("/proc/self/exe");
192     if (link != NULL && link[0] != '[')
193       return link;
194     if (executable_fd < 0)
195       executable_fd = open ("/proc/self/exe", O_EXEC, 0);
196
197     {
198       char buf[6+10+5];
199       sprintf (buf, "/proc/%d/exe", getpid ());
200       link = xreadlink (buf);
201       if (link != NULL && link[0] != '[')
202         return link;
203       if (executable_fd < 0)
204         executable_fd = open (buf, O_EXEC, 0);
205     }
206   }
207 # endif
208 # ifdef __CYGWIN__
209   /* The executable is accessible as /proc/<pid>/exe, at least in
210      Cygwin >= 1.5.  */
211   {
212     char *link;
213
214     link = xreadlink ("/proc/self/exe");
215     if (link != NULL)
216       return link;
217     if (executable_fd < 0)
218       executable_fd = open ("/proc/self/exe", O_EXEC, 0);
219   }
220 # endif
221 # if HAVE_MACH_O_DYLD_H && HAVE__NSGETEXECUTABLEPATH
222   /* On Mac OS X 10.2 or newer, the function
223        int _NSGetExecutablePath (char *buf, uint32_t *bufsize);
224      can be used to retrieve the executable's full path.  */
225   char location[4096];
226   unsigned int length = sizeof (location);
227   if (_NSGetExecutablePath (location, &length) == 0
228       && location[0] == '/')
229     return canonicalize_file_name (location);
230 # endif
231   /* Guess the executable's full path.  We assume the executable has been
232      called via execlp() or execvp() with properly set up argv[0].  The
233      login(1) convention to add a '-' prefix to argv[0] is not supported.  */
234   {
235     bool has_slash = false;
236     {
237       const char *p;
238       for (p = argv0; *p; p++)
239         if (*p == '/')
240           {
241             has_slash = true;
242             break;
243           }
244     }
245     if (!has_slash)
246       {
247         /* exec searches paths without slashes in the directory list given
248            by $PATH.  */
249         const char *path = getenv ("PATH");
250
251         if (path != NULL)
252           {
253             const char *p;
254             const char *p_next;
255
256             for (p = path; *p; p = p_next)
257               {
258                 const char *q;
259                 size_t p_len;
260                 char *concat_name;
261
262                 for (q = p; *q; q++)
263                   if (*q == ':')
264                     break;
265                 p_len = q - p;
266                 p_next = (*q == '\0' ? q : q + 1);
267
268                 /* We have a path item at p, of length p_len.
269                    Now concatenate the path item and argv0.  */
270                 concat_name = (char *) xmalloc (p_len + strlen (argv0) + 2);
271 # ifdef NO_XMALLOC
272                 if (concat_name == NULL)
273                   return NULL;
274 # endif
275                 if (p_len == 0)
276                   /* An empty PATH element designates the current directory.  */
277                   strcpy (concat_name, argv0);
278                 else
279                   {
280                     memcpy (concat_name, p, p_len);
281                     concat_name[p_len] = '/';
282                     strcpy (concat_name + p_len + 1, argv0);
283                   }
284                 if (maybe_executable (concat_name))
285                   return canonicalize_file_name (concat_name);
286                 free (concat_name);
287               }
288           }
289         /* Not found in the PATH, assume the current directory.  */
290       }
291     /* exec treats paths containing slashes as relative to the current
292        directory.  */
293     if (maybe_executable (argv0))
294       return canonicalize_file_name (argv0);
295   }
296   /* No way to find the executable.  */
297   return NULL;
298 #endif
299 }
300
301 /* Full pathname of executable, or NULL.  */
302 static char *executable_fullname;
303
304 static void
305 prepare_relocate (const char *orig_installprefix, const char *orig_installdir,
306                   const char *argv0)
307 {
308   char *curr_prefix;
309
310   /* Determine the full pathname of the current executable.  */
311   executable_fullname = find_executable (argv0);
312
313   /* Determine the current installation prefix from it.  */
314   curr_prefix = compute_curr_prefix (orig_installprefix, orig_installdir,
315                                      executable_fullname);
316   if (curr_prefix != NULL)
317     {
318       /* Now pass this prefix to all copies of the relocate.c source file.  */
319       set_relocation_prefix (orig_installprefix, curr_prefix);
320
321       free (curr_prefix);
322     }
323 }
324
325 /* Set program_name, based on argv[0], and original installation prefix and
326    directory, for relocatability.  */
327 void
328 set_program_name_and_installdir (const char *argv0,
329                                  const char *orig_installprefix,
330                                  const char *orig_installdir)
331 {
332   const char *argv0_stripped = argv0;
333
334   /* Relocatable programs are renamed to .bin by install-reloc.  Or, more
335      generally, their suffix is changed from $exeext to .bin$exeext.
336      Remove the ".bin" here.  */
337   {
338     size_t argv0_len = strlen (argv0);
339     const size_t exeext_len = sizeof (EXEEXT) - sizeof ("");
340     if (argv0_len > 4 + exeext_len)
341       if (memcmp (argv0 + argv0_len - exeext_len - 4, ".bin", 4) == 0)
342         {
343           if (sizeof (EXEEXT) > sizeof (""))
344             {
345               /* Compare using an inlined copy of c_strncasecmp(), because
346                  the filenames may have undergone a case conversion since
347                  they were packaged.  In other words, EXEEXT may be ".exe"
348                  on one system and ".EXE" on another.  */
349               static const char exeext[] = EXEEXT;
350               const char *s1 = argv0 + argv0_len - exeext_len;
351               const char *s2 = exeext;
352               for (; *s1 != '\0'; s1++, s2++)
353                 {
354                   unsigned char c1 = *s1;
355                   unsigned char c2 = *s2;
356                   if ((c1 >= 'A' && c1 <= 'Z' ? c1 - 'A' + 'a' : c1)
357                       != (c2 >= 'A' && c2 <= 'Z' ? c2 - 'A' + 'a' : c2))
358                     goto done_stripping;
359                 }
360             }
361           /* Remove ".bin" before EXEEXT or its equivalent.  */
362           {
363             char *shorter = (char *) xmalloc (argv0_len - 4 + 1);
364 #ifdef NO_XMALLOC
365             if (shorter != NULL)
366 #endif
367               {
368                 memcpy (shorter, argv0, argv0_len - exeext_len - 4);
369                 if (sizeof (EXEEXT) > sizeof (""))
370                   memcpy (shorter + argv0_len - exeext_len - 4,
371                           argv0 + argv0_len - exeext_len - 4,
372                           exeext_len);
373                 shorter[argv0_len - 4] = '\0';
374                 argv0_stripped = shorter;
375               }
376           }
377          done_stripping: ;
378       }
379   }
380
381   set_program_name (argv0_stripped);
382
383   prepare_relocate (orig_installprefix, orig_installdir, argv0);
384 }
385
386 /* Return the full pathname of the current executable, based on the earlier
387    call to set_program_name_and_installdir.  Return NULL if unknown.  */
388 char *
389 get_full_program_name (void)
390 {
391   return executable_fullname;
392 }
393
394 #endif