aboutsummaryrefslogtreecommitdiff
path: root/src/util/os_installation.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/os_installation.c')
-rw-r--r--src/util/os_installation.c443
1 files changed, 443 insertions, 0 deletions
diff --git a/src/util/os_installation.c b/src/util/os_installation.c
new file mode 100644
index 000000000..201095544
--- /dev/null
+++ b/src/util/os_installation.c
@@ -0,0 +1,443 @@
1/*
2 This file is part of GNUnet.
3 (C) 2006 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file src/util/os_installation.c
23 * @brief get paths used by the program
24 * @author Milan
25 */
26
27#ifdef __cplusplus
28extern "C"
29{
30#if 0 /* keep Emacsens' auto-indent happy */
31}
32#endif
33#endif
34
35#include <sys/stat.h>
36#include <stdlib.h>
37#include <string.h>
38#include <unistd.h>
39
40#include "platform.h"
41#include "gnunet_common.h"
42#include "gnunet_configuration_lib.h"
43#include "gnunet_disk_lib.h"
44#include "gnunet_os_lib.h"
45#if OSX
46#include <mach-o/ldsyms.h>
47#include <mach-o/dyld.h>
48#endif
49
50#if LINUX
51/**
52 * Try to determine path by reading /proc/PID/exe
53 */
54static char *
55get_path_from_proc_maps ()
56{
57 char fn[64];
58 char *line;
59 char *dir;
60 FILE *f;
61
62 GNUNET_snprintf (fn, 64, "/proc/%u/maps", getpid ());
63 line = GNUNET_malloc (1024);
64 dir = GNUNET_malloc (1024);
65 f = fopen (fn, "r");
66 if (f != NULL)
67 {
68 while (NULL != fgets (line, 1024, f))
69 {
70 if ((1 == sscanf (line,
71 "%*x-%*x %*c%*c%*c%*c %*x %*2u:%*2u %*u%*[ ]%s",
72 dir)) && (NULL != strstr (dir, "libgnunetutil")))
73 {
74 strstr (dir, "libgnunetutil")[0] = '\0';
75 fclose (f);
76 GNUNET_free (line);
77 return dir;
78 }
79 }
80 fclose (f);
81 }
82 GNUNET_free (dir);
83 GNUNET_free (line);
84 return NULL;
85}
86
87/**
88 * Try to determine path by reading /proc/PID/exe
89 */
90static char *
91get_path_from_proc_exe ()
92{
93 char fn[64];
94 char *lnk;
95 size_t size;
96
97 GNUNET_snprintf (fn, 64, "/proc/%u/exe", getpid ());
98 lnk = GNUNET_malloc (1024);
99 size = readlink (fn, lnk, 1023);
100 if ((size == 0) || (size >= 1024))
101 {
102 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "readlink", fn);
103 GNUNET_free (lnk);
104 return NULL;
105 }
106 lnk[size] = '\0';
107 while ((lnk[size] != '/') && (size > 0))
108 size--;
109 if ((size < 4) || (lnk[size - 4] != '/'))
110 {
111 /* not installed in "/bin/" -- binary path probably useless */
112 GNUNET_free (lnk);
113 return NULL;
114 }
115 lnk[size] = '\0';
116 return lnk;
117}
118#endif
119
120#if WINDOWS
121/**
122 * Try to determine path with win32-specific function
123 */
124static char *
125get_path_from_module_filename ()
126{
127 char *path;
128 char *idx;
129
130 path = GNUNET_malloc (4097);
131 GetModuleFileName (NULL, path, 4096);
132 idx = path + strlen (path);
133 while ((idx > path) && (*idx != '\\') && (*idx != '/'))
134 idx--;
135 *idx = '\0';
136 return path;
137}
138#endif
139
140#if OSX
141typedef int (*MyNSGetExecutablePathProto) (char *buf, size_t * bufsize);
142
143static char *
144get_path_from_NSGetExecutablePath ()
145{
146 static char zero = '\0';
147 char *path;
148 size_t len;
149 MyNSGetExecutablePathProto func;
150 int ret;
151
152 path = NULL;
153 func =
154 (MyNSGetExecutablePathProto) dlsym (RTLD_DEFAULT, "_NSGetExecutablePath");
155 if (!func)
156 return NULL;
157 path = &zero;
158 len = 0;
159 /* get the path len, including the trailing \0 */
160 func (path, &len);
161 if (len == 0)
162 return NULL;
163 path = GNUNET_malloc (len);
164 ret = func (path, &len);
165 if (ret != 0)
166 {
167 GNUNET_free (path);
168 return NULL;
169 }
170 len = strlen (path);
171 while ((path[len] != '/') && (len > 0))
172 len--;
173 path[len] = '\0';
174 return path;
175}
176
177static char *
178get_path_from_dyld_image ()
179{
180 const char *path;
181 char *p, *s;
182 int i;
183 int c;
184
185 p = NULL;
186 c = _dyld_image_count ();
187 for (i = 0; i < c; i++)
188 {
189 if (_dyld_get_image_header (i) == &_mh_dylib_header)
190 {
191 path = _dyld_get_image_name (i);
192 if (path != NULL && strlen (path) > 0)
193 {
194 p = strdup (path);
195 s = p + strlen (p);
196 while ((s > p) && (*s != '/'))
197 s--;
198 s++;
199 *s = '\0';
200 }
201 break;
202 }
203 }
204 return p;
205}
206#endif
207
208static char *
209get_path_from_PATH ()
210{
211 char *path;
212 char *pos;
213 char *end;
214 char *buf;
215 const char *p;
216 size_t size;
217
218 p = getenv ("PATH");
219 if (p == NULL)
220 return NULL;
221 path = GNUNET_strdup (p); /* because we write on it */
222 buf = GNUNET_malloc (strlen (path) + 20);
223 size = strlen (path);
224 pos = path;
225
226 while (NULL != (end = strchr (pos, ':')))
227 {
228 *end = '\0';
229 sprintf (buf, "%s/%s", pos, "gnunetd");
230 if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
231 {
232 pos = GNUNET_strdup (pos);
233 GNUNET_free (buf);
234 GNUNET_free (path);
235 return pos;
236 }
237 pos = end + 1;
238 }
239 sprintf (buf, "%s/%s", pos, "gnunetd");
240 if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
241 {
242 pos = GNUNET_strdup (pos);
243 GNUNET_free (buf);
244 GNUNET_free (path);
245 return pos;
246 }
247 GNUNET_free (buf);
248 GNUNET_free (path);
249 return NULL;
250}
251
252static char *
253get_path_from_GNUNET_PREFIX ()
254{
255 const char *p;
256
257 p = getenv ("GNUNET_PREFIX");
258 if (p != NULL)
259 return GNUNET_strdup (p);
260 return NULL;
261}
262
263/*
264 * @brief get the path to GNUnet bin/ or lib/, prefering the lib/ path
265 * @author Milan
266 *
267 * @return a pointer to the executable path, or NULL on error
268 */
269static char *
270os_get_gnunet_path ()
271{
272 char *ret;
273
274 ret = get_path_from_GNUNET_PREFIX ();
275 if (ret != NULL)
276 return ret;
277#if LINUX
278 ret = get_path_from_proc_maps ();
279 if (ret != NULL)
280 return ret;
281 ret = get_path_from_proc_exe ();
282 if (ret != NULL)
283 return ret;
284#endif
285#if WINDOWS
286 ret = get_path_from_module_filename ();
287 if (ret != NULL)
288 return ret;
289#endif
290#if OSX
291 ret = get_path_from_dyld_image ();
292 if (ret != NULL)
293 return ret;
294 ret = get_path_from_NSGetExecutablePath ();
295 if (ret != NULL)
296 return ret;
297#endif
298 ret = get_path_from_PATH ();
299 if (ret != NULL)
300 return ret;
301 /* other attempts here */
302 return NULL;
303}
304
305/*
306 * @brief get the path to current app's bin/
307 * @author Milan
308 *
309 * @return a pointer to the executable path, or NULL on error
310 */
311static char *
312os_get_exec_path ()
313{
314 char *ret;
315
316#if LINUX
317 ret = get_path_from_proc_exe ();
318 if (ret != NULL)
319 return ret;
320#endif
321#if WINDOWS
322 ret = get_path_from_module_filename ();
323 if (ret != NULL)
324 return ret;
325#endif
326#if OSX
327 ret = get_path_from_NSGetExecutablePath ();
328 if (ret != NULL)
329 return ret;
330#endif
331 /* other attempts here */
332 return NULL;
333}
334
335
336
337/**
338 * @brief get the path to a specific GNUnet installation directory or,
339 * with GNUNET_IPK_SELF_PREFIX, the current running apps installation directory
340 * @author Milan
341 * @return a pointer to the dir path (to be freed by the caller)
342 */
343char *
344GNUNET_OS_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind)
345{
346 size_t n;
347 const char *dirname;
348 char *execpath = NULL;
349 char *tmp;
350 int isbasedir;
351
352 /* if wanted, try to get the current app's bin/ */
353 if (dirkind == GNUNET_OS_IPK_SELF_PREFIX)
354 execpath = os_get_exec_path ();
355
356 /* try to get GNUnet's bin/ or lib/, or if previous was unsuccessful some
357 * guess for the current app */
358 if (execpath == NULL)
359 execpath = os_get_gnunet_path ();
360
361 if (execpath == NULL)
362 return NULL;
363
364 n = strlen (execpath);
365 if (n == 0)
366 {
367 /* should never happen, but better safe than sorry */
368 GNUNET_free (execpath);
369 return NULL;
370 }
371 /* remove filename itself */
372 while ((n > 1) && (execpath[n - 1] == DIR_SEPARATOR))
373 execpath[--n] = '\0';
374
375 isbasedir = 1;
376 if ((n > 5) &&
377 ((0 == strcasecmp (&execpath[n - 5], "lib32")) ||
378 (0 == strcasecmp (&execpath[n - 5], "lib64"))))
379 {
380 if (dirkind != GNUNET_OS_IPK_LIBDIR)
381 {
382 /* strip '/lib32' or '/lib64' */
383 execpath[n - 5] = '\0';
384 n -= 5;
385 }
386 else
387 isbasedir = 0;
388 }
389 else if ((n > 3) &&
390 ((0 == strcasecmp (&execpath[n - 3], "bin")) ||
391 (0 == strcasecmp (&execpath[n - 3], "lib"))))
392 {
393 /* strip '/bin' or '/lib' */
394 execpath[n - 3] = '\0';
395 n -= 3;
396 }
397 /* in case this was a directory named foo-bin, remove "foo-" */
398 while ((n > 1) && (execpath[n - 1] == DIR_SEPARATOR))
399 execpath[--n] = '\0';
400 switch (dirkind)
401 {
402 case GNUNET_OS_IPK_PREFIX:
403 case GNUNET_OS_IPK_SELF_PREFIX:
404 dirname = DIR_SEPARATOR_STR;
405 break;
406 case GNUNET_OS_IPK_BINDIR:
407 dirname = DIR_SEPARATOR_STR "bin" DIR_SEPARATOR_STR;
408 break;
409 case GNUNET_OS_IPK_LIBDIR:
410 if (isbasedir)
411 dirname =
412 DIR_SEPARATOR_STR "lib" DIR_SEPARATOR_STR "gnunet"
413 DIR_SEPARATOR_STR;
414 else
415 dirname = DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
416 break;
417 case GNUNET_OS_IPK_DATADIR:
418 dirname =
419 DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "gnunet"
420 DIR_SEPARATOR_STR;
421 break;
422 case GNUNET_OS_IPK_LOCALEDIR:
423 dirname =
424 DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "locale"
425 DIR_SEPARATOR_STR;
426 break;
427 default:
428 GNUNET_free (execpath);
429 return NULL;
430 }
431 tmp = GNUNET_malloc (strlen (execpath) + strlen (dirname) + 1);
432 sprintf (tmp, "%s%s", execpath, dirname);
433 GNUNET_free (execpath);
434 return tmp;
435}
436
437#if 0 /* keep Emacsens' auto-indent happy */
438{
439#endif
440#ifdef __cplusplus
441}
442#endif
443/* end of installpath.c */