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