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