Add a third default.
[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
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 %*2u:%*2u %*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/ */
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_abort ();
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_abort ();
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   int isbasedir;
469
470   /* if wanted, try to get the current app's bin/ */
471   if (dirkind == GNUNET_OS_IPK_SELF_PREFIX)
472     execpath = os_get_exec_path ();
473
474   /* try to get GNUnet's bin/ or lib/, or if previous was unsuccessful some
475    * guess for the current app */
476   if (NULL == execpath)
477     execpath = os_get_gnunet_path ();
478
479   if (NULL == execpath)
480     return NULL;
481
482   n = strlen (execpath);
483   if (0 == n)
484   {
485     /* should never happen, but better safe than sorry */
486     GNUNET_free (execpath);
487     return NULL;
488   }
489   /* remove filename itself */
490   while ((n > 1) && (DIR_SEPARATOR == execpath[n - 1]))
491     execpath[--n] = '\0';
492
493   isbasedir = 1;
494   if ((n > 6) &&
495       ((0 == strcasecmp (&execpath[n - 6], "/lib32")) ||
496        (0 == strcasecmp (&execpath[n - 6], "/lib64"))))
497   {
498     if ( (GNUNET_OS_IPK_LIBDIR != dirkind) &&
499          (GNUNET_OS_IPK_LIBEXECDIR != dirkind) )
500     {
501       /* strip '/lib32' or '/lib64' */
502       execpath[n - 6] = '\0';
503       n -= 6;
504     }
505     else
506       isbasedir = 0;
507   }
508   else if ((n > 4) &&
509            ((0 == strcasecmp (&execpath[n - 4], "/bin")) ||
510             (0 == strcasecmp (&execpath[n - 4], "/lib"))))
511   {
512     /* strip '/bin' or '/lib' */
513     execpath[n - 4] = '\0';
514     n -= 4;
515   }
516   /* in case this was a directory named foo-bin, remove "foo-" */
517   while ((n > 1) && (execpath[n - 1] == DIR_SEPARATOR))
518     execpath[--n] = '\0';
519   switch (dirkind)
520   {
521   case GNUNET_OS_IPK_PREFIX:
522   case GNUNET_OS_IPK_SELF_PREFIX:
523     dirname = DIR_SEPARATOR_STR;
524     break;
525   case GNUNET_OS_IPK_BINDIR:
526     dirname = DIR_SEPARATOR_STR "bin" DIR_SEPARATOR_STR;
527     break;
528   case GNUNET_OS_IPK_LIBDIR:
529     if (isbasedir)
530     {
531       dirname =
532           DIR_SEPARATOR_STR "lib" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
533       tmp = GNUNET_malloc (strlen (execpath) + strlen (dirname) + 1);
534       sprintf (tmp, "%s%s", execpath, dirname);
535       if ( (GNUNET_YES !=
536             GNUNET_DISK_directory_test (tmp, GNUNET_YES)) &&
537            (4 == sizeof (void *)) )
538       {
539         GNUNET_free (tmp);
540         dirname =
541           DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
542         tmp = GNUNET_malloc (strlen (execpath) + strlen (dirname) + 1);
543         sprintf (tmp, "%s%s", execpath, dirname);
544       }
545       if ( (GNUNET_YES !=
546             GNUNET_DISK_directory_test (tmp, GNUNET_YES)) &&
547            (8 == sizeof (void *)) )
548       {
549         dirname =
550           DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
551       }
552       GNUNET_free (tmp);
553     }
554     else
555       dirname = DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
556     break;
557   case GNUNET_OS_IPK_DATADIR:
558     dirname =
559         DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
560     break;
561   case GNUNET_OS_IPK_LOCALEDIR:
562     dirname =
563         DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "locale" DIR_SEPARATOR_STR;
564     break;
565   case GNUNET_OS_IPK_ICONDIR:
566     dirname =
567         DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "icons" DIR_SEPARATOR_STR;
568     break;
569   case GNUNET_OS_IPK_DOCDIR:
570     dirname =
571         DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "doc" DIR_SEPARATOR_STR \
572         "gnunet" DIR_SEPARATOR_STR;
573     break;
574   case GNUNET_OS_IPK_LIBEXECDIR:
575     if (isbasedir)
576     {
577       dirname =
578         DIR_SEPARATOR_STR "lib" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR \
579         "libexec" DIR_SEPARATOR_STR;
580       tmp = GNUNET_malloc (strlen (execpath) + strlen (dirname) + 1);
581       sprintf (tmp, "%s%s", execpath, dirname);
582       if ( (GNUNET_YES !=
583             GNUNET_DISK_directory_test (tmp, GNUNET_YES)) &&
584            (4 == sizeof (void *)) )
585       {
586         GNUNET_free (tmp);
587         dirname =
588           DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR \
589           "libexec" DIR_SEPARATOR_STR;
590         tmp = GNUNET_malloc (strlen (execpath) + strlen (dirname) + 1);
591         sprintf (tmp, "%s%s", execpath, dirname);
592       }
593       if ( (GNUNET_YES !=
594             GNUNET_DISK_directory_test (tmp, GNUNET_YES)) &&
595            (8 == sizeof (void *)) )
596       {
597         dirname =
598           DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR \
599           "libexec" DIR_SEPARATOR_STR;
600       }
601       GNUNET_free (tmp);
602     }
603     else
604       dirname =
605         DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR \
606         "libexec" DIR_SEPARATOR_STR;
607     break;
608   default:
609     GNUNET_free (execpath);
610     return NULL;
611   }
612   tmp = GNUNET_malloc (strlen (execpath) + strlen (dirname) + 1);
613   sprintf (tmp, "%s%s", execpath, dirname);
614   GNUNET_free (execpath);
615   return tmp;
616 }
617
618
619 /**
620  * Given the name of a gnunet-helper, gnunet-service or gnunet-daemon
621  * binary, try to prefix it with the libexec/-directory to get the
622  * full path.
623  *
624  * @param progname name of the binary
625  * @return full path to the binary, if possible, otherwise copy of 'progname'
626  */
627 char *
628 GNUNET_OS_get_libexec_binary_path (const char *progname)
629 {
630   char *libexecdir;
631   char *binary;
632
633   if (DIR_SEPARATOR == progname[0])
634     return GNUNET_strdup (progname);
635   if (GNUNET_YES == GNUNET_STRINGS_path_is_absolute (progname, GNUNET_NO, NULL, NULL))
636     return GNUNET_strdup (progname);
637   libexecdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBEXECDIR);
638   if (NULL == libexecdir)
639     return GNUNET_strdup (progname);
640   GNUNET_asprintf (&binary,
641                    "%s%s",
642                    libexecdir,
643                    progname);
644   GNUNET_free (libexecdir);
645   return binary;
646 }
647
648
649 /**
650  * Check whether an executable exists and possibly
651  * if the suid bit is set on the file.
652  * Attempts to find the file using the current
653  * PATH environment variable as a search path.
654  *
655  * @param binary the name of the file to check.
656  *        W32: must not have an .exe suffix.
657  * @param check_suid input true if the binary should be checked for SUID (*nix)
658  *        W32: checks if the program has sufficient privileges by executing this
659  *             binary with the -d flag. -d omits a programs main loop and only
660  *             executes all privileged operations in an binary.
661  * @param params parameters used for w32 privilege checking (can be NULL for != w32 )
662  * @return #GNUNET_YES if the file is SUID (*nix) or can be executed with current privileges (W32),
663  *         #GNUNET_NO if not SUID (but binary exists),
664  *         #GNUNET_SYSERR on error (no such binary or not executable)
665  */
666 int
667 GNUNET_OS_check_helper_binary (const char *binary, int check_suid, const char *params)
668 {
669   struct stat statbuf;
670   char *p;
671   char *pf;
672 #ifdef MINGW
673   char *binaryexe;
674
675   GNUNET_asprintf (&binaryexe, "%s.exe", binary);
676   if ( (GNUNET_YES == GNUNET_STRINGS_path_is_absolute (binaryexe, GNUNET_NO,
677                                                        NULL, NULL)) ||
678        (0 == strncmp (binary, "./", 2)) )
679     p = GNUNET_strdup (binaryexe);
680   else
681   {
682     p = get_path_from_PATH (binaryexe);
683     if (NULL != p)
684     {
685       GNUNET_asprintf (&pf, "%s/%s", p, binaryexe);
686       GNUNET_free (p);
687       p = pf;
688     }
689   }
690   GNUNET_free (binaryexe);
691 #else
692   if ( (GNUNET_YES == GNUNET_STRINGS_path_is_absolute (binary, GNUNET_NO,
693                                                        NULL, NULL)) ||
694        (0 == strncmp (binary, "./", 2)) )
695     p = GNUNET_strdup (binary);
696   else
697   {
698     p = get_path_from_PATH (binary);
699     if (NULL != p)
700     {
701       GNUNET_asprintf (&pf, "%s/%s", p, binary);
702       GNUNET_free (p);
703       p = pf;
704     }
705   }
706 #endif
707   if (NULL == p)
708   {
709     LOG (GNUNET_ERROR_TYPE_INFO,
710          _("Could not find binary `%s' in PATH!\n"),
711          binary);
712     return GNUNET_SYSERR;
713   }
714   if (0 != ACCESS (p, X_OK))
715   {
716     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", p);
717     GNUNET_free (p);
718     return GNUNET_SYSERR;
719   }
720 #ifndef MINGW
721   if (0 == getuid ())
722   {
723     /* as we run as root, we don't insist on SUID */
724     GNUNET_free (p);
725     return GNUNET_OK;
726   }
727 #endif
728   if (0 != STAT (p, &statbuf))
729   {
730     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", p);
731     GNUNET_free (p);
732     return GNUNET_SYSERR;
733   }
734   if (check_suid){
735 #ifndef MINGW
736     if ((0 != (statbuf.st_mode & S_ISUID)) && (0 == statbuf.st_uid))
737     {
738       GNUNET_free (p);
739       return GNUNET_YES;
740     }
741     /* binary exists, but not SUID */
742 #else
743     STARTUPINFO start;
744     char parameters[512];
745     PROCESS_INFORMATION proc;
746     DWORD exit_value;
747
748     GNUNET_snprintf (parameters,
749                      sizeof (parameters),
750                      "-d %s", params);
751     memset (&start, 0, sizeof (start));
752     start.cb = sizeof (start);
753     memset (&proc, 0, sizeof (proc));
754
755
756     // Start the child process.
757     if ( ! (CreateProcess( p,   // current windows (2k3 and up can handle / instead of \ in paths))
758         parameters,           // execute dryrun/priviliege checking mode
759         NULL,           // Process handle not inheritable
760         NULL,           // Thread handle not inheritable
761         FALSE,          // Set handle inheritance to FALSE
762         CREATE_DEFAULT_ERROR_MODE, // No creation flags
763         NULL,           // Use parent's environment block
764         NULL,           // Use parent's starting directory
765         &start,            // Pointer to STARTUPINFO structure
766         &proc )           // Pointer to PROCESS_INFORMATION structure
767                                ))
768       {
769         LOG (GNUNET_ERROR_TYPE_ERROR,
770              _("CreateProcess failed for binary %s (%d).\n"),
771              p, GetLastError());
772         return GNUNET_SYSERR;
773     }
774
775     // Wait until child process exits.
776     WaitForSingleObject( proc.hProcess, INFINITE );
777
778     if ( ! GetExitCodeProcess (proc.hProcess, &exit_value)){
779         LOG (GNUNET_ERROR_TYPE_ERROR,
780              _("GetExitCodeProcess failed for binary %s (%d).\n"),
781              p, GetLastError() );
782         return GNUNET_SYSERR;
783       }
784     // Close process and thread handles.
785     CloseHandle( proc.hProcess );
786     CloseHandle( proc.hThread );
787
788     if (!exit_value)
789       return GNUNET_YES;
790 #endif
791     }
792   GNUNET_free (p);
793   return GNUNET_NO;
794 }
795
796
797 /* end of os_installation.c */