Sync usage with man page.
[netbsd-mini2440.git] / gnu / dist / gettext / gettext-tools / lib / progreloc.c
blob22f2350063a9dd6758d008c56d7bfcddc743e766
1 /* Provide relocatable programs.
2 Copyright (C) 2003-2004 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 it
6 under the terms of the GNU Library General Public License as published
7 by the Free Software Foundation; either version 2, or (at your option)
8 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 GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
18 USA. */
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
25 /* Specification. */
26 #include "progname.h"
28 #include <stdbool.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #if HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36 #include <sys/stat.h>
38 #if defined _WIN32 || defined __WIN32__
39 # undef WIN32 /* avoid warning on mingw32 */
40 # define WIN32
41 #endif
43 #ifdef WIN32
44 # define WIN32_LEAN_AND_MEAN
45 # include <windows.h>
46 #endif
48 #include "xreadlink.h"
49 #include "canonicalize.h"
50 #include "relocatable.h"
52 #ifdef NO_XMALLOC
53 # define xmalloc malloc
54 # define xstrdup strdup
55 #else
56 # include "xalloc.h"
57 #endif
59 /* Pathname support.
60 ISSLASH(C) tests whether C is a directory separator character.
61 IS_PATH_WITH_DIR(P) tests whether P contains a directory specification.
63 #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
64 /* Win32, Cygwin, OS/2, DOS */
65 # define ISSLASH(C) ((C) == '/' || (C) == '\\')
66 # define HAS_DEVICE(P) \
67 ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
68 && (P)[1] == ':')
69 # define IS_PATH_WITH_DIR(P) \
70 (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
71 # define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
72 #else
73 /* Unix */
74 # define ISSLASH(C) ((C) == '/')
75 # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
76 # define FILE_SYSTEM_PREFIX_LEN(P) 0
77 #endif
79 #undef set_program_name
82 #if ENABLE_RELOCATABLE
84 #ifdef __linux__
85 /* File descriptor of the executable.
86 (Only used to verify that we find the correct executable.) */
87 static int executable_fd = -1;
88 #endif
90 /* Tests whether a given pathname may belong to the executable. */
91 static bool
92 maybe_executable (const char *filename)
94 #if !defined WIN32
95 if (access (filename, X_OK) < 0)
96 return false;
98 #ifdef __linux__
99 if (executable_fd >= 0)
101 /* If we already have an executable_fd, check that filename points to
102 the same inode. */
103 struct stat statexe;
104 struct stat statfile;
106 if (fstat (executable_fd, &statexe) >= 0)
108 if (stat (filename, &statfile) < 0)
109 return false;
110 if (!(statfile.st_dev
111 && statfile.st_dev == statexe.st_dev
112 && statfile.st_ino == statexe.st_ino))
113 return false;
116 #endif
117 #endif
119 return true;
122 /* Determine the full pathname of the current executable, freshly allocated.
123 Return NULL if unknown.
124 Guaranteed to work on Linux and Woe32. Likely to work on the other
125 Unixes (maybe except BeOS), under most conditions. */
126 static char *
127 find_executable (const char *argv0)
129 #ifdef WIN32
130 char buf[1024];
131 int length = GetModuleFileName (NULL, buf, sizeof (buf));
132 if (length < 0)
133 return NULL;
134 if (!IS_PATH_WITH_DIR (buf))
135 /* Shouldn't happen. */
136 return NULL;
137 return xstrdup (buf);
138 #else /* Unix */
139 #ifdef __linux__
140 /* The executable is accessible as /proc/<pid>/exe. In newer Linux
141 versions, also as /proc/self/exe. Linux >= 2.1 provides a symlink
142 to the true pathname; older Linux versions give only device and ino,
143 enclosed in brackets, which we cannot use here. */
145 char *link;
147 link = xreadlink ("/proc/self/exe");
148 if (link != NULL && link[0] != '[')
149 return link;
150 if (executable_fd < 0)
151 executable_fd = open ("/proc/self/exe", O_RDONLY, 0);
154 char buf[6+10+5];
155 sprintf (buf, "/proc/%d/exe", getpid ());
156 link = xreadlink (buf);
157 if (link != NULL && link[0] != '[')
158 return link;
159 if (executable_fd < 0)
160 executable_fd = open (buf, O_RDONLY, 0);
163 #endif
164 /* Guess the executable's full path. We assume the executable has been
165 called via execlp() or execvp() with properly set up argv[0]. The
166 login(1) convention to add a '-' prefix to argv[0] is not supported. */
168 bool has_slash = false;
170 const char *p;
171 for (p = argv0; *p; p++)
172 if (*p == '/')
174 has_slash = true;
175 break;
178 if (!has_slash)
180 /* exec searches paths without slashes in the directory list given
181 by $PATH. */
182 const char *path = getenv ("PATH");
184 if (path != NULL)
186 const char *p;
187 const char *p_next;
189 for (p = path; *p; p = p_next)
191 const char *q;
192 size_t p_len;
193 char *concat_name;
195 for (q = p; *q; q++)
196 if (*q == ':')
197 break;
198 p_len = q - p;
199 p_next = (*q == '\0' ? q : q + 1);
201 /* We have a path item at p, of length p_len.
202 Now concatenate the path item and argv0. */
203 concat_name = (char *) xmalloc (p_len + strlen (argv0) + 2);
204 #ifdef NO_XMALLOC
205 if (concat_name == NULL)
206 return NULL;
207 #endif
208 if (p_len == 0)
209 /* An empty PATH element designates the current directory. */
210 strcpy (concat_name, argv0);
211 else
213 memcpy (concat_name, p, p_len);
214 concat_name[p_len] = '/';
215 strcpy (concat_name + p_len + 1, argv0);
217 if (maybe_executable (concat_name))
218 return canonicalize_file_name (concat_name);
219 free (concat_name);
222 /* Not found in the PATH, assume the current directory. */
224 /* exec treats paths containing slashes as relative to the current
225 directory. */
226 if (maybe_executable (argv0))
227 return canonicalize_file_name (argv0);
229 /* No way to find the executable. */
230 return NULL;
231 #endif
234 /* Full pathname of executable, or NULL. */
235 static char *executable_fullname;
237 static void
238 prepare_relocate (const char *orig_installprefix, const char *orig_installdir,
239 const char *argv0)
241 const char *curr_prefix;
243 /* Determine the full pathname of the current executable. */
244 executable_fullname = find_executable (argv0);
246 /* Determine the current installation prefix from it. */
247 curr_prefix = compute_curr_prefix (orig_installprefix, orig_installdir,
248 executable_fullname);
249 if (curr_prefix != NULL)
250 /* Now pass this prefix to all copies of the relocate.c source file. */
251 set_relocation_prefix (orig_installprefix, curr_prefix);
254 /* Set program_name, based on argv[0], and original installation prefix and
255 directory, for relocatability. */
256 void
257 set_program_name_and_installdir (const char *argv0,
258 const char *orig_installprefix,
259 const char *orig_installdir)
261 const char *argv0_stripped = argv0;
263 /* Relocatable programs are renamed to .bin by install-reloc. Remove
264 this suffix here. */
266 size_t argv0_len = strlen (argv0);
267 if (argv0_len > 4 && memcmp (argv0 + argv0_len - 4, ".bin", 4) == 0)
269 char *shorter = (char *) xmalloc (argv0_len - 4 + 1);
270 #ifdef NO_XMALLOC
271 if (shorter != NULL)
272 #endif
274 memcpy (shorter, argv0, argv0_len - 4);
275 shorter[argv0_len - 4] = '\0';
276 argv0_stripped = shorter;
281 set_program_name (argv0_stripped);
283 prepare_relocate (orig_installprefix, orig_installdir, argv0);
286 /* Return the full pathname of the current executable, based on the earlier
287 call to set_program_name_and_installdir. Return NULL if unknown. */
288 char *
289 get_full_program_name (void)
291 return executable_fullname;
294 #endif