This source file includes following definitions.
- safe_read
- full_read
- maybe_executable
- find_executable
- prepare_relocate
- set_program_name_and_installdir
- get_full_program_name
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #define _GL_USE_STDLIB_ALLOC 1
20 #include <config.h>
21
22
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
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
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
79
80
81 extern char * canonicalize_file_name (const char *name);
82
83 #if defined WINDOWS_NATIVE
84
85 # undef GetModuleFileName
86 # define GetModuleFileName GetModuleFileNameA
87 #endif
88
89
90
91
92
93 #if (defined _WIN32 && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__
94
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
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
110 #undef sprintf
111
112 #undef set_program_name
113
114
115 #if ENABLE_RELOCATABLE
116
117 #ifdef __sun
118
119
120 static size_t
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
133 static size_t
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
161
162 static int executable_fd = -1;
163 #endif
164
165
166 #if !(defined WINDOWS_NATIVE || defined __EMX__)
167
168
169 static bool
170 maybe_executable (const char *filename)
171 {
172
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
182
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
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
206
207
208
209 static char *
210 find_executable (const char *argv0)
211 {
212 #if defined WINDOWS_NATIVE
213
214
215
216
217
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
224 return NULL;
225 return xstrdup (location);
226 #elif defined __EMX__
227 PPIB ppib;
228 char location[CCHMAXPATH];
229
230
231
232 if (DosGetInfoBlocks (NULL, &ppib))
233 return NULL;
234
235
236
237 if (DosQueryModuleName (ppib->pib_hmte, sizeof (location), location))
238 return NULL;
239
240 _fnslashify (location);
241
242 return xstrdup (location);
243 #else
244 # if defined __linux__
245
246
247
248
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
271
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
282
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
297
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
308
309
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
327
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
340
341
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
349
350
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
365
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
386
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
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
407 }
408
409
410 if (maybe_executable (argv0))
411 return canonicalize_file_name (argv0);
412 }
413
414 return NULL;
415 #endif
416 }
417
418
419 static char *executable_fullname;
420
421 static void
422 prepare_relocate (const char *orig_installprefix, const char *orig_installdir,
423 const char *argv0)
424 {
425 char *curr_prefix;
426
427
428 executable_fullname = find_executable (argv0);
429
430
431 curr_prefix = compute_curr_prefix (orig_installprefix, orig_installdir,
432 executable_fullname);
433 if (curr_prefix != NULL)
434 {
435
436 set_relocation_prefix (orig_installprefix, curr_prefix);
437
438 free (curr_prefix);
439 }
440 }
441
442
443
444 void
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
452
453
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
463
464
465
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
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
504
505 char *
506 get_full_program_name (void)
507 {
508 return executable_fullname;
509 }
510
511 #endif