- fix
[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 2, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file src/util/os_installation.c
23  * @brief get paths used by the program
24  * @author Milan
25  */
26 #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_common.h"
34 #include "gnunet_configuration_lib.h"
35 #include "gnunet_disk_lib.h"
36 #include "gnunet_os_lib.h"
37 #include "gnunet_strings_lib.h"
38 #if DARWIN
39 #include <mach-o/ldsyms.h>
40 #include <mach-o/dyld.h>
41 #endif
42
43 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
44
45 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
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 #if WINDOWS
120
121 static HINSTANCE dll_instance;
122
123
124 /* GNUNET_util_cl_init() in common_logging.c is preferred.
125  * This function is only for thread-local storage (not used in GNUnet)
126  * and hInstance saving.
127  */
128 BOOL WINAPI
129 DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
130 {
131   switch (fdwReason)
132   {
133     case DLL_PROCESS_ATTACH:
134       dll_instance = hinstDLL;
135       break;
136     case DLL_THREAD_ATTACH:
137       break;
138     case DLL_THREAD_DETACH:
139       break;
140     case DLL_PROCESS_DETACH:
141       break;
142   }
143   return TRUE;
144 }
145
146
147 /**
148  * Try to determine path with win32-specific function
149  *
150  * @return NULL on error
151  */
152 static char *
153 get_path_from_module_filename ()
154 {
155   size_t pathlen = 512;
156   DWORD real_pathlen;
157   wchar_t *idx;
158   wchar_t *modulepath = NULL;
159   char *upath;
160   uint8_t *u8_string;
161   size_t u8_string_length;
162
163   /* This braindead function won't tell us how much space it needs, so
164    * we start at 1024 and double the space up if it doesn't fit, until
165    * it fits, or we exceed the threshold.
166    */
167   do
168   {
169     pathlen = pathlen * 2;
170     modulepath = GNUNET_realloc (modulepath, pathlen * sizeof (wchar_t));
171     SetLastError (0);
172     real_pathlen = GetModuleFileNameW (dll_instance, modulepath, pathlen * sizeof (wchar_t));
173   } while (real_pathlen >= pathlen && pathlen < 16*1024);
174   if (real_pathlen >= pathlen)
175     GNUNET_abort ();
176   /* To be safe */
177   modulepath[real_pathlen] = '\0';
178
179   idx = modulepath + real_pathlen;
180   while ((idx > modulepath) && (*idx != L'\\') && (*idx != L'/'))
181     idx--;
182   *idx = L'\0';
183
184   /* Now modulepath holds full path to the directory where libgnunetutil is.
185    * This directory should look like <GNUNET_PREFIX>/bin or <GNUNET_PREFIX>.
186    */
187   if (wcschr (modulepath, L'/') || wcschr (modulepath, L'\\'))
188   {
189     /* At least one directory component (i.e. we're not in a root directory) */
190     wchar_t *dirname = idx;
191     while ((dirname > modulepath) && (*dirname != L'\\') && (*dirname != L'/'))
192       dirname--;
193     *dirname = L'\0';
194     if (dirname > modulepath)
195     {
196       dirname++;
197       /* Now modulepath holds full path to the parent directory of the directory
198        * where libgnunetutil is.
199        * dirname holds the name of the directory where libgnunetutil is.
200        */
201       if (wcsicmp (dirname, L"bin") == 0)
202       {
203         /* pass */
204       }
205       else
206       {
207         /* Roll back our changes to modulepath */
208         dirname--;
209         *dirname = L'/';
210       }
211     }
212   }
213
214   /* modulepath is GNUNET_PREFIX */
215   u8_string = u16_to_u8 (modulepath, wcslen (modulepath), NULL, &u8_string_length);
216   if (NULL == u8_string)
217     GNUNET_abort ();
218
219   upath = GNUNET_malloc (u8_string_length + 1);
220   memcpy (upath, u8_string, u8_string_length);
221   upath[u8_string_length] = '\0';
222
223   free (u8_string);
224   GNUNET_free (modulepath);
225
226   return upath;
227 }
228 #endif
229
230 #if DARWIN
231 /**
232  * Signature of the '_NSGetExecutablePath" function.
233  *
234  * @param buf where to write the path
235  * @param number of bytes available in 'buf'
236  * @return 0 on success, otherwise desired number of bytes is stored in 'bufsize'
237  */
238 typedef int (*MyNSGetExecutablePathProto) (char *buf, size_t * bufsize);
239
240
241 /**
242  * Try to obtain the path of our executable using '_NSGetExecutablePath'.
243  *
244  * @return NULL on error
245  */
246 static char *
247 get_path_from_NSGetExecutablePath ()
248 {
249   static char zero = '\0';
250   char *path;
251   size_t len;
252   MyNSGetExecutablePathProto func;
253
254   path = NULL;
255   if (NULL == (func =
256                (MyNSGetExecutablePathProto) dlsym (RTLD_DEFAULT, "_NSGetExecutablePath")))
257     return NULL;
258   path = &zero;
259   len = 0;
260   /* get the path len, including the trailing \0 */
261   (void) func (path, &len);
262   if (0 == len)
263     return NULL;
264   path = GNUNET_malloc (len);
265   if (0 != func (path, &len))
266   {
267     GNUNET_free (path);
268     return NULL;
269   }
270   len = strlen (path);
271   while ((path[len] != '/') && (len > 0))
272     len--;
273   path[len] = '\0';
274   return path;
275 }
276
277
278 /**
279  * Try to obtain the path of our executable using '_dyld_image' API.
280  *
281  * @return NULL on error
282  */
283 static char *
284 get_path_from_dyld_image ()
285 {
286   const char *path;
287   char *p;
288   char *s;
289   unsigned int i;
290   int c;
291
292   c = _dyld_image_count ();
293   for (i = 0; i < c; i++)
294   {
295     if (_dyld_get_image_header (i) != &_mh_dylib_header)
296       continue;
297     path = _dyld_get_image_name (i);
298     if ( (NULL == path) || (0 == strlen (path)) )
299       continue;
300     p = GNUNET_strdup (path);
301     s = p + strlen (p);
302     while ((s > p) && ('/' != *s))
303       s--;
304     s++;
305     *s = '\0';
306     return p;
307   }
308   return NULL;
309 }
310 #endif
311
312
313 /**
314  * Return the actual path to a file found in the current
315  * PATH environment variable.
316  *
317  * @param binary the name of the file to find
318  * @return path to binary, NULL if not found
319  */
320 static char *
321 get_path_from_PATH (const char *binary)
322 {
323   char *path;
324   char *pos;
325   char *end;
326   char *buf;
327   const char *p;
328
329   if (NULL == (p = getenv ("PATH")))
330     return NULL;
331 #if WINDOWS
332   /* On W32 look in CWD first. */
333   GNUNET_asprintf (&path, ".%c%s", PATH_SEPARATOR, p);
334 #else
335   path = GNUNET_strdup (p);     /* because we write on it */
336 #endif
337   buf = GNUNET_malloc (strlen (path) + strlen (binary) + 1 + 1);
338   pos = path;
339   while (NULL != (end = strchr (pos, PATH_SEPARATOR)))
340   {
341     *end = '\0';
342     sprintf (buf, "%s/%s", pos, binary);
343     if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
344     {
345       pos = GNUNET_strdup (pos);
346       GNUNET_free (buf);
347       GNUNET_free (path);
348       return pos;
349     }
350     pos = end + 1;
351   }
352   sprintf (buf, "%s/%s", pos, binary);
353   if (GNUNET_YES == GNUNET_DISK_file_test (buf))
354   {
355     pos = GNUNET_strdup (pos);
356     GNUNET_free (buf);
357     GNUNET_free (path);
358     return pos;
359   }
360   GNUNET_free (buf);
361   GNUNET_free (path);
362   return NULL;
363 }
364
365
366 /**
367  * Try to obtain the installation path using the "GNUNET_PREFIX" environment
368  * variable.
369  *
370  * @return NULL on error (environment variable not set)
371  */
372 static char *
373 get_path_from_GNUNET_PREFIX ()
374 {
375   const char *p;
376
377   if (NULL != (p = getenv ("GNUNET_PREFIX")))
378     return GNUNET_strdup (p);
379   return NULL;
380 }
381
382
383 /**
384  * @brief get the path to GNUnet bin/ or lib/, prefering the lib/ path
385  * @author Milan
386  *
387  * @return a pointer to the executable path, or NULL on error
388  */
389 static char *
390 os_get_gnunet_path ()
391 {
392   char *ret;
393
394   if (NULL != (ret = get_path_from_GNUNET_PREFIX ()))
395     return ret;
396 #if LINUX
397   if (NULL != (ret = get_path_from_proc_maps ()))
398     return ret;
399   /* try path *first*, before /proc/exe, as /proc/exe can be wrong */
400   if (NULL != (ret = get_path_from_PATH ("gnunet-arm")))
401     return ret;
402   if (NULL != (ret = get_path_from_proc_exe ()))
403     return ret;
404 #endif
405 #if WINDOWS
406   if (NULL != (ret = get_path_from_module_filename ()))
407     return ret;
408 #endif
409 #if DARWIN
410   if (NULL != (ret = get_path_from_dyld_image ()))
411     return ret;
412   if (NULL != (ret = get_path_from_NSGetExecutablePath ()))
413     return ret;
414 #endif
415   if (NULL != (ret = get_path_from_PATH ("gnunet-arm")))
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        "GNUnet", "GNUNET_PREFIX");
422   return NULL;
423 }
424
425
426 /**
427  * @brief get the path to current app's bin/
428  * @author Milan
429  *
430  * @return a pointer to the executable path, or NULL on error
431  */
432 static char *
433 os_get_exec_path ()
434 {
435   char *ret = NULL;
436
437 #if LINUX
438   if (NULL != (ret = get_path_from_proc_exe ()))
439     return ret;
440 #endif
441 #if WINDOWS
442   if (NULL != (ret = get_path_from_module_filename ()))
443     return ret;
444 #endif
445 #if DARWIN
446   if (NULL != (ret = get_path_from_NSGetExecutablePath ()))
447     return ret;
448 #endif
449   /* other attempts here */
450   return ret;
451 }
452
453
454 /**
455  * @brief get the path to a specific GNUnet installation directory or,
456  * with GNUNET_IPK_SELF_PREFIX, the current running apps installation directory
457  * @author Milan
458  * @return a pointer to the dir path (to be freed by the caller)
459  */
460 char *
461 GNUNET_OS_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind)
462 {
463   size_t n;
464   const char *dirname;
465   char *execpath = NULL;
466   char *tmp;
467   int isbasedir;
468
469   /* if wanted, try to get the current app's bin/ */
470   if (dirkind == GNUNET_OS_IPK_SELF_PREFIX)
471     execpath = os_get_exec_path ();
472
473   /* try to get GNUnet's bin/ or lib/, or if previous was unsuccessful some
474    * guess for the current app */
475   if (NULL == execpath)
476     execpath = os_get_gnunet_path ();
477
478   if (NULL == execpath)
479     return NULL;
480
481   n = strlen (execpath);
482   if (0 == n)
483   {
484     /* should never happen, but better safe than sorry */
485     GNUNET_free (execpath);
486     return NULL;
487   }
488   /* remove filename itself */
489   while ((n > 1) && (DIR_SEPARATOR == execpath[n - 1]))
490     execpath[--n] = '\0';
491
492   isbasedir = 1;
493   if ((n > 6) &&
494       ((0 == strcasecmp (&execpath[n - 6], "/lib32")) ||
495        (0 == strcasecmp (&execpath[n - 6], "/lib64"))))
496   {
497     if ( (GNUNET_OS_IPK_LIBDIR != dirkind) &&
498          (GNUNET_OS_IPK_LIBEXECDIR != dirkind) )
499     {
500       /* strip '/lib32' or '/lib64' */
501       execpath[n - 6] = '\0';
502       n -= 6;
503     }
504     else
505       isbasedir = 0;
506   }
507   else if ((n > 4) &&
508            ((0 == strcasecmp (&execpath[n - 4], "/bin")) ||
509             (0 == strcasecmp (&execpath[n - 4], "/lib"))))
510   {
511     /* strip '/bin' or '/lib' */
512     execpath[n - 4] = '\0';
513     n -= 4;
514   }
515   /* in case this was a directory named foo-bin, remove "foo-" */
516   while ((n > 1) && (execpath[n - 1] == DIR_SEPARATOR))
517     execpath[--n] = '\0';
518   switch (dirkind)
519   {
520   case GNUNET_OS_IPK_PREFIX:
521   case GNUNET_OS_IPK_SELF_PREFIX:
522     dirname = DIR_SEPARATOR_STR;
523     break;
524   case GNUNET_OS_IPK_BINDIR:
525     dirname = DIR_SEPARATOR_STR "bin" DIR_SEPARATOR_STR;
526     break;
527   case GNUNET_OS_IPK_LIBDIR:
528     if (isbasedir)
529     {
530       dirname =
531           DIR_SEPARATOR_STR "lib" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
532       tmp = GNUNET_malloc (strlen (execpath) + strlen (dirname) + 1);
533       sprintf (tmp, "%s%s", execpath, dirname);
534       if ( (GNUNET_YES !=
535             GNUNET_DISK_directory_test (tmp, GNUNET_YES)) &&
536            (4 == sizeof (void *)) )
537       {
538         GNUNET_free (tmp);
539         dirname =
540           DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
541         tmp = GNUNET_malloc (strlen (execpath) + strlen (dirname) + 1);
542         sprintf (tmp, "%s%s", execpath, dirname);
543       }
544       if ( (GNUNET_YES !=
545             GNUNET_DISK_directory_test (tmp, GNUNET_YES)) &&
546            (8 == sizeof (void *)) )
547       {
548         dirname =
549           DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
550       }
551       GNUNET_free (tmp);
552     }
553     else
554       dirname = DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
555     break;
556   case GNUNET_OS_IPK_DATADIR:
557     dirname =
558         DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
559     break;
560   case GNUNET_OS_IPK_LOCALEDIR:
561     dirname =
562         DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "locale" DIR_SEPARATOR_STR;
563     break;
564   case GNUNET_OS_IPK_ICONDIR:
565     dirname =
566         DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "icons" DIR_SEPARATOR_STR;
567     break;
568   case GNUNET_OS_IPK_DOCDIR:
569     dirname =
570         DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "doc" DIR_SEPARATOR_STR \
571         "gnunet" DIR_SEPARATOR_STR;
572     break;
573   case GNUNET_OS_IPK_LIBEXECDIR:
574     if (isbasedir)
575     {
576       dirname =
577         DIR_SEPARATOR_STR "lib" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR \
578         "libexec" DIR_SEPARATOR_STR;
579       tmp = GNUNET_malloc (strlen (execpath) + strlen (dirname) + 1);
580       sprintf (tmp, "%s%s", execpath, dirname);
581       if ( (GNUNET_YES !=
582             GNUNET_DISK_directory_test (tmp, GNUNET_YES)) &&
583            (4 == sizeof (void *)) )
584       {
585         GNUNET_free (tmp);
586         dirname =
587           DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR \
588           "libexec" DIR_SEPARATOR_STR;
589         tmp = GNUNET_malloc (strlen (execpath) + strlen (dirname) + 1);
590         sprintf (tmp, "%s%s", execpath, dirname);
591       }
592       if ( (GNUNET_YES !=
593             GNUNET_DISK_directory_test (tmp, GNUNET_YES)) &&
594            (8 == sizeof (void *)) )
595       {
596         dirname =
597           DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR \
598           "libexec" DIR_SEPARATOR_STR;
599       }
600       GNUNET_free (tmp);
601     }
602     else
603       dirname =
604         DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR \
605         "libexec" DIR_SEPARATOR_STR;
606     break;
607   default:
608     GNUNET_free (execpath);
609     return NULL;
610   }
611   tmp = GNUNET_malloc (strlen (execpath) + strlen (dirname) + 1);
612   sprintf (tmp, "%s%s", execpath, dirname);
613   GNUNET_free (execpath);
614   return tmp;
615 }
616
617
618 /**
619  * Given the name of a gnunet-helper, gnunet-service or gnunet-daemon
620  * binary, try to prefix it with the libexec/-directory to get the
621  * full path.
622  *
623  * @param progname name of the binary
624  * @return full path to the binary, if possible, otherwise copy of 'progname'
625  */
626 char *
627 GNUNET_OS_get_libexec_binary_path (const char *progname)
628 {
629   char *libexecdir;
630   char *binary;
631
632   if (DIR_SEPARATOR == progname[0])
633     return GNUNET_strdup (progname);
634   libexecdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBEXECDIR);
635   if (NULL == libexecdir)
636     return GNUNET_strdup (progname);
637   GNUNET_asprintf (&binary,
638                    "%s%s",
639                    libexecdir,
640                    progname);
641   GNUNET_free (libexecdir);
642   return binary;
643 }
644
645
646 /**
647  * Check whether an executable exists and possibly
648  * if the suid bit is set on the file.
649  * Attempts to find the file using the current
650  * PATH environment variable as a search path.
651  *
652  * @param binary the name of the file to check.
653  *        W32: must not have an .exe suffix.
654  * @return GNUNET_YES if the file is SUID,
655  *         GNUNET_NO if not SUID (but binary exists)
656  *         GNUNET_SYSERR on error (no such binary or not executable)
657  */
658 int
659 GNUNET_OS_check_helper_binary (const char *binary)
660 {
661   struct stat statbuf;
662   char *p;
663   char *pf;
664 #ifdef MINGW
665   SOCKET rawsock;
666   char *binaryexe;
667
668   GNUNET_asprintf (&binaryexe, "%s.exe", binary);
669   if ( (GNUNET_YES == GNUNET_STRINGS_path_is_absolute (binaryexe, GNUNET_NO,
670                                                        NULL, NULL)) ||
671        (0 == strncmp (binary, "./", 2)) )
672     p = GNUNET_strdup (binaryexe);
673   else
674   {
675     p = get_path_from_PATH (binaryexe);
676     if (NULL != p)
677     {
678       GNUNET_asprintf (&pf, "%s/%s", p, binaryexe);
679       GNUNET_free (p);
680       p = pf;
681     }
682   }
683   GNUNET_free (binaryexe);
684 #else
685   if ( (GNUNET_YES == GNUNET_STRINGS_path_is_absolute (binary, GNUNET_NO,
686                                                        NULL, NULL)) ||
687        (0 == strncmp (binary, "./", 2)) )
688     p = GNUNET_strdup (binary);
689   else
690   {
691     p = get_path_from_PATH (binary);
692     if (NULL != p)
693     {
694       GNUNET_asprintf (&pf, "%s/%s", p, binary);
695       GNUNET_free (p);
696       p = pf;
697     }
698   }
699 #endif
700   if (NULL == p)
701   {
702     LOG (GNUNET_ERROR_TYPE_INFO, _("Could not find binary `%s' in PATH!\n"),
703          binary);
704     return GNUNET_SYSERR;
705   }
706   if (0 != ACCESS (p, X_OK))
707   {
708     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", p);
709     GNUNET_free (p);
710     return GNUNET_SYSERR;
711   }
712 #ifndef MINGW
713   if (0 == getuid ())
714   {
715     /* as we run as root, we don't insist on SUID */
716     GNUNET_free (p);
717     return GNUNET_OK;
718   }
719 #endif
720   if (0 != STAT (p, &statbuf))
721   {
722     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", p);
723     GNUNET_free (p);
724     return GNUNET_SYSERR;
725   }
726 #ifndef MINGW
727   if ((0 != (statbuf.st_mode & S_ISUID)) && (0 == statbuf.st_uid))
728   {
729     GNUNET_free (p);
730     return GNUNET_YES;
731   }
732   /* binary exists, but not SUID */
733   GNUNET_free (p);
734   return GNUNET_NO;
735 #else
736   GNUNET_free (p);
737   {
738     static int once; /* remember result from previous runs... */
739
740     if (0 == once)
741     {
742       rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
743       if (INVALID_SOCKET == rawsock)
744         {
745           DWORD err = GetLastError ();
746           
747           LOG (GNUNET_ERROR_TYPE_DEBUG,
748                "socket (AF_INET, SOCK_RAW, IPPROTO_ICMP) failed! GLE = %d\n", err);
749           once = -1;
750           return GNUNET_NO;           /* not running as administrator */
751         }
752       once = 1;
753       closesocket (rawsock);
754     }
755     if (-1 == once)
756       return GNUNET_NO;
757     return GNUNET_YES;
758   }
759 #endif
760 }
761
762
763 /* end of os_installation.c */