generally use GNUNET_assert() instead of GNUNET_abort() to also log the error
[oweals/gnunet.git] / src / util / os_installation.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2006-2014 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 3, 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 #include <sys/stat.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <unistr.h> /* for u16_to_u8 */
31
32 #include "platform.h"
33 #include "gnunet_util_lib.h"
34 #if DARWIN
35 #include <mach-o/ldsyms.h>
36 #include <mach-o/dyld.h>
37 #elif WINDOWS
38 #include <windows.h>
39 #endif
40
41
42 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
43
44 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
45
46
47 #if LINUX
48 /**
49  * Try to determine path by reading /proc/PID/exe
50  *
51  * @return NULL on error
52  */
53 static char *
54 get_path_from_proc_maps ()
55 {
56   char fn[64];
57   char line[1024];
58   char dir[1024];
59   FILE *f;
60   char *lgu;
61
62   GNUNET_snprintf (fn, sizeof (fn), "/proc/%u/maps", getpid ());
63   if (NULL == (f = FOPEN (fn, "r")))
64     return NULL;
65   while (NULL != fgets (line, sizeof (line), f))
66   {
67     if ((1 ==
68          SSCANF (line, "%*x-%*x %*c%*c%*c%*c %*x %*2x:%*2x %*u%*[ ]%1023s", dir)) &&
69         (NULL != (lgu = strstr (dir, "libgnunetutil"))))
70     {
71       lgu[0] = '\0';
72       FCLOSE (f);
73       return GNUNET_strdup (dir);
74     }
75   }
76   FCLOSE (f);
77   return NULL;
78 }
79
80
81 /**
82  * Try to determine path by reading /proc/PID/exe
83  *
84  * @return NULL on error
85  */
86 static char *
87 get_path_from_proc_exe ()
88 {
89   char fn[64];
90   char lnk[1024];
91   ssize_t size;
92
93   GNUNET_snprintf (fn, sizeof (fn), "/proc/%u/exe", getpid ());
94   size = readlink (fn, lnk, sizeof (lnk) - 1);
95   if (size <= 0)
96   {
97     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "readlink", fn);
98     return NULL;
99   }
100   GNUNET_assert (size < sizeof (lnk));
101   lnk[size] = '\0';
102   while ((lnk[size] != '/') && (size > 0))
103     size--;
104   /* test for being in lib/gnunet/libexec/ or lib/MULTIARCH/gnunet/libexec */
105   if ( (size > strlen ("/gnunet/libexec/")) &&
106        (0 == strcmp ("/gnunet/libexec/",
107                      &lnk[size - strlen ("/gnunet/libexec/")])) )
108     size -= strlen ("gnunet/libexec/");
109   if ((size < 4) || (lnk[size - 4] != '/'))
110   {
111     /* not installed in "/bin/" -- binary path probably useless */
112     return NULL;
113   }
114   lnk[size] = '\0';
115   return GNUNET_strdup (lnk);
116 }
117 #endif
118
119
120 #if WINDOWS
121 static HINSTANCE dll_instance;
122
123
124 /**
125  * GNUNET_util_cl_init() in common_logging.c is preferred.
126  * This function is only for thread-local storage (not used in GNUnet)
127  * and hInstance saving.
128  */
129 BOOL WINAPI
130 DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
131 {
132   switch (fdwReason)
133   {
134     case DLL_PROCESS_ATTACH:
135       dll_instance = hinstDLL;
136       break;
137     case DLL_THREAD_ATTACH:
138       break;
139     case DLL_THREAD_DETACH:
140       break;
141     case DLL_PROCESS_DETACH:
142       break;
143   }
144   return TRUE;
145 }
146
147
148 /**
149  * Try to determine path with win32-specific function
150  *
151  * @return NULL on error
152  */
153 static char *
154 get_path_from_module_filename ()
155 {
156   size_t pathlen = 512;
157   DWORD real_pathlen;
158   wchar_t *idx;
159   wchar_t *modulepath = NULL;
160   char *upath;
161   uint8_t *u8_string;
162   size_t u8_string_length;
163
164   /* This braindead function won't tell us how much space it needs, so
165    * we start at 1024 and double the space up if it doesn't fit, until
166    * it fits, or we exceed the threshold.
167    */
168   do
169   {
170     pathlen = pathlen * 2;
171     modulepath = GNUNET_realloc (modulepath, pathlen * sizeof (wchar_t));
172     SetLastError (0);
173     real_pathlen = GetModuleFileNameW (dll_instance, modulepath, pathlen * sizeof (wchar_t));
174   } while (real_pathlen >= pathlen && pathlen < 16*1024);
175   if (real_pathlen >= pathlen)
176     GNUNET_assert (0);
177   /* To be safe */
178   modulepath[real_pathlen] = '\0';
179
180   idx = modulepath + real_pathlen;
181   while ((idx > modulepath) && (*idx != L'\\') && (*idx != L'/'))
182     idx--;
183   *idx = L'\0';
184
185   /* Now modulepath holds full path to the directory where libgnunetutil is.
186    * This directory should look like <GNUNET_PREFIX>/bin or <GNUNET_PREFIX>.
187    */
188   if (wcschr (modulepath, L'/') || wcschr (modulepath, L'\\'))
189   {
190     /* At least one directory component (i.e. we're not in a root directory) */
191     wchar_t *dirname = idx;
192     while ((dirname > modulepath) && (*dirname != L'\\') && (*dirname != L'/'))
193       dirname--;
194     *dirname = L'\0';
195     if (dirname > modulepath)
196     {
197       dirname++;
198       /* Now modulepath holds full path to the parent directory of the directory
199        * where libgnunetutil is.
200        * dirname holds the name of the directory where libgnunetutil is.
201        */
202       if (wcsicmp (dirname, L"bin") == 0)
203       {
204         /* pass */
205       }
206       else
207       {
208         /* Roll back our changes to modulepath */
209         dirname--;
210         *dirname = L'/';
211       }
212     }
213   }
214
215   /* modulepath is GNUNET_PREFIX */
216   u8_string = u16_to_u8 (modulepath, wcslen (modulepath), NULL, &u8_string_length);
217   if (NULL == u8_string)
218     GNUNET_assert (0);
219
220   upath = GNUNET_malloc (u8_string_length + 1);
221   memcpy (upath, u8_string, u8_string_length);
222   upath[u8_string_length] = '\0';
223
224   free (u8_string);
225   GNUNET_free (modulepath);
226
227   return upath;
228 }
229 #endif
230
231
232 #if DARWIN
233 /**
234  * Signature of the '_NSGetExecutablePath" function.
235  *
236  * @param buf where to write the path
237  * @param number of bytes available in 'buf'
238  * @return 0 on success, otherwise desired number of bytes is stored in 'bufsize'
239  */
240 typedef int (*MyNSGetExecutablePathProto) (char *buf, size_t * bufsize);
241
242
243 /**
244  * Try to obtain the path of our executable using '_NSGetExecutablePath'.
245  *
246  * @return NULL on error
247  */
248 static char *
249 get_path_from_NSGetExecutablePath ()
250 {
251   static char zero = '\0';
252   char *path;
253   size_t len;
254   MyNSGetExecutablePathProto func;
255
256   path = NULL;
257   if (NULL == (func =
258                (MyNSGetExecutablePathProto) dlsym (RTLD_DEFAULT, "_NSGetExecutablePath")))
259     return NULL;
260   path = &zero;
261   len = 0;
262   /* get the path len, including the trailing \0 */
263   (void) func (path, &len);
264   if (0 == len)
265     return NULL;
266   path = GNUNET_malloc (len);
267   if (0 != func (path, &len))
268   {
269     GNUNET_free (path);
270     return NULL;
271   }
272   len = strlen (path);
273   while ((path[len] != '/') && (len > 0))
274     len--;
275   path[len] = '\0';
276   return path;
277 }
278
279
280 /**
281  * Try to obtain the path of our executable using '_dyld_image' API.
282  *
283  * @return NULL on error
284  */
285 static char *
286 get_path_from_dyld_image ()
287 {
288   const char *path;
289   char *p;
290   char *s;
291   unsigned int i;
292   int c;
293
294   c = _dyld_image_count ();
295   for (i = 0; i < c; i++)
296   {
297     if (((const void *) _dyld_get_image_header (i)) != (const void *)&_mh_dylib_header)
298       continue;
299     path = _dyld_get_image_name (i);
300     if ( (NULL == path) || (0 == strlen (path)) )
301       continue;
302     p = GNUNET_strdup (path);
303     s = p + strlen (p);
304     while ((s > p) && ('/' != *s))
305       s--;
306     s++;
307     *s = '\0';
308     return p;
309   }
310   return NULL;
311 }
312 #endif
313
314
315 /**
316  * Return the actual path to a file found in the current
317  * PATH environment variable.
318  *
319  * @param binary the name of the file to find
320  * @return path to binary, NULL if not found
321  */
322 static char *
323 get_path_from_PATH (const char *binary)
324 {
325   char *path;
326   char *pos;
327   char *end;
328   char *buf;
329   const char *p;
330
331   if (NULL == (p = getenv ("PATH")))
332     return NULL;
333 #if WINDOWS
334   /* On W32 look in CWD first. */
335   GNUNET_asprintf (&path, ".%c%s", PATH_SEPARATOR, p);
336 #else
337   path = GNUNET_strdup (p);     /* because we write on it */
338 #endif
339   buf = GNUNET_malloc (strlen (path) + strlen (binary) + 1 + 1);
340   pos = path;
341   while (NULL != (end = strchr (pos, PATH_SEPARATOR)))
342   {
343     *end = '\0';
344     sprintf (buf, "%s/%s", pos, binary);
345     if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
346     {
347       pos = GNUNET_strdup (pos);
348       GNUNET_free (buf);
349       GNUNET_free (path);
350       return pos;
351     }
352     pos = end + 1;
353   }
354   sprintf (buf, "%s/%s", pos, binary);
355   if (GNUNET_YES == GNUNET_DISK_file_test (buf))
356   {
357     pos = GNUNET_strdup (pos);
358     GNUNET_free (buf);
359     GNUNET_free (path);
360     return pos;
361   }
362   GNUNET_free (buf);
363   GNUNET_free (path);
364   return NULL;
365 }
366
367
368 /**
369  * Try to obtain the installation path using the "GNUNET_PREFIX" environment
370  * variable.
371  *
372  * @return NULL on error (environment variable not set)
373  */
374 static char *
375 get_path_from_GNUNET_PREFIX ()
376 {
377   const char *p;
378
379   if (NULL != (p = getenv ("GNUNET_PREFIX")))
380     return GNUNET_strdup (p);
381   return NULL;
382 }
383
384
385 /**
386  * @brief get the path to GNUnet bin/ or lib/, prefering 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 ()
393 {
394   char *ret;
395
396   if (NULL != (ret = get_path_from_GNUNET_PREFIX ()))
397     return ret;
398 #if 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 != (ret = get_path_from_PATH ("gnunet-arm")))
403     return ret;
404   if (NULL != (ret = get_path_from_proc_exe ()))
405     return ret;
406 #endif
407 #if WINDOWS
408   if (NULL != (ret = get_path_from_module_filename ()))
409     return ret;
410 #endif
411 #if DARWIN
412   if (NULL != (ret = get_path_from_dyld_image ()))
413     return ret;
414   if (NULL != (ret = get_path_from_NSGetExecutablePath ()))
415     return ret;
416 #endif
417   if (NULL != (ret = get_path_from_PATH ("gnunet-arm")))
418     return ret;
419   /* other attempts here */
420   LOG (GNUNET_ERROR_TYPE_ERROR,
421        _("Could not determine installation path for %s.  Set `%s' environment variable.\n"),
422        "GNUnet", "GNUNET_PREFIX");
423   return NULL;
424 }
425
426
427 /**
428  * @brief get the path to current app's bin/
429  * @author Milan
430  *
431  * @return a pointer to the executable path, or NULL on error
432  */
433 static char *
434 os_get_exec_path ()
435 {
436   char *ret = NULL;
437
438 #if LINUX
439   if (NULL != (ret = get_path_from_proc_exe ()))
440     return ret;
441 #endif
442 #if WINDOWS
443   if (NULL != (ret = get_path_from_module_filename ()))
444     return ret;
445 #endif
446 #if DARWIN
447   if (NULL != (ret = get_path_from_NSGetExecutablePath ()))
448     return ret;
449 #endif
450   /* other attempts here */
451   return ret;
452 }
453
454
455 /**
456  * @brief get the path to a specific GNUnet installation directory or,
457  * with #GNUNET_OS_IPK_SELF_PREFIX, the current running apps installation directory
458  * @author Milan
459  * @return a pointer to the dir path (to be freed by the caller)
460  */
461 char *
462 GNUNET_OS_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind)
463 {
464   size_t n;
465   const char *dirname;
466   char *execpath = NULL;
467   char *tmp;
468   char *multiarch;
469   char *libdir;
470   int isbasedir;
471
472   /* if wanted, try to get the current app's bin/ */
473   if (dirkind == GNUNET_OS_IPK_SELF_PREFIX)
474     execpath = os_get_exec_path ();
475
476   /* try to get GNUnet's bin/ or lib/, or if previous was unsuccessful some
477    * guess for the current app */
478   if (NULL == execpath)
479     execpath = os_get_gnunet_path ();
480
481   if (NULL == execpath)
482     return NULL;
483
484   n = strlen (execpath);
485   if (0 == n)
486   {
487     /* should never happen, but better safe than sorry */
488     GNUNET_free (execpath);
489     return NULL;
490   }
491   /* remove filename itself */
492   while ((n > 1) && (DIR_SEPARATOR == execpath[n - 1]))
493     execpath[--n] = '\0';
494
495   isbasedir = 1;
496   if ((n > 6) &&
497       ((0 == strcasecmp (&execpath[n - 6], "/lib32")) ||
498        (0 == strcasecmp (&execpath[n - 6], "/lib64"))))
499   {
500     if ( (GNUNET_OS_IPK_LIBDIR != dirkind) &&
501          (GNUNET_OS_IPK_LIBEXECDIR != dirkind) )
502     {
503       /* strip '/lib32' or '/lib64' */
504       execpath[n - 6] = '\0';
505       n -= 6;
506     }
507     else
508       isbasedir = 0;
509   }
510   else if ((n > 4) &&
511            ((0 == strcasecmp (&execpath[n - 4], "/bin")) ||
512             (0 == strcasecmp (&execpath[n - 4], "/lib"))))
513   {
514     /* strip '/bin' or '/lib' */
515     execpath[n - 4] = '\0';
516     n -= 4;
517   }
518   multiarch = NULL;
519   if (NULL != (libdir = strstr (execpath, "/lib/")))
520   {
521     /* test for multi-arch path of the form "PREFIX/lib/MULTIARCH/";
522        here we need to re-add 'multiarch' to lib and libexec paths later! */
523     multiarch = &libdir[5];
524     if (NULL == strchr (multiarch, '/'))
525       libdir[0] = '\0'; /* Debian multiarch format, cut of from 'execpath' but preserve in multicarch */
526     else
527       multiarch = NULL; /* maybe not, multiarch still has a '/', which is not OK */
528   }
529   /* in case this was a directory named foo-bin, remove "foo-" */
530   while ((n > 1) && (execpath[n - 1] == DIR_SEPARATOR))
531     execpath[--n] = '\0';
532   switch (dirkind)
533   {
534   case GNUNET_OS_IPK_PREFIX:
535   case GNUNET_OS_IPK_SELF_PREFIX:
536     dirname = DIR_SEPARATOR_STR;
537     break;
538   case GNUNET_OS_IPK_BINDIR:
539     dirname = DIR_SEPARATOR_STR "bin" DIR_SEPARATOR_STR;
540     break;
541   case GNUNET_OS_IPK_LIBDIR:
542     if (isbasedir)
543     {
544       GNUNET_asprintf (&tmp,
545                        "%s%s%s%s%s",
546                        execpath,
547                        DIR_SEPARATOR_STR "lib",
548                        (NULL != multiarch) ? DIR_SEPARATOR_STR : "",
549                        (NULL != multiarch) ? multiarch : "",
550                        DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR);
551       if (GNUNET_YES ==
552           GNUNET_DISK_directory_test (tmp, GNUNET_YES))
553       {
554         GNUNET_free (execpath);
555         return tmp;
556       }
557       GNUNET_free (tmp);
558       tmp = NULL;
559       if (4 == sizeof (void *))
560       {
561         dirname =
562           DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
563         GNUNET_asprintf (&tmp,
564                          "%s%s",
565                          execpath,
566                          dirname);
567       }
568       if (8 == sizeof (void *))
569       {
570         dirname =
571           DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
572         GNUNET_asprintf (&tmp,
573                          "%s%s",
574                          execpath,
575                          dirname);
576       }
577
578       if ( (NULL != tmp) &&
579            (GNUNET_YES ==
580             GNUNET_DISK_directory_test (tmp, GNUNET_YES)) )
581       {
582         GNUNET_free (execpath);
583         return tmp;
584       }
585       GNUNET_free (tmp);
586     }
587     dirname = DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
588     break;
589   case GNUNET_OS_IPK_DATADIR:
590     dirname =
591         DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
592     break;
593   case GNUNET_OS_IPK_LOCALEDIR:
594     dirname =
595         DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "locale" DIR_SEPARATOR_STR;
596     break;
597   case GNUNET_OS_IPK_ICONDIR:
598     dirname =
599         DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "icons" DIR_SEPARATOR_STR;
600     break;
601   case GNUNET_OS_IPK_DOCDIR:
602     dirname =
603         DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "doc" DIR_SEPARATOR_STR \
604         "gnunet" DIR_SEPARATOR_STR;
605     break;
606   case GNUNET_OS_IPK_LIBEXECDIR:
607     if (isbasedir)
608     {
609       dirname =
610         DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR "libexec" DIR_SEPARATOR_STR;
611       GNUNET_asprintf (&tmp,
612                        "%s%s%s%s",
613                        execpath,
614                        DIR_SEPARATOR_STR "lib" DIR_SEPARATOR_STR,
615                        (NULL != multiarch) ? multiarch : "",
616                        dirname);
617       if (GNUNET_YES ==
618           GNUNET_DISK_directory_test (tmp, GNUNET_YES))
619       {
620         GNUNET_free (execpath);
621         return tmp;
622       }
623       GNUNET_free (tmp);
624       tmp = NULL;
625       if (4 == sizeof (void *))
626       {
627         dirname =
628           DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR \
629           "libexec" DIR_SEPARATOR_STR;
630         GNUNET_asprintf (&tmp,
631                          "%s%s",
632                          execpath,
633                          dirname);
634       }
635       if (8 == sizeof (void *))
636       {
637         dirname =
638           DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR \
639           "libexec" DIR_SEPARATOR_STR;
640         GNUNET_asprintf (&tmp,
641                          "%s%s",
642                          execpath,
643                          dirname);
644       }
645       if ( (NULL != tmp) &&
646            (GNUNET_YES ==
647             GNUNET_DISK_directory_test (tmp, GNUNET_YES)) )
648       {
649         GNUNET_free (execpath);
650         return tmp;
651       }
652
653       GNUNET_free (tmp);
654     }
655     dirname =
656       DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR \
657       "libexec" DIR_SEPARATOR_STR;
658     break;
659   default:
660     GNUNET_free (execpath);
661     return NULL;
662   }
663   GNUNET_asprintf (&tmp,
664                    "%s%s",
665                    execpath,
666                    dirname);
667   GNUNET_free (execpath);
668   return tmp;
669 }
670
671
672 /**
673  * Given the name of a gnunet-helper, gnunet-service or gnunet-daemon
674  * binary, try to prefix it with the libexec/-directory to get the
675  * full path.
676  *
677  * @param progname name of the binary
678  * @return full path to the binary, if possible, otherwise copy of 'progname'
679  */
680 char *
681 GNUNET_OS_get_libexec_binary_path (const char *progname)
682 {
683   static char *cache;
684   char *libexecdir;
685   char *binary;
686
687   if ( (DIR_SEPARATOR == progname[0]) ||
688        (GNUNET_YES == GNUNET_STRINGS_path_is_absolute (progname, GNUNET_NO, NULL, NULL)) )
689     return GNUNET_strdup (progname);
690   if (NULL != cache)
691     libexecdir = cache;
692   else
693     libexecdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBEXECDIR);
694   if (NULL == libexecdir)
695     return GNUNET_strdup (progname);
696   GNUNET_asprintf (&binary,
697                    "%s%s",
698                    libexecdir,
699                    progname);
700   cache = libexecdir;
701   return binary;
702 }
703
704
705 /**
706  * Check whether an executable exists and possibly
707  * if the suid bit is set on the file.
708  * Attempts to find the file using the current
709  * PATH environment variable as a search path.
710  *
711  * @param binary the name of the file to check.
712  *        W32: must not have an .exe suffix.
713  * @param check_suid input true if the binary should be checked for SUID (*nix)
714  *        W32: checks if the program has sufficient privileges by executing this
715  *             binary with the -d flag. -d omits a programs main loop and only
716  *             executes all privileged operations in an binary.
717  * @param params parameters used for w32 privilege checking (can be NULL for != w32 )
718  * @return #GNUNET_YES if the file is SUID (*nix) or can be executed with current privileges (W32),
719  *         #GNUNET_NO if not SUID (but binary exists),
720  *         #GNUNET_SYSERR on error (no such binary or not executable)
721  */
722 int
723 GNUNET_OS_check_helper_binary (const char *binary, int check_suid, const char *params)
724 {
725   struct stat statbuf;
726   char *p;
727   char *pf;
728 #ifdef MINGW
729   char *binaryexe;
730
731   GNUNET_asprintf (&binaryexe, "%s.exe", binary);
732   if ( (GNUNET_YES == GNUNET_STRINGS_path_is_absolute (binaryexe, GNUNET_NO,
733                                                        NULL, NULL)) ||
734        (0 == strncmp (binary, "./", 2)) )
735     p = GNUNET_strdup (binaryexe);
736   else
737   {
738     p = get_path_from_PATH (binaryexe);
739     if (NULL != p)
740     {
741       GNUNET_asprintf (&pf, "%s/%s", p, binaryexe);
742       GNUNET_free (p);
743       p = pf;
744     }
745   }
746   GNUNET_free (binaryexe);
747 #else
748   if ( (GNUNET_YES == GNUNET_STRINGS_path_is_absolute (binary, GNUNET_NO,
749                                                        NULL, NULL)) ||
750        (0 == strncmp (binary, "./", 2)) )
751     p = GNUNET_strdup (binary);
752   else
753   {
754     p = get_path_from_PATH (binary);
755     if (NULL != p)
756     {
757       GNUNET_asprintf (&pf, "%s/%s", p, binary);
758       GNUNET_free (p);
759       p = pf;
760     }
761   }
762 #endif
763   if (NULL == p)
764   {
765     LOG (GNUNET_ERROR_TYPE_INFO,
766          _("Could not find binary `%s' in PATH!\n"),
767          binary);
768     return GNUNET_SYSERR;
769   }
770   if (0 != ACCESS (p, X_OK))
771   {
772     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", p);
773     GNUNET_free (p);
774     return GNUNET_SYSERR;
775   }
776 #ifndef MINGW
777   if (0 == getuid ())
778   {
779     /* as we run as root, we don't insist on SUID */
780     GNUNET_free (p);
781     return GNUNET_OK;
782   }
783 #endif
784   if (0 != STAT (p, &statbuf))
785   {
786     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", p);
787     GNUNET_free (p);
788     return GNUNET_SYSERR;
789   }
790   if (check_suid){
791 #ifndef MINGW
792     if ((0 != (statbuf.st_mode & S_ISUID)) && (0 == statbuf.st_uid))
793     {
794       GNUNET_free (p);
795       return GNUNET_YES;
796     }
797     /* binary exists, but not SUID */
798 #else
799     STARTUPINFO start;
800     char parameters[512];
801     PROCESS_INFORMATION proc;
802     DWORD exit_value;
803
804     GNUNET_snprintf (parameters,
805                      sizeof (parameters),
806                      "-d %s", params);
807     memset (&start, 0, sizeof (start));
808     start.cb = sizeof (start);
809     memset (&proc, 0, sizeof (proc));
810
811
812     // Start the child process.
813     if ( ! (CreateProcess( p,   // current windows (2k3 and up can handle / instead of \ in paths))
814         parameters,           // execute dryrun/priviliege checking mode
815         NULL,           // Process handle not inheritable
816         NULL,           // Thread handle not inheritable
817         FALSE,          // Set handle inheritance to FALSE
818         CREATE_DEFAULT_ERROR_MODE, // No creation flags
819         NULL,           // Use parent's environment block
820         NULL,           // Use parent's starting directory
821         &start,            // Pointer to STARTUPINFO structure
822         &proc )           // Pointer to PROCESS_INFORMATION structure
823                                ))
824       {
825         LOG (GNUNET_ERROR_TYPE_ERROR,
826              _("CreateProcess failed for binary %s (%d).\n"),
827              p, GetLastError());
828         return GNUNET_SYSERR;
829     }
830
831     // Wait until child process exits.
832     WaitForSingleObject( proc.hProcess, INFINITE );
833
834     if ( ! GetExitCodeProcess (proc.hProcess, &exit_value)){
835         LOG (GNUNET_ERROR_TYPE_ERROR,
836              _("GetExitCodeProcess failed for binary %s (%d).\n"),
837              p, GetLastError() );
838         return GNUNET_SYSERR;
839       }
840     // Close process and thread handles.
841     CloseHandle( proc.hProcess );
842     CloseHandle( proc.hThread );
843
844     if (!exit_value)
845       return GNUNET_YES;
846 #endif
847     }
848   GNUNET_free (p);
849   return GNUNET_NO;
850 }
851
852
853 /* end of os_installation.c */