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