diff options
Diffstat (limited to 'src/util/os_installation.c')
-rw-r--r-- | src/util/os_installation.c | 833 |
1 files changed, 0 insertions, 833 deletions
diff --git a/src/util/os_installation.c b/src/util/os_installation.c deleted file mode 100644 index 1835c6e84..000000000 --- a/src/util/os_installation.c +++ /dev/null | |||
@@ -1,833 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2006-2018, 2022 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your 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 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file src/util/os_installation.c | ||
23 | * @brief get paths used by the program | ||
24 | * @author Milan | ||
25 | * @author Christian Fuchs | ||
26 | * @author Christian Grothoff | ||
27 | * @author Matthias Wachs | ||
28 | * @author Heikki Lindholm | ||
29 | * @author LRN | ||
30 | */ | ||
31 | #include <sys/stat.h> | ||
32 | #include <stdlib.h> | ||
33 | #include <string.h> | ||
34 | #include <unistd.h> | ||
35 | #include <unistr.h> /* for u16_to_u8 */ | ||
36 | |||
37 | #include "platform.h" | ||
38 | #include "gnunet_util_lib.h" | ||
39 | #if DARWIN | ||
40 | #include <mach-o/ldsyms.h> | ||
41 | #include <mach-o/dyld.h> | ||
42 | #endif | ||
43 | |||
44 | |||
45 | #define LOG(kind, ...) \ | ||
46 | GNUNET_log_from (kind, "util-os-installation", __VA_ARGS__) | ||
47 | |||
48 | #define LOG_STRERROR_FILE(kind, syscall, filename) \ | ||
49 | GNUNET_log_from_strerror_file (kind, \ | ||
50 | "util-os-installation", \ | ||
51 | syscall, \ | ||
52 | filename) | ||
53 | |||
54 | |||
55 | /** | ||
56 | * Default project data used for installation path detection | ||
57 | * for GNUnet (core). | ||
58 | */ | ||
59 | static const struct GNUNET_OS_ProjectData default_pd = { | ||
60 | .libname = "libgnunetutil", | ||
61 | .project_dirname = "gnunet", | ||
62 | .binary_name = "gnunet-arm", | ||
63 | .version = PACKAGE_VERSION " " VCS_VERSION, | ||
64 | .env_varname = "GNUNET_PREFIX", | ||
65 | .base_config_varname = "GNUNET_BASE_CONFIG", | ||
66 | .bug_email = "gnunet-developers@gnu.org", | ||
67 | .homepage = "http://www.gnu.org/s/gnunet/", | ||
68 | .config_file = "gnunet.conf", | ||
69 | .user_config_file = "~/.config/gnunet.conf", | ||
70 | .is_gnu = 1, | ||
71 | .gettext_domain = "gnunet", | ||
72 | .gettext_path = NULL, | ||
73 | .agpl_url = GNUNET_AGPL_URL, | ||
74 | }; | ||
75 | |||
76 | /** | ||
77 | * Which project data do we currently use for installation | ||
78 | * path detection? Never NULL. | ||
79 | */ | ||
80 | static const struct GNUNET_OS_ProjectData *current_pd = &default_pd; | ||
81 | |||
82 | /** | ||
83 | * PD for which gettext has been initialized last. | ||
84 | * Note that the gettext initialization done within | ||
85 | * GNUNET_PROGRAM_run2 is for the specific application. | ||
86 | */ | ||
87 | static const struct GNUNET_OS_ProjectData *gettextinit; | ||
88 | |||
89 | |||
90 | /** | ||
91 | * Return default project data used by 'libgnunetutil' for GNUnet. | ||
92 | */ | ||
93 | const struct GNUNET_OS_ProjectData * | ||
94 | GNUNET_OS_project_data_default (void) | ||
95 | { | ||
96 | return &default_pd; | ||
97 | } | ||
98 | |||
99 | |||
100 | /** | ||
101 | * @return current project data. | ||
102 | */ | ||
103 | const struct GNUNET_OS_ProjectData * | ||
104 | GNUNET_OS_project_data_get () | ||
105 | { | ||
106 | if (current_pd != gettextinit) | ||
107 | { | ||
108 | char *path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LOCALEDIR); | ||
109 | |||
110 | if (NULL != path) | ||
111 | bindtextdomain (PACKAGE, | ||
112 | path); | ||
113 | GNUNET_free (path); | ||
114 | gettextinit = current_pd; | ||
115 | } | ||
116 | return current_pd; | ||
117 | } | ||
118 | |||
119 | |||
120 | /** | ||
121 | * Setup OS subsystem with project data. | ||
122 | * | ||
123 | * @param pd project data used to determine paths | ||
124 | */ | ||
125 | void | ||
126 | GNUNET_OS_init (const struct GNUNET_OS_ProjectData *pd) | ||
127 | { | ||
128 | GNUNET_assert (NULL != pd); | ||
129 | current_pd = pd; | ||
130 | if (pd != gettextinit) | ||
131 | { | ||
132 | char *path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LOCALEDIR); | ||
133 | |||
134 | if (NULL != path) | ||
135 | bindtextdomain (PACKAGE, | ||
136 | path); | ||
137 | GNUNET_free (path); | ||
138 | gettextinit = pd; | ||
139 | } | ||
140 | } | ||
141 | |||
142 | |||
143 | #ifdef __linux__ | ||
144 | /** | ||
145 | * Try to determine path by reading /proc/PID/exe | ||
146 | * | ||
147 | * @return NULL on error | ||
148 | */ | ||
149 | static char * | ||
150 | get_path_from_proc_maps (void) | ||
151 | { | ||
152 | char fn[64]; | ||
153 | char line[1024]; | ||
154 | char dir[1024]; | ||
155 | FILE *f; | ||
156 | char *lgu; | ||
157 | |||
158 | if (NULL == current_pd->libname) | ||
159 | return NULL; | ||
160 | GNUNET_snprintf (fn, | ||
161 | sizeof(fn), | ||
162 | "/proc/%u/maps", | ||
163 | getpid ()); | ||
164 | if (NULL == (f = fopen (fn, "r"))) | ||
165 | return NULL; | ||
166 | while (NULL != fgets (line, sizeof(line), f)) | ||
167 | { | ||
168 | if ((1 == sscanf (line, | ||
169 | "%*p-%*p %*c%*c%*c%*c %*x %*x:%*x %*u%*[ ]%1023s", | ||
170 | dir)) && | ||
171 | (NULL != (lgu = strstr (dir, | ||
172 | current_pd->libname)))) | ||
173 | { | ||
174 | lgu[0] = '\0'; | ||
175 | fclose (f); | ||
176 | return GNUNET_strdup (dir); | ||
177 | } | ||
178 | } | ||
179 | fclose (f); | ||
180 | return NULL; | ||
181 | } | ||
182 | |||
183 | |||
184 | /** | ||
185 | * Try to determine path by reading /proc/PID/exe | ||
186 | * | ||
187 | * @return NULL on error | ||
188 | */ | ||
189 | static char * | ||
190 | get_path_from_proc_exe (void) | ||
191 | { | ||
192 | char fn[64]; | ||
193 | char lnk[1024]; | ||
194 | ssize_t size; | ||
195 | char *lep; | ||
196 | |||
197 | GNUNET_snprintf (fn, sizeof(fn), "/proc/%u/exe", getpid ()); | ||
198 | size = readlink (fn, lnk, sizeof(lnk) - 1); | ||
199 | if (size <= 0) | ||
200 | { | ||
201 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "readlink", fn); | ||
202 | return NULL; | ||
203 | } | ||
204 | GNUNET_assert (((size_t) size) < sizeof(lnk)); | ||
205 | lnk[size] = '\0'; | ||
206 | while ((lnk[size] != '/') && (size > 0)) | ||
207 | size--; | ||
208 | GNUNET_asprintf (&lep, "/%s/libexec/", current_pd->project_dirname); | ||
209 | /* test for being in lib/gnunet/libexec/ or lib/MULTIARCH/gnunet/libexec */ | ||
210 | if ((((size_t) size) > strlen (lep)) && | ||
211 | (0 == strcmp (lep, &lnk[size - strlen (lep)]))) | ||
212 | size -= strlen (lep) - 1; | ||
213 | GNUNET_free (lep); | ||
214 | if ((size < 4) || (lnk[size - 4] != '/')) | ||
215 | { | ||
216 | /* not installed in "/bin/" -- binary path probably useless */ | ||
217 | return NULL; | ||
218 | } | ||
219 | lnk[size] = '\0'; | ||
220 | return GNUNET_strdup (lnk); | ||
221 | } | ||
222 | |||
223 | |||
224 | #endif | ||
225 | |||
226 | |||
227 | #if DARWIN | ||
228 | /** | ||
229 | * Signature of the '_NSGetExecutablePath" function. | ||
230 | * | ||
231 | * @param buf where to write the path | ||
232 | * @param number of bytes available in @a buf | ||
233 | * @return 0 on success, otherwise desired number of bytes is stored in 'bufsize' | ||
234 | */ | ||
235 | typedef int (*MyNSGetExecutablePathProto) (char *buf, size_t *bufsize); | ||
236 | |||
237 | |||
238 | /** | ||
239 | * Try to obtain the path of our executable using '_NSGetExecutablePath'. | ||
240 | * | ||
241 | * @return NULL on error | ||
242 | */ | ||
243 | static char * | ||
244 | get_path_from_NSGetExecutablePath (void) | ||
245 | { | ||
246 | static char zero = '\0'; | ||
247 | char *path; | ||
248 | size_t len; | ||
249 | MyNSGetExecutablePathProto func; | ||
250 | |||
251 | path = NULL; | ||
252 | if (NULL == | ||
253 | (func = (MyNSGetExecutablePathProto) dlsym (RTLD_DEFAULT, | ||
254 | "_NSGetExecutablePath"))) | ||
255 | return NULL; | ||
256 | path = &zero; | ||
257 | len = 0; | ||
258 | /* get the path len, including the trailing \0 */ | ||
259 | (void) func (path, &len); | ||
260 | if (0 == len) | ||
261 | return NULL; | ||
262 | path = GNUNET_malloc (len); | ||
263 | if (0 != func (path, &len)) | ||
264 | { | ||
265 | GNUNET_free (path); | ||
266 | return NULL; | ||
267 | } | ||
268 | len = strlen (path); | ||
269 | while ((path[len] != '/') && (len > 0)) | ||
270 | len--; | ||
271 | path[len] = '\0'; | ||
272 | return path; | ||
273 | } | ||
274 | |||
275 | |||
276 | /** | ||
277 | * Try to obtain the path of our executable using '_dyld_image' API. | ||
278 | * | ||
279 | * @return NULL on error | ||
280 | */ | ||
281 | static char * | ||
282 | get_path_from_dyld_image (void) | ||
283 | { | ||
284 | const char *path; | ||
285 | char *p; | ||
286 | char *s; | ||
287 | unsigned int i; | ||
288 | int c; | ||
289 | |||
290 | c = _dyld_image_count (); | ||
291 | for (i = 0; i < c; i++) | ||
292 | { | ||
293 | if (((const void *) _dyld_get_image_header (i)) != | ||
294 | ((const void *) &_mh_dylib_header)) | ||
295 | continue; | ||
296 | path = _dyld_get_image_name (i); | ||
297 | if ((NULL == path) || (0 == strlen (path))) | ||
298 | continue; | ||
299 | p = GNUNET_strdup (path); | ||
300 | s = p + strlen (p); | ||
301 | while ((s > p) && ('/' != *s)) | ||
302 | s--; | ||
303 | s++; | ||
304 | *s = '\0'; | ||
305 | return p; | ||
306 | } | ||
307 | return NULL; | ||
308 | } | ||
309 | |||
310 | |||
311 | #endif | ||
312 | |||
313 | |||
314 | /** | ||
315 | * Return the actual path to a file found in the current | ||
316 | * PATH environment variable. | ||
317 | * | ||
318 | * @param binary the name of the file to find | ||
319 | * @return path to binary, NULL if not found | ||
320 | */ | ||
321 | static char * | ||
322 | get_path_from_PATH (const char *binary) | ||
323 | { | ||
324 | char *path; | ||
325 | char *pos; | ||
326 | char *end; | ||
327 | char *buf; | ||
328 | const char *p; | ||
329 | |||
330 | if (NULL == (p = getenv ("PATH"))) | ||
331 | return NULL; | ||
332 | |||
333 | path = GNUNET_strdup (p); /* because we write on it */ | ||
334 | |||
335 | buf = GNUNET_malloc (strlen (path) + strlen (binary) + 1 + 1); | ||
336 | pos = path; | ||
337 | while (NULL != (end = strchr (pos, PATH_SEPARATOR))) | ||
338 | { | ||
339 | *end = '\0'; | ||
340 | sprintf (buf, "%s/%s", pos, binary); | ||
341 | if (GNUNET_DISK_file_test (buf) == GNUNET_YES) | ||
342 | { | ||
343 | pos = GNUNET_strdup (pos); | ||
344 | GNUNET_free (buf); | ||
345 | GNUNET_free (path); | ||
346 | return pos; | ||
347 | } | ||
348 | pos = end + 1; | ||
349 | } | ||
350 | sprintf (buf, "%s/%s", pos, binary); | ||
351 | if (GNUNET_YES == GNUNET_DISK_file_test (buf)) | ||
352 | { | ||
353 | pos = GNUNET_strdup (pos); | ||
354 | GNUNET_free (buf); | ||
355 | GNUNET_free (path); | ||
356 | return pos; | ||
357 | } | ||
358 | GNUNET_free (buf); | ||
359 | GNUNET_free (path); | ||
360 | return NULL; | ||
361 | } | ||
362 | |||
363 | |||
364 | /** | ||
365 | * Try to obtain the installation path using the "GNUNET_PREFIX" environment | ||
366 | * variable. | ||
367 | * | ||
368 | * @return NULL on error (environment variable not set) | ||
369 | */ | ||
370 | static char * | ||
371 | get_path_from_GNUNET_PREFIX (void) | ||
372 | { | ||
373 | const char *p; | ||
374 | |||
375 | if ((NULL != current_pd->env_varname) && | ||
376 | (NULL != (p = getenv (current_pd->env_varname)))) | ||
377 | return GNUNET_strdup (p); | ||
378 | if ((NULL != current_pd->env_varname_alt) && | ||
379 | (NULL != (p = getenv (current_pd->env_varname_alt)))) | ||
380 | return GNUNET_strdup (p); | ||
381 | return NULL; | ||
382 | } | ||
383 | |||
384 | |||
385 | /** | ||
386 | * @brief get the path to GNUnet bin/ or lib/, preferring the lib/ path | ||
387 | * @author Milan | ||
388 | * | ||
389 | * @return a pointer to the executable path, or NULL on error | ||
390 | */ | ||
391 | static char * | ||
392 | os_get_gnunet_path (void) | ||
393 | { | ||
394 | char *ret; | ||
395 | |||
396 | if (NULL != (ret = get_path_from_GNUNET_PREFIX ())) | ||
397 | return ret; | ||
398 | #ifdef __linux__ | ||
399 | if (NULL != (ret = get_path_from_proc_maps ())) | ||
400 | return ret; | ||
401 | /* try path *first*, before /proc/exe, as /proc/exe can be wrong */ | ||
402 | if ((NULL != current_pd->binary_name) && | ||
403 | (NULL != (ret = get_path_from_PATH (current_pd->binary_name)))) | ||
404 | return ret; | ||
405 | if (NULL != (ret = get_path_from_proc_exe ())) | ||
406 | return ret; | ||
407 | #endif | ||
408 | #if DARWIN | ||
409 | if (NULL != (ret = get_path_from_dyld_image ())) | ||
410 | return ret; | ||
411 | if (NULL != (ret = get_path_from_NSGetExecutablePath ())) | ||
412 | return ret; | ||
413 | #endif | ||
414 | if ((NULL != current_pd->binary_name) && | ||
415 | (NULL != (ret = get_path_from_PATH (current_pd->binary_name)))) | ||
416 | return ret; | ||
417 | /* other attempts here */ | ||
418 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
419 | _ ( | ||
420 | "Could not determine installation path for %s. Set `%s' environment variable.\n"), | ||
421 | current_pd->project_dirname, | ||
422 | current_pd->env_varname); | ||
423 | return NULL; | ||
424 | } | ||
425 | |||
426 | |||
427 | /** | ||
428 | * @brief get the path to current app's bin/ | ||
429 | * @return a pointer to the executable path, or NULL on error | ||
430 | */ | ||
431 | static char * | ||
432 | os_get_exec_path () | ||
433 | { | ||
434 | char *ret = NULL; | ||
435 | |||
436 | #ifdef __linux__ | ||
437 | if (NULL != (ret = get_path_from_proc_exe ())) | ||
438 | return ret; | ||
439 | #endif | ||
440 | #if DARWIN | ||
441 | if (NULL != (ret = get_path_from_NSGetExecutablePath ())) | ||
442 | return ret; | ||
443 | #endif | ||
444 | /* other attempts here */ | ||
445 | return ret; | ||
446 | } | ||
447 | |||
448 | |||
449 | /** | ||
450 | * @brief get the path to a specific GNUnet installation directory or, | ||
451 | * with #GNUNET_OS_IPK_SELF_PREFIX, the current running apps installation directory | ||
452 | * @return a pointer to the dir path (to be freed by the caller) | ||
453 | */ | ||
454 | char * | ||
455 | GNUNET_OS_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind) | ||
456 | { | ||
457 | size_t n; | ||
458 | char *dirname; | ||
459 | char *execpath = NULL; | ||
460 | char *tmp; | ||
461 | char *multiarch; | ||
462 | char *libdir; | ||
463 | int isbasedir; | ||
464 | |||
465 | /* if wanted, try to get the current app's bin/ */ | ||
466 | if (dirkind == GNUNET_OS_IPK_SELF_PREFIX) | ||
467 | execpath = os_get_exec_path (); | ||
468 | |||
469 | /* try to get GNUnet's bin/ or lib/, or if previous was unsuccessful some | ||
470 | * guess for the current app */ | ||
471 | if (NULL == execpath) | ||
472 | execpath = os_get_gnunet_path (); | ||
473 | if (NULL == execpath) | ||
474 | return NULL; | ||
475 | |||
476 | n = strlen (execpath); | ||
477 | if (0 == n) | ||
478 | { | ||
479 | /* should never happen, but better safe than sorry */ | ||
480 | GNUNET_free (execpath); | ||
481 | return NULL; | ||
482 | } | ||
483 | /* remove filename itself */ | ||
484 | while ((n > 1) && (DIR_SEPARATOR == execpath[n - 1])) | ||
485 | execpath[--n] = '\0'; | ||
486 | |||
487 | isbasedir = 1; | ||
488 | if ((n > 6) && ((0 == strcasecmp (&execpath[n - 6], "/lib32")) || | ||
489 | (0 == strcasecmp (&execpath[n - 6], "/lib64")))) | ||
490 | { | ||
491 | if ((GNUNET_OS_IPK_LIBDIR != dirkind) && | ||
492 | (GNUNET_OS_IPK_LIBEXECDIR != dirkind)) | ||
493 | { | ||
494 | /* strip '/lib32' or '/lib64' */ | ||
495 | execpath[n - 6] = '\0'; | ||
496 | n -= 6; | ||
497 | } | ||
498 | else | ||
499 | isbasedir = 0; | ||
500 | } | ||
501 | else if ((n > 4) && ((0 == strcasecmp (&execpath[n - 4], "/bin")) || | ||
502 | (0 == strcasecmp (&execpath[n - 4], "/lib")))) | ||
503 | { | ||
504 | /* strip '/bin' or '/lib' */ | ||
505 | execpath[n - 4] = '\0'; | ||
506 | n -= 4; | ||
507 | } | ||
508 | multiarch = NULL; | ||
509 | if (NULL != (libdir = strstr (execpath, "/lib/"))) | ||
510 | { | ||
511 | /* test for multi-arch path of the form "PREFIX/lib/MULTIARCH/"; | ||
512 | here we need to re-add 'multiarch' to lib and libexec paths later! */ | ||
513 | multiarch = &libdir[5]; | ||
514 | if (NULL == strchr (multiarch, '/')) | ||
515 | libdir[0] = | ||
516 | '\0'; /* Debian multiarch format, cut of from 'execpath' but preserve in multicarch */ | ||
517 | else | ||
518 | multiarch = | ||
519 | NULL; /* maybe not, multiarch still has a '/', which is not OK */ | ||
520 | } | ||
521 | /* in case this was a directory named foo-bin, remove "foo-" */ | ||
522 | while ((n > 1) && (execpath[n - 1] == DIR_SEPARATOR)) | ||
523 | execpath[--n] = '\0'; | ||
524 | switch (dirkind) | ||
525 | { | ||
526 | case GNUNET_OS_IPK_PREFIX: | ||
527 | case GNUNET_OS_IPK_SELF_PREFIX: | ||
528 | dirname = GNUNET_strdup (DIR_SEPARATOR_STR); | ||
529 | break; | ||
530 | |||
531 | case GNUNET_OS_IPK_BINDIR: | ||
532 | dirname = GNUNET_strdup (DIR_SEPARATOR_STR "bin" DIR_SEPARATOR_STR); | ||
533 | break; | ||
534 | |||
535 | case GNUNET_OS_IPK_LIBDIR: | ||
536 | if (isbasedir) | ||
537 | { | ||
538 | GNUNET_asprintf (&tmp, | ||
539 | "%s%s%s%s%s%s%s", | ||
540 | execpath, | ||
541 | DIR_SEPARATOR_STR "lib", | ||
542 | (NULL != multiarch) ? DIR_SEPARATOR_STR : "", | ||
543 | (NULL != multiarch) ? multiarch : "", | ||
544 | DIR_SEPARATOR_STR, | ||
545 | current_pd->project_dirname, | ||
546 | DIR_SEPARATOR_STR); | ||
547 | if (GNUNET_YES == GNUNET_DISK_directory_test (tmp, GNUNET_YES)) | ||
548 | { | ||
549 | GNUNET_free (execpath); | ||
550 | return tmp; | ||
551 | } | ||
552 | GNUNET_free (tmp); | ||
553 | tmp = NULL; | ||
554 | dirname = NULL; | ||
555 | if (4 == sizeof(void *)) | ||
556 | { | ||
557 | GNUNET_asprintf (&dirname, | ||
558 | DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR | ||
559 | "%s" DIR_SEPARATOR_STR, | ||
560 | current_pd->project_dirname); | ||
561 | GNUNET_asprintf (&tmp, "%s%s", execpath, dirname); | ||
562 | } | ||
563 | if (8 == sizeof(void *)) | ||
564 | { | ||
565 | GNUNET_asprintf (&dirname, | ||
566 | DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR | ||
567 | "%s" DIR_SEPARATOR_STR, | ||
568 | current_pd->project_dirname); | ||
569 | GNUNET_asprintf (&tmp, "%s%s", execpath, dirname); | ||
570 | } | ||
571 | |||
572 | if ((NULL != tmp) && | ||
573 | (GNUNET_YES == GNUNET_DISK_directory_test (tmp, GNUNET_YES))) | ||
574 | { | ||
575 | GNUNET_free (execpath); | ||
576 | GNUNET_free (dirname); | ||
577 | return tmp; | ||
578 | } | ||
579 | GNUNET_free (tmp); | ||
580 | GNUNET_free (dirname); | ||
581 | } | ||
582 | GNUNET_asprintf (&dirname, | ||
583 | DIR_SEPARATOR_STR "%s" DIR_SEPARATOR_STR, | ||
584 | current_pd->project_dirname); | ||
585 | break; | ||
586 | |||
587 | case GNUNET_OS_IPK_DATADIR: | ||
588 | GNUNET_asprintf (&dirname, | ||
589 | DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR | ||
590 | "%s" DIR_SEPARATOR_STR, | ||
591 | current_pd->project_dirname); | ||
592 | break; | ||
593 | |||
594 | case GNUNET_OS_IPK_LOCALEDIR: | ||
595 | dirname = GNUNET_strdup (DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR | ||
596 | "locale" DIR_SEPARATOR_STR); | ||
597 | break; | ||
598 | |||
599 | case GNUNET_OS_IPK_ICONDIR: | ||
600 | dirname = GNUNET_strdup (DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR | ||
601 | "icons" DIR_SEPARATOR_STR); | ||
602 | break; | ||
603 | |||
604 | case GNUNET_OS_IPK_DOCDIR: | ||
605 | GNUNET_asprintf (&dirname, | ||
606 | DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR | ||
607 | "doc" DIR_SEPARATOR_STR | ||
608 | "%s" DIR_SEPARATOR_STR, | ||
609 | current_pd->project_dirname); | ||
610 | break; | ||
611 | |||
612 | case GNUNET_OS_IPK_LIBEXECDIR: | ||
613 | if (isbasedir) | ||
614 | { | ||
615 | GNUNET_asprintf (&dirname, | ||
616 | DIR_SEPARATOR_STR "%s" DIR_SEPARATOR_STR | ||
617 | "libexec" DIR_SEPARATOR_STR, | ||
618 | current_pd->project_dirname); | ||
619 | GNUNET_asprintf (&tmp, | ||
620 | "%s%s%s%s", | ||
621 | execpath, | ||
622 | DIR_SEPARATOR_STR "lib" DIR_SEPARATOR_STR, | ||
623 | (NULL != multiarch) ? multiarch : "", | ||
624 | dirname); | ||
625 | GNUNET_free (dirname); | ||
626 | if (GNUNET_YES == GNUNET_DISK_directory_test (tmp, GNUNET_YES)) | ||
627 | { | ||
628 | GNUNET_free (execpath); | ||
629 | return tmp; | ||
630 | } | ||
631 | GNUNET_free (tmp); | ||
632 | tmp = NULL; | ||
633 | dirname = NULL; | ||
634 | if (4 == sizeof(void *)) | ||
635 | { | ||
636 | GNUNET_asprintf (&dirname, | ||
637 | DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR | ||
638 | "%s" DIR_SEPARATOR_STR | ||
639 | "libexec" DIR_SEPARATOR_STR, | ||
640 | current_pd->project_dirname); | ||
641 | GNUNET_asprintf (&tmp, "%s%s", execpath, dirname); | ||
642 | } | ||
643 | if (8 == sizeof(void *)) | ||
644 | { | ||
645 | GNUNET_asprintf (&dirname, | ||
646 | DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR | ||
647 | "%s" DIR_SEPARATOR_STR | ||
648 | "libexec" DIR_SEPARATOR_STR, | ||
649 | current_pd->project_dirname); | ||
650 | GNUNET_asprintf (&tmp, "%s%s", execpath, dirname); | ||
651 | } | ||
652 | if ((NULL != tmp) && | ||
653 | (GNUNET_YES == GNUNET_DISK_directory_test (tmp, GNUNET_YES))) | ||
654 | { | ||
655 | GNUNET_free (execpath); | ||
656 | GNUNET_free (dirname); | ||
657 | return tmp; | ||
658 | } | ||
659 | GNUNET_free (tmp); | ||
660 | GNUNET_free (dirname); | ||
661 | } | ||
662 | GNUNET_asprintf (&dirname, | ||
663 | DIR_SEPARATOR_STR "%s" DIR_SEPARATOR_STR | ||
664 | "libexec" DIR_SEPARATOR_STR, | ||
665 | current_pd->project_dirname); | ||
666 | break; | ||
667 | |||
668 | default: | ||
669 | GNUNET_free (execpath); | ||
670 | return NULL; | ||
671 | } | ||
672 | GNUNET_asprintf (&tmp, "%s%s", execpath, dirname); | ||
673 | GNUNET_free (dirname); | ||
674 | GNUNET_free (execpath); | ||
675 | return tmp; | ||
676 | } | ||
677 | |||
678 | |||
679 | /** | ||
680 | * Given the name of a gnunet-helper, gnunet-service or gnunet-daemon | ||
681 | * binary, try to prefix it with the libexec/-directory to get the | ||
682 | * full path. | ||
683 | * | ||
684 | * @param progname name of the binary | ||
685 | * @return full path to the binary, if possible, otherwise copy of 'progname' | ||
686 | */ | ||
687 | char * | ||
688 | GNUNET_OS_get_libexec_binary_path (const char *progname) | ||
689 | { | ||
690 | static char *cache; | ||
691 | char *libexecdir; | ||
692 | char *binary; | ||
693 | |||
694 | if ((DIR_SEPARATOR == progname[0]) || | ||
695 | (GNUNET_YES == | ||
696 | GNUNET_STRINGS_path_is_absolute (progname, GNUNET_NO, NULL, NULL))) | ||
697 | return GNUNET_strdup (progname); | ||
698 | if (NULL != cache) | ||
699 | libexecdir = cache; | ||
700 | else | ||
701 | libexecdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBEXECDIR); | ||
702 | if (NULL == libexecdir) | ||
703 | return GNUNET_strdup (progname); | ||
704 | GNUNET_asprintf (&binary, "%s%s", libexecdir, progname); | ||
705 | cache = libexecdir; | ||
706 | return binary; | ||
707 | } | ||
708 | |||
709 | |||
710 | /** | ||
711 | * Given the name of a helper, service or daemon binary construct the full | ||
712 | * path to the binary using the SUID_BINARY_PATH in the PATHS section of the | ||
713 | * configuration. If that option is not present, fall back to | ||
714 | * GNUNET_OS_get_libexec_binary_path. If @a progname is an absolute path, a | ||
715 | * copy of this path is returned. | ||
716 | * | ||
717 | * @param cfg configuration to inspect | ||
718 | * @param progname name of the binary | ||
719 | * @return full path to the binary, if possible, a copy of @a progname | ||
720 | * otherwise | ||
721 | */ | ||
722 | char * | ||
723 | GNUNET_OS_get_suid_binary_path (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
724 | const char *progname) | ||
725 | { | ||
726 | static char *cache; | ||
727 | char *binary = NULL; | ||
728 | char *path = NULL; | ||
729 | size_t path_len; | ||
730 | |||
731 | if (GNUNET_YES == | ||
732 | GNUNET_STRINGS_path_is_absolute (progname, GNUNET_NO, NULL, NULL)) | ||
733 | { | ||
734 | return GNUNET_strdup (progname); | ||
735 | } | ||
736 | if (NULL != cache) | ||
737 | path = cache; | ||
738 | else | ||
739 | GNUNET_CONFIGURATION_get_value_string (cfg, | ||
740 | "PATHS", | ||
741 | "SUID_BINARY_PATH", | ||
742 | &path); | ||
743 | if ((NULL == path) || (0 == strlen (path))) | ||
744 | { | ||
745 | if (NULL != path) | ||
746 | GNUNET_free (path); | ||
747 | cache = NULL; | ||
748 | return GNUNET_OS_get_libexec_binary_path (progname); | ||
749 | } | ||
750 | path_len = strlen (path); | ||
751 | GNUNET_asprintf (&binary, | ||
752 | "%s%s%s", | ||
753 | path, | ||
754 | (path[path_len - 1] == DIR_SEPARATOR) ? "" | ||
755 | : DIR_SEPARATOR_STR, | ||
756 | progname); | ||
757 | cache = path; | ||
758 | return binary; | ||
759 | } | ||
760 | |||
761 | |||
762 | enum GNUNET_GenericReturnValue | ||
763 | GNUNET_OS_check_helper_binary (const char *binary, | ||
764 | bool check_suid, | ||
765 | const char *params) | ||
766 | { | ||
767 | struct stat statbuf; | ||
768 | char *p; | ||
769 | char *pf; | ||
770 | |||
771 | if ((GNUNET_YES == | ||
772 | GNUNET_STRINGS_path_is_absolute (binary, GNUNET_NO, NULL, NULL)) || | ||
773 | (0 == strncmp (binary, "./", 2))) | ||
774 | { | ||
775 | p = GNUNET_strdup (binary); | ||
776 | } | ||
777 | else | ||
778 | { | ||
779 | p = get_path_from_PATH (binary); | ||
780 | if (NULL != p) | ||
781 | { | ||
782 | GNUNET_asprintf (&pf, "%s/%s", p, binary); | ||
783 | GNUNET_free (p); | ||
784 | p = pf; | ||
785 | } | ||
786 | } | ||
787 | |||
788 | if (NULL == p) | ||
789 | { | ||
790 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
791 | _ ("Could not find binary `%s' in PATH!\n"), | ||
792 | binary); | ||
793 | return GNUNET_SYSERR; | ||
794 | } | ||
795 | if (0 != access (p, X_OK)) | ||
796 | { | ||
797 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", p); | ||
798 | GNUNET_free (p); | ||
799 | return GNUNET_SYSERR; | ||
800 | } | ||
801 | |||
802 | if (0 == getuid ()) | ||
803 | { | ||
804 | /* as we run as root, we don't insist on SUID */ | ||
805 | GNUNET_free (p); | ||
806 | return GNUNET_YES; | ||
807 | } | ||
808 | |||
809 | if (0 != stat (p, &statbuf)) | ||
810 | { | ||
811 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", p); | ||
812 | GNUNET_free (p); | ||
813 | return GNUNET_SYSERR; | ||
814 | } | ||
815 | if (check_suid) | ||
816 | { | ||
817 | (void) params; | ||
818 | if ((0 != (statbuf.st_mode & S_ISUID)) && (0 == statbuf.st_uid)) | ||
819 | { | ||
820 | GNUNET_free (p); | ||
821 | return GNUNET_YES; | ||
822 | } | ||
823 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
824 | _ ("Binary `%s' exists, but is not SUID\n"), | ||
825 | p); | ||
826 | /* binary exists, but not SUID */ | ||
827 | } | ||
828 | GNUNET_free (p); | ||
829 | return GNUNET_NO; | ||
830 | } | ||
831 | |||
832 | |||
833 | /* end of os_installation.c */ | ||