glob: fix heap buffer overflow
[gnulib.git] / lib / progreloc.c
blob88387aca11eb8d2357ddb3365d21f8cc46dab78d
1 /* Provide relocatable programs.
2 Copyright (C) 2003-2017 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
20 #include <config.h>
22 /* Specification. */
23 #include "progname.h"
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>
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
38 #if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__
39 # define WINDOWS_NATIVE
40 #endif
42 #ifdef WINDOWS_NATIVE
43 # define WIN32_LEAN_AND_MEAN
44 # include <windows.h>
45 #endif
47 #ifdef __EMX__
48 # define INCL_DOS
49 # include <os2.h>
50 #endif
52 #include "relocatable.h"
54 #ifdef NO_XMALLOC
55 # include "areadlink.h"
56 # define xreadlink areadlink
57 #else
58 # include "xreadlink.h"
59 #endif
61 #ifdef NO_XMALLOC
62 # define xmalloc malloc
63 # define xstrdup strdup
64 #else
65 # include "xalloc.h"
66 #endif
68 #ifndef O_EXEC
69 # define O_EXEC O_RDONLY /* This is often close enough in older systems. */
70 #endif
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);
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.
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
97 /* Use the system functions, not the gnulib overrides in this file. */
98 #undef sprintf
100 #undef set_program_name
103 #if ENABLE_RELOCATABLE
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
111 /* Tests whether a given pathname may belong to the executable. */
112 static bool
113 maybe_executable (const char *filename)
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
121 #if defined __linux__ || defined __CYGWIN__
122 if (executable_fd >= 0)
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;
129 if (fstat (executable_fd, &statexe) >= 0)
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;
139 #endif
141 return true;
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)
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 <https://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];
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;
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;
179 _fnslashify (location);
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. */
189 char *link;
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);
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);
207 # endif
208 # ifdef __CYGWIN__
209 /* The executable is accessible as /proc/<pid>/exe, at least in
210 Cygwin >= 1.5. */
212 char *link;
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);
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. */
235 bool has_slash = false;
237 const char *p;
238 for (p = argv0; *p; p++)
239 if (*p == '/')
241 has_slash = true;
242 break;
245 if (!has_slash)
247 /* exec searches paths without slashes in the directory list given
248 by $PATH. */
249 const char *path = getenv ("PATH");
251 if (path != NULL)
253 const char *p;
254 const char *p_next;
256 for (p = path; *p; p = p_next)
258 const char *q;
259 size_t p_len;
260 char *concat_name;
262 for (q = p; *q; q++)
263 if (*q == ':')
264 break;
265 p_len = q - p;
266 p_next = (*q == '\0' ? q : q + 1);
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
280 memcpy (concat_name, p, p_len);
281 concat_name[p_len] = '/';
282 strcpy (concat_name + p_len + 1, argv0);
284 if (maybe_executable (concat_name))
285 return canonicalize_file_name (concat_name);
286 free (concat_name);
289 /* Not found in the PATH, assume the current directory. */
291 /* exec treats paths containing slashes as relative to the current
292 directory. */
293 if (maybe_executable (argv0))
294 return canonicalize_file_name (argv0);
296 /* No way to find the executable. */
297 return NULL;
298 #endif
301 /* Full pathname of executable, or NULL. */
302 static char *executable_fullname;
304 static void
305 prepare_relocate (const char *orig_installprefix, const char *orig_installdir,
306 const char *argv0)
308 char *curr_prefix;
310 /* Determine the full pathname of the current executable. */
311 executable_fullname = find_executable (argv0);
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)
318 /* Now pass this prefix to all copies of the relocate.c source file. */
319 set_relocation_prefix (orig_installprefix, curr_prefix);
321 free (curr_prefix);
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)
332 const char *argv0_stripped = argv0;
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. */
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)
343 if (sizeof (EXEEXT) > sizeof (""))
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++)
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;
361 /* Remove ".bin" before EXEEXT or its equivalent. */
363 char *shorter = (char *) xmalloc (argv0_len - 4 + 1);
364 #ifdef NO_XMALLOC
365 if (shorter != NULL)
366 #endif
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;
377 done_stripping: ;
381 set_program_name (argv0_stripped);
383 prepare_relocate (orig_installprefix, orig_installdir, argv0);
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)
391 return executable_fullname;
394 #endif