diff options
Diffstat (limited to 'src/util/os_installation.c')
-rw-r--r-- | src/util/os_installation.c | 443 |
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 | ||
28 | extern "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 | */ | ||
54 | static char * | ||
55 | get_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 | */ | ||
90 | static char * | ||
91 | get_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 | */ | ||
124 | static char * | ||
125 | get_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 | ||
141 | typedef int (*MyNSGetExecutablePathProto) (char *buf, size_t * bufsize); | ||
142 | |||
143 | static char * | ||
144 | get_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 | |||
177 | static char * | ||
178 | get_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 | |||
208 | static char * | ||
209 | get_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 | |||
252 | static char * | ||
253 | get_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 | */ | ||
269 | static char * | ||
270 | os_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 | */ | ||
311 | static char * | ||
312 | os_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 | */ | ||
343 | char * | ||
344 | GNUNET_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 */ | ||