Add test code, but it's still segfaulting.
[oweals/gnunet.git] / src / util / os_installation.c
index 188401abbc40de24d32a14a1d8f2aff2ea9609f8..ea6361a92db4424ef6006132db4b35eea93844d5 100644 (file)
@@ -1,10 +1,10 @@
 /*
      This file is part of GNUnet.
 /*
      This file is part of GNUnet.
-     (C) 2006 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2006-2014 Christian Grothoff (and other contributing authors)
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
@@ -14,8 +14,8 @@
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
 */
 
 /**
 */
 
 /**
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <unistr.h> /* for u16_to_u8 */
 
 #include "platform.h"
 
 #include "platform.h"
-#include "gnunet_common.h"
-#include "gnunet_configuration_lib.h"
-#include "gnunet_disk_lib.h"
-#include "gnunet_os_lib.h"
+#include "gnunet_util_lib.h"
 #if DARWIN
 #include <mach-o/ldsyms.h>
 #include <mach-o/dyld.h>
 #if DARWIN
 #include <mach-o/ldsyms.h>
 #include <mach-o/dyld.h>
+#elif WINDOWS
+#include <windows.h>
 #endif
 
 #endif
 
+
+#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
+
+#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
+
+
 #if LINUX
 /**
  * Try to determine path by reading /proc/PID/exe
 #if LINUX
 /**
  * Try to determine path by reading /proc/PID/exe
+ *
+ * @return NULL on error
  */
 static char *
 get_path_from_proc_maps ()
  */
 static char *
 get_path_from_proc_maps ()
@@ -52,26 +60,28 @@ get_path_from_proc_maps ()
   char *lgu;
 
   GNUNET_snprintf (fn, sizeof (fn), "/proc/%u/maps", getpid ());
   char *lgu;
 
   GNUNET_snprintf (fn, sizeof (fn), "/proc/%u/maps", getpid ());
-  f = fopen (fn, "r");
-  if (f == NULL)
+  if (NULL == (f = FOPEN (fn, "r")))
     return NULL;
   while (NULL != fgets (line, sizeof (line), f))
   {
     return NULL;
   while (NULL != fgets (line, sizeof (line), f))
   {
-    if ((1 == sscanf (line,
-                      "%*x-%*x %*c%*c%*c%*c %*x %*2u:%*2u %*u%*[ ]%s",
-                      dir)) && (NULL != (lgu = strstr (dir, "libgnunetutil"))))
+    if ((1 ==
+         SSCANF (line, "%*x-%*x %*c%*c%*c%*c %*x %*2x:%*2x %*u%*[ ]%1023s", dir)) &&
+        (NULL != (lgu = strstr (dir, "libgnunetutil"))))
     {
       lgu[0] = '\0';
     {
       lgu[0] = '\0';
-      fclose (f);
+      FCLOSE (f);
       return GNUNET_strdup (dir);
     }
   }
       return GNUNET_strdup (dir);
     }
   }
-  fclose (f);
+  FCLOSE (f);
   return NULL;
 }
 
   return NULL;
 }
 
+
 /**
  * Try to determine path by reading /proc/PID/exe
 /**
  * Try to determine path by reading /proc/PID/exe
+ *
+ * @return NULL on error
  */
 static char *
 get_path_from_proc_exe ()
  */
 static char *
 get_path_from_proc_exe ()
@@ -84,13 +94,18 @@ get_path_from_proc_exe ()
   size = readlink (fn, lnk, sizeof (lnk) - 1);
   if (size <= 0)
   {
   size = readlink (fn, lnk, sizeof (lnk) - 1);
   if (size <= 0)
   {
-    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "readlink", fn);
+    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "readlink", fn);
     return NULL;
   }
   GNUNET_assert (size < sizeof (lnk));
   lnk[size] = '\0';
   while ((lnk[size] != '/') && (size > 0))
     size--;
     return NULL;
   }
   GNUNET_assert (size < sizeof (lnk));
   lnk[size] = '\0';
   while ((lnk[size] != '/') && (size > 0))
     size--;
+  /* test for being in lib/gnunet/libexec/ or lib/MULTIARCH/gnunet/libexec */
+  if ( (size > strlen ("/gnunet/libexec/")) &&
+       (0 == strcmp ("/gnunet/libexec/",
+                    &lnk[size - strlen ("/gnunet/libexec/")])) )
+    size -= strlen ("gnunet/libexec/");
   if ((size < 4) || (lnk[size - 4] != '/'))
   {
     /* not installed in "/bin/" -- binary path probably useless */
   if ((size < 4) || (lnk[size - 4] != '/'))
   {
     /* not installed in "/bin/" -- binary path probably useless */
@@ -101,28 +116,135 @@ get_path_from_proc_exe ()
 }
 #endif
 
 }
 #endif
 
+
 #if WINDOWS
 #if WINDOWS
+static HINSTANCE dll_instance;
+
+
+/**
+ * GNUNET_util_cl_init() in common_logging.c is preferred.
+ * This function is only for thread-local storage (not used in GNUnet)
+ * and hInstance saving.
+ */
+BOOL WINAPI
+DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+  switch (fdwReason)
+  {
+    case DLL_PROCESS_ATTACH:
+      dll_instance = hinstDLL;
+      break;
+    case DLL_THREAD_ATTACH:
+      break;
+    case DLL_THREAD_DETACH:
+      break;
+    case DLL_PROCESS_DETACH:
+      break;
+  }
+  return TRUE;
+}
+
+
 /**
  * Try to determine path with win32-specific function
 /**
  * Try to determine path with win32-specific function
+ *
+ * @return NULL on error
  */
 static char *
 get_path_from_module_filename ()
 {
  */
 static char *
 get_path_from_module_filename ()
 {
-  char path[4097];
-  char *idx;
-
-  GetModuleFileName (NULL, path, sizeof (path) - 1);
-  idx = path + strlen (path);
-  while ((idx > path) && (*idx != '\\') && (*idx != '/'))
+  size_t pathlen = 512;
+  DWORD real_pathlen;
+  wchar_t *idx;
+  wchar_t *modulepath = NULL;
+  char *upath;
+  uint8_t *u8_string;
+  size_t u8_string_length;
+
+  /* This braindead function won't tell us how much space it needs, so
+   * we start at 1024 and double the space up if it doesn't fit, until
+   * it fits, or we exceed the threshold.
+   */
+  do
+  {
+    pathlen = pathlen * 2;
+    modulepath = GNUNET_realloc (modulepath, pathlen * sizeof (wchar_t));
+    SetLastError (0);
+    real_pathlen = GetModuleFileNameW (dll_instance, modulepath, pathlen * sizeof (wchar_t));
+  } while (real_pathlen >= pathlen && pathlen < 16*1024);
+  if (real_pathlen >= pathlen)
+    GNUNET_assert (0);
+  /* To be safe */
+  modulepath[real_pathlen] = '\0';
+
+  idx = modulepath + real_pathlen;
+  while ((idx > modulepath) && (*idx != L'\\') && (*idx != L'/'))
     idx--;
     idx--;
-  *idx = '\0';
-  return GNUNET_strdup (path);
+  *idx = L'\0';
+
+  /* Now modulepath holds full path to the directory where libgnunetutil is.
+   * This directory should look like <GNUNET_PREFIX>/bin or <GNUNET_PREFIX>.
+   */
+  if (wcschr (modulepath, L'/') || wcschr (modulepath, L'\\'))
+  {
+    /* At least one directory component (i.e. we're not in a root directory) */
+    wchar_t *dirname = idx;
+    while ((dirname > modulepath) && (*dirname != L'\\') && (*dirname != L'/'))
+      dirname--;
+    *dirname = L'\0';
+    if (dirname > modulepath)
+    {
+      dirname++;
+      /* Now modulepath holds full path to the parent directory of the directory
+       * where libgnunetutil is.
+       * dirname holds the name of the directory where libgnunetutil is.
+       */
+      if (wcsicmp (dirname, L"bin") == 0)
+      {
+        /* pass */
+      }
+      else
+      {
+        /* Roll back our changes to modulepath */
+        dirname--;
+        *dirname = L'/';
+      }
+    }
+  }
+
+  /* modulepath is GNUNET_PREFIX */
+  u8_string = u16_to_u8 (modulepath, wcslen (modulepath), NULL, &u8_string_length);
+  if (NULL == u8_string)
+    GNUNET_assert (0);
+
+  upath = GNUNET_malloc (u8_string_length + 1);
+  memcpy (upath, u8_string, u8_string_length);
+  upath[u8_string_length] = '\0';
+
+  free (u8_string);
+  GNUNET_free (modulepath);
+
+  return upath;
 }
 #endif
 
 }
 #endif
 
+
 #if DARWIN
 #if DARWIN
+/**
+ * Signature of the '_NSGetExecutablePath" function.
+ *
+ * @param buf where to write the path
+ * @param number of bytes available in 'buf'
+ * @return 0 on success, otherwise desired number of bytes is stored in 'bufsize'
+ */
 typedef int (*MyNSGetExecutablePathProto) (char *buf, size_t * bufsize);
 
 typedef int (*MyNSGetExecutablePathProto) (char *buf, size_t * bufsize);
 
+
+/**
+ * Try to obtain the path of our executable using '_NSGetExecutablePath'.
+ *
+ * @return NULL on error
+ */
 static char *
 get_path_from_NSGetExecutablePath ()
 {
 static char *
 get_path_from_NSGetExecutablePath ()
 {
@@ -130,22 +252,19 @@ get_path_from_NSGetExecutablePath ()
   char *path;
   size_t len;
   MyNSGetExecutablePathProto func;
   char *path;
   size_t len;
   MyNSGetExecutablePathProto func;
-  int ret;
 
   path = NULL;
 
   path = NULL;
-  func =
-      (MyNSGetExecutablePathProto) dlsym (RTLD_DEFAULT, "_NSGetExecutablePath");
-  if (!func)
+  if (NULL == (func =
+              (MyNSGetExecutablePathProto) dlsym (RTLD_DEFAULT, "_NSGetExecutablePath")))
     return NULL;
   path = &zero;
   len = 0;
   /* get the path len, including the trailing \0 */
     return NULL;
   path = &zero;
   len = 0;
   /* get the path len, including the trailing \0 */
-  func (path, &len);
-  if (len == 0)
+  (void) func (path, &len);
+  if (0 == len)
     return NULL;
   path = GNUNET_malloc (len);
     return NULL;
   path = GNUNET_malloc (len);
-  ret = func (path, &len);
-  if (ret != 0)
+  if (0 != func (path, &len))
   {
     GNUNET_free (path);
     return NULL;
   {
     GNUNET_free (path);
     return NULL;
@@ -157,37 +276,42 @@ get_path_from_NSGetExecutablePath ()
   return path;
 }
 
   return path;
 }
 
+
+/**
+ * Try to obtain the path of our executable using '_dyld_image' API.
+ *
+ * @return NULL on error
+ */
 static char *
 get_path_from_dyld_image ()
 {
   const char *path;
 static char *
 get_path_from_dyld_image ()
 {
   const char *path;
-  char *p, *s;
-  int i;
+  char *p;
+  char *s;
+  unsigned int i;
   int c;
 
   int c;
 
-  p = NULL;
   c = _dyld_image_count ();
   for (i = 0; i < c; i++)
   {
   c = _dyld_image_count ();
   for (i = 0; i < c; i++)
   {
-    if (_dyld_get_image_header (i) == &_mh_dylib_header)
-    {
-      path = _dyld_get_image_name (i);
-      if (path != NULL && strlen (path) > 0)
-      {
-        p = strdup (path);
-        s = p + strlen (p);
-        while ((s > p) && (*s != '/'))
-          s--;
-        s++;
-        *s = '\0';
-      }
-      break;
-    }
+    if (((const void *) _dyld_get_image_header (i)) != (const void *)&_mh_dylib_header)
+      continue;
+    path = _dyld_get_image_name (i);
+    if ( (NULL == path) || (0 == strlen (path)) )
+      continue;
+    p = GNUNET_strdup (path);
+    s = p + strlen (p);
+    while ((s > p) && ('/' != *s))
+      s--;
+    s++;
+    *s = '\0';
+    return p;
   }
   }
-  return p;
+  return NULL;
 }
 #endif
 
 }
 #endif
 
+
 /**
  * Return the actual path to a file found in the current
  * PATH environment variable.
 /**
  * Return the actual path to a file found in the current
  * PATH environment variable.
@@ -204,11 +328,15 @@ get_path_from_PATH (const char *binary)
   char *buf;
   const char *p;
 
   char *buf;
   const char *p;
 
-  p = getenv ("PATH");
-  if (p == NULL)
+  if (NULL == (p = getenv ("PATH")))
     return NULL;
     return NULL;
+#if WINDOWS
+  /* On W32 look in CWD first. */
+  GNUNET_asprintf (&path, ".%c%s", PATH_SEPARATOR, p);
+#else
   path = GNUNET_strdup (p);     /* because we write on it */
   path = GNUNET_strdup (p);     /* because we write on it */
-  buf = GNUNET_malloc (strlen (path) + 20);
+#endif
+  buf = GNUNET_malloc (strlen (path) + strlen (binary) + 1 + 1);
   pos = path;
   while (NULL != (end = strchr (pos, PATH_SEPARATOR)))
   {
   pos = path;
   while (NULL != (end = strchr (pos, PATH_SEPARATOR)))
   {
@@ -224,7 +352,7 @@ get_path_from_PATH (const char *binary)
     pos = end + 1;
   }
   sprintf (buf, "%s/%s", pos, binary);
     pos = end + 1;
   }
   sprintf (buf, "%s/%s", pos, binary);
-  if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
+  if (GNUNET_YES == GNUNET_DISK_file_test (buf))
   {
     pos = GNUNET_strdup (pos);
     GNUNET_free (buf);
   {
     pos = GNUNET_strdup (pos);
     GNUNET_free (buf);
@@ -236,18 +364,25 @@ get_path_from_PATH (const char *binary)
   return NULL;
 }
 
   return NULL;
 }
 
+
+/**
+ * Try to obtain the installation path using the "GNUNET_PREFIX" environment
+ * variable.
+ *
+ * @return NULL on error (environment variable not set)
+ */
 static char *
 get_path_from_GNUNET_PREFIX ()
 {
   const char *p;
 
 static char *
 get_path_from_GNUNET_PREFIX ()
 {
   const char *p;
 
-  p = getenv ("GNUNET_PREFIX");
-  if (p != NULL)
+  if (NULL != (p = getenv ("GNUNET_PREFIX")))
     return GNUNET_strdup (p);
   return NULL;
 }
 
     return GNUNET_strdup (p);
   return NULL;
 }
 
-/*
+
+/**
  * @brief get the path to GNUnet bin/ or lib/, prefering the lib/ path
  * @author Milan
  *
  * @brief get the path to GNUnet bin/ or lib/, prefering the lib/ path
  * @author Milan
  *
@@ -258,42 +393,38 @@ os_get_gnunet_path ()
 {
   char *ret;
 
 {
   char *ret;
 
-  ret = get_path_from_GNUNET_PREFIX ();
-  if (ret != NULL)
+  if (NULL != (ret = get_path_from_GNUNET_PREFIX ()))
     return ret;
 #if LINUX
     return ret;
 #if LINUX
-  ret = get_path_from_proc_maps ();
-  if (ret != NULL)
+  if (NULL != (ret = get_path_from_proc_maps ()))
+    return ret;
+  /* try path *first*, before /proc/exe, as /proc/exe can be wrong */
+  if (NULL != (ret = get_path_from_PATH ("gnunet-arm")))
     return ret;
     return ret;
-  ret = get_path_from_proc_exe ();
-  if (ret != NULL)
+  if (NULL != (ret = get_path_from_proc_exe ()))
     return ret;
 #endif
 #if WINDOWS
     return ret;
 #endif
 #if WINDOWS
-  ret = get_path_from_module_filename ();
-  if (ret != NULL)
+  if (NULL != (ret = get_path_from_module_filename ()))
     return ret;
 #endif
 #if DARWIN
     return ret;
 #endif
 #if DARWIN
-  ret = get_path_from_dyld_image ();
-  if (ret != NULL)
+  if (NULL != (ret = get_path_from_dyld_image ()))
     return ret;
     return ret;
-  ret = get_path_from_NSGetExecutablePath ();
-  if (ret != NULL)
+  if (NULL != (ret = get_path_from_NSGetExecutablePath ()))
     return ret;
 #endif
     return ret;
 #endif
-  ret = get_path_from_PATH ("gnunet-arm");
-  if (ret != NULL)
+  if (NULL != (ret = get_path_from_PATH ("gnunet-arm")))
     return ret;
   /* other attempts here */
     return ret;
   /* other attempts here */
-  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-              _
-              ("Could not determine installation path for %s.  Set `%s' environment variable.\n"),
-              "GNUnet", "GNUNET_PREFIX");
+  LOG (GNUNET_ERROR_TYPE_ERROR,
+       _("Could not determine installation path for %s.  Set `%s' environment variable.\n"),
+       "GNUnet", "GNUNET_PREFIX");
   return NULL;
 }
 
   return NULL;
 }
 
-/*
+
+/**
  * @brief get the path to current app's bin/
  * @author Milan
  *
  * @brief get the path to current app's bin/
  * @author Milan
  *
@@ -302,22 +433,18 @@ os_get_gnunet_path ()
 static char *
 os_get_exec_path ()
 {
 static char *
 os_get_exec_path ()
 {
-  char *ret;
+  char *ret = NULL;
 
 
-  ret = NULL;
 #if LINUX
 #if LINUX
-  ret = get_path_from_proc_exe ();
-  if (ret != NULL)
+  if (NULL != (ret = get_path_from_proc_exe ()))
     return ret;
 #endif
 #if WINDOWS
     return ret;
 #endif
 #if WINDOWS
-  ret = get_path_from_module_filename ();
-  if (ret != NULL)
+  if (NULL != (ret = get_path_from_module_filename ()))
     return ret;
 #endif
 #if DARWIN
     return ret;
 #endif
 #if DARWIN
-  ret = get_path_from_NSGetExecutablePath ();
-  if (ret != NULL)
+  if (NULL != (ret = get_path_from_NSGetExecutablePath ()))
     return ret;
 #endif
   /* other attempts here */
     return ret;
 #endif
   /* other attempts here */
@@ -325,10 +452,9 @@ os_get_exec_path ()
 }
 
 
 }
 
 
-
 /**
  * @brief get the path to a specific GNUnet installation directory or,
 /**
  * @brief get the path to a specific GNUnet installation directory or,
- * with GNUNET_IPK_SELF_PREFIX, the current running apps installation directory
+ * with #GNUNET_OS_IPK_SELF_PREFIX, the current running apps installation directory
  * @author Milan
  * @return a pointer to the dir path (to be freed by the caller)
  */
  * @author Milan
  * @return a pointer to the dir path (to be freed by the caller)
  */
@@ -339,6 +465,8 @@ GNUNET_OS_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind)
   const char *dirname;
   char *execpath = NULL;
   char *tmp;
   const char *dirname;
   char *execpath = NULL;
   char *tmp;
+  char *multiarch;
+  char *libdir;
   int isbasedir;
 
   /* if wanted, try to get the current app's bin/ */
   int isbasedir;
 
   /* if wanted, try to get the current app's bin/ */
@@ -347,44 +475,56 @@ GNUNET_OS_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind)
 
   /* try to get GNUnet's bin/ or lib/, or if previous was unsuccessful some
    * guess for the current app */
 
   /* try to get GNUnet's bin/ or lib/, or if previous was unsuccessful some
    * guess for the current app */
-  if (execpath == NULL)
+  if (NULL == execpath)
     execpath = os_get_gnunet_path ();
 
     execpath = os_get_gnunet_path ();
 
-  if (execpath == NULL)
+  if (NULL == execpath)
     return NULL;
 
   n = strlen (execpath);
     return NULL;
 
   n = strlen (execpath);
-  if (n == 0)
+  if (0 == n)
   {
     /* should never happen, but better safe than sorry */
     GNUNET_free (execpath);
     return NULL;
   }
   /* remove filename itself */
   {
     /* should never happen, but better safe than sorry */
     GNUNET_free (execpath);
     return NULL;
   }
   /* remove filename itself */
-  while ((n > 1) && (execpath[n - 1] == DIR_SEPARATOR))
+  while ((n > 1) && (DIR_SEPARATOR == execpath[n - 1]))
     execpath[--n] = '\0';
 
   isbasedir = 1;
     execpath[--n] = '\0';
 
   isbasedir = 1;
-  if ((n > 5) &&
-      ((0 == strcasecmp (&execpath[n - 5], "lib32")) ||
-       (0 == strcasecmp (&execpath[n - 5], "lib64"))))
+  if ((n > 6) &&
+      ((0 == strcasecmp (&execpath[n - 6], "/lib32")) ||
+       (0 == strcasecmp (&execpath[n - 6], "/lib64"))))
   {
   {
-    if (dirkind != GNUNET_OS_IPK_LIBDIR)
+    if ( (GNUNET_OS_IPK_LIBDIR != dirkind) &&
+        (GNUNET_OS_IPK_LIBEXECDIR != dirkind) )
     {
       /* strip '/lib32' or '/lib64' */
     {
       /* strip '/lib32' or '/lib64' */
-      execpath[n - 5] = '\0';
-      n -= 5;
+      execpath[n - 6] = '\0';
+      n -= 6;
     }
     else
       isbasedir = 0;
   }
     }
     else
       isbasedir = 0;
   }
-  else if ((n > 3) &&
-           ((0 == strcasecmp (&execpath[n - 3], "bin")) ||
-            (0 == strcasecmp (&execpath[n - 3], "lib"))))
+  else if ((n > 4) &&
+           ((0 == strcasecmp (&execpath[n - 4], "/bin")) ||
+            (0 == strcasecmp (&execpath[n - 4], "/lib"))))
   {
     /* strip '/bin' or '/lib' */
   {
     /* strip '/bin' or '/lib' */
-    execpath[n - 3] = '\0';
-    n -= 3;
+    execpath[n - 4] = '\0';
+    n -= 4;
+  }
+  multiarch = NULL;
+  if (NULL != (libdir = strstr (execpath, "/lib/")))
+  {
+    /* test for multi-arch path of the form "PREFIX/lib/MULTIARCH/";
+       here we need to re-add 'multiarch' to lib and libexec paths later! */
+    multiarch = &libdir[5];
+    if (NULL == strchr (multiarch, '/'))
+      libdir[0] = '\0'; /* Debian multiarch format, cut of from 'execpath' but preserve in multicarch */
+    else
+      multiarch = NULL; /* maybe not, multiarch still has a '/', which is not OK */
   }
   /* in case this was a directory named foo-bin, remove "foo-" */
   while ((n > 1) && (execpath[n - 1] == DIR_SEPARATOR))
   }
   /* in case this was a directory named foo-bin, remove "foo-" */
   while ((n > 1) && (execpath[n - 1] == DIR_SEPARATOR))
@@ -400,10 +540,51 @@ GNUNET_OS_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind)
     break;
   case GNUNET_OS_IPK_LIBDIR:
     if (isbasedir)
     break;
   case GNUNET_OS_IPK_LIBDIR:
     if (isbasedir)
-      dirname =
-          DIR_SEPARATOR_STR "lib" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
-    else
-      dirname = DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
+    {
+      GNUNET_asprintf (&tmp,
+                       "%s%s%s%s%s",
+                       execpath,
+                       DIR_SEPARATOR_STR "lib",
+                       (NULL != multiarch) ? DIR_SEPARATOR_STR : "",
+                       (NULL != multiarch) ? multiarch : "",
+                       DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR);
+      if (GNUNET_YES ==
+          GNUNET_DISK_directory_test (tmp, GNUNET_YES))
+      {
+        GNUNET_free (execpath);
+        return tmp;
+      }
+      GNUNET_free (tmp);
+      tmp = NULL;
+      if (4 == sizeof (void *))
+      {
+       dirname =
+         DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
+       GNUNET_asprintf (&tmp,
+                         "%s%s",
+                         execpath,
+                         dirname);
+      }
+      if (8 == sizeof (void *))
+      {
+       dirname =
+         DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
+       GNUNET_asprintf (&tmp,
+                         "%s%s",
+                         execpath,
+                         dirname);
+      }
+
+      if ( (NULL != tmp) &&
+           (GNUNET_YES ==
+            GNUNET_DISK_directory_test (tmp, GNUNET_YES)) )
+      {
+        GNUNET_free (execpath);
+        return tmp;
+      }
+      GNUNET_free (tmp);
+    }
+    dirname = DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR;
     break;
   case GNUNET_OS_IPK_DATADIR:
     dirname =
     break;
   case GNUNET_OS_IPK_DATADIR:
     dirname =
@@ -417,98 +598,257 @@ GNUNET_OS_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind)
     dirname =
         DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "icons" DIR_SEPARATOR_STR;
     break;
     dirname =
         DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "icons" DIR_SEPARATOR_STR;
     break;
+  case GNUNET_OS_IPK_DOCDIR:
+    dirname =
+        DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "doc" DIR_SEPARATOR_STR \
+        "gnunet" DIR_SEPARATOR_STR;
+    break;
+  case GNUNET_OS_IPK_LIBEXECDIR:
+    if (isbasedir)
+    {
+      dirname =
+        DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR "libexec" DIR_SEPARATOR_STR;
+      GNUNET_asprintf (&tmp,
+                       "%s%s%s%s",
+                       execpath,
+                       DIR_SEPARATOR_STR "lib" DIR_SEPARATOR_STR,
+                       (NULL != multiarch) ? multiarch : "",
+                       dirname);
+      if (GNUNET_YES ==
+          GNUNET_DISK_directory_test (tmp, GNUNET_YES))
+      {
+        GNUNET_free (execpath);
+        return tmp;
+      }
+      GNUNET_free (tmp);
+      tmp = NULL;
+      if (4 == sizeof (void *))
+      {
+       dirname =
+         DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR \
+         "libexec" DIR_SEPARATOR_STR;
+       GNUNET_asprintf (&tmp,
+                         "%s%s",
+                         execpath,
+                         dirname);
+      }
+      if (8 == sizeof (void *))
+      {
+       dirname =
+         DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR \
+         "libexec" DIR_SEPARATOR_STR;
+       GNUNET_asprintf (&tmp,
+                         "%s%s",
+                         execpath,
+                         dirname);
+      }
+      if ( (NULL != tmp) &&
+           (GNUNET_YES ==
+            GNUNET_DISK_directory_test (tmp, GNUNET_YES)) )
+      {
+        GNUNET_free (execpath);
+        return tmp;
+      }
+
+      GNUNET_free (tmp);
+    }
+    dirname =
+      DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR \
+      "libexec" DIR_SEPARATOR_STR;
+    break;
   default:
     GNUNET_free (execpath);
     return NULL;
   }
   default:
     GNUNET_free (execpath);
     return NULL;
   }
-  tmp = GNUNET_malloc (strlen (execpath) + strlen (dirname) + 1);
-  sprintf (tmp, "%s%s", execpath, dirname);
+  GNUNET_asprintf (&tmp,
+                   "%s%s",
+                   execpath,
+                   dirname);
   GNUNET_free (execpath);
   return tmp;
 }
 
 
   GNUNET_free (execpath);
   return tmp;
 }
 
 
+/**
+ * Given the name of a gnunet-helper, gnunet-service or gnunet-daemon
+ * binary, try to prefix it with the libexec/-directory to get the
+ * full path.
+ *
+ * @param progname name of the binary
+ * @return full path to the binary, if possible, otherwise copy of 'progname'
+ */
+char *
+GNUNET_OS_get_libexec_binary_path (const char *progname)
+{
+  static char *cache;
+  char *libexecdir;
+  char *binary;
+
+  if ( (DIR_SEPARATOR == progname[0]) ||
+       (GNUNET_YES == GNUNET_STRINGS_path_is_absolute (progname, GNUNET_NO, NULL, NULL)) )
+    return GNUNET_strdup (progname);
+  if (NULL != cache)
+    libexecdir = cache;
+  else
+    libexecdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBEXECDIR);
+  if (NULL == libexecdir)
+    return GNUNET_strdup (progname);
+  GNUNET_asprintf (&binary,
+                  "%s%s",
+                  libexecdir,
+                  progname);
+  cache = libexecdir;
+  return binary;
+}
+
+
 /**
  * Check whether an executable exists and possibly
  * if the suid bit is set on the file.
  * Attempts to find the file using the current
  * PATH environment variable as a search path.
  *
 /**
  * Check whether an executable exists and possibly
  * if the suid bit is set on the file.
  * Attempts to find the file using the current
  * PATH environment variable as a search path.
  *
- * @param binary the name of the file to check
- * @return GNUNET_YES if the file is SUID, 
- *         GNUNET_NO if not SUID (but binary exists)
- *         GNUNET_SYSERR on error (no such binary or not executable)
+ * @param binary the name of the file to check.
+ *        W32: must not have an .exe suffix.
+ * @param check_suid input true if the binary should be checked for SUID (*nix)
+ *        W32: checks if the program has sufficient privileges by executing this
+ *             binary with the -d flag. -d omits a programs main loop and only
+ *             executes all privileged operations in an binary.
+ * @param params parameters used for w32 privilege checking (can be NULL for != w32 )
+ * @return #GNUNET_YES if the file is SUID (*nix) or can be executed with current privileges (W32),
+ *         #GNUNET_NO if not SUID (but binary exists),
+ *         #GNUNET_SYSERR on error (no such binary or not executable)
  */
 int
  */
 int
-GNUNET_OS_check_helper_binary (const char *binary)
+GNUNET_OS_check_helper_binary (const char *binary,
+                               int check_suid,
+                               const char *params)
 {
   struct stat statbuf;
   char *p;
   char *pf;
 {
   struct stat statbuf;
   char *p;
   char *pf;
-
 #ifdef MINGW
 #ifdef MINGW
-  SOCKET rawsock;
   char *binaryexe;
 
   GNUNET_asprintf (&binaryexe, "%s.exe", binary);
   char *binaryexe;
 
   GNUNET_asprintf (&binaryexe, "%s.exe", binary);
-  p = get_path_from_PATH (binaryexe);
-  if (p != NULL)
+  if ( (GNUNET_YES == GNUNET_STRINGS_path_is_absolute (binaryexe, GNUNET_NO,
+                                                      NULL, NULL)) ||
+       (0 == strncmp (binary, "./", 2)) )
+    p = GNUNET_strdup (binaryexe);
+  else
   {
   {
-    GNUNET_asprintf (&pf, "%s/%s", p, binaryexe);
-    GNUNET_free (p);
-    p = pf;
+    p = get_path_from_PATH (binaryexe);
+    if (NULL != p)
+    {
+      GNUNET_asprintf (&pf, "%s/%s", p, binaryexe);
+      GNUNET_free (p);
+      p = pf;
+    }
   }
   }
-  free (binaryexe);
+  GNUNET_free (binaryexe);
 #else
 #else
-  p = get_path_from_PATH (binary);
-  if (p != NULL)
+  if ( (GNUNET_YES == GNUNET_STRINGS_path_is_absolute (binary, GNUNET_NO,
+                                                      NULL, NULL)) ||
+       (0 == strncmp (binary, "./", 2)) )
+    p = GNUNET_strdup (binary);
+  else
   {
   {
-    GNUNET_asprintf (&pf, "%s/%s", p, binary);
-    GNUNET_free (p);
-    p = pf;
+    p = get_path_from_PATH (binary);
+    if (NULL != p)
+    {
+      GNUNET_asprintf (&pf, "%s/%s", p, binary);
+      GNUNET_free (p);
+      p = pf;
+    }
   }
 #endif
   }
 #endif
-  if (p == NULL)
+  if (NULL == p)
   {
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                _("Could not find binary `%s' in PATH!\n"), binary);
+    LOG (GNUNET_ERROR_TYPE_INFO,
+         _("Could not find binary `%s' in PATH!\n"),
+         binary);
     return GNUNET_SYSERR;
   }
     return GNUNET_SYSERR;
   }
-  if (0 != STAT (p, &statbuf))
+  if (0 != ACCESS (p, X_OK))
   {
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                _("stat (%s) failed: %s\n"), p, STRERROR (errno));
+    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", p);
     GNUNET_free (p);
     return GNUNET_SYSERR;
   }
 #ifndef MINGW
     GNUNET_free (p);
     return GNUNET_SYSERR;
   }
 #ifndef MINGW
-  if ((0 != (statbuf.st_mode & S_ISUID)) && (statbuf.st_uid == 0))
+  if (0 == getuid ())
   {
   {
+    /* as we run as root, we don't insist on SUID */
     GNUNET_free (p);
     GNUNET_free (p);
-    return GNUNET_YES;
+    return GNUNET_OK;
   }
   }
-  if (0 == ACCESS (p, X_OK))
+#endif
+  if (0 != STAT (p, &statbuf))
   {
   {
+    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", p);
     GNUNET_free (p);
     GNUNET_free (p);
-    return GNUNET_NO;
+    return GNUNET_SYSERR;
   }
   }
-  GNUNET_free (p);
-  return GNUNET_SYSERR;
+  if (check_suid){
+#ifndef MINGW
+    if ((0 != (statbuf.st_mode & S_ISUID)) && (0 == statbuf.st_uid))
+    {
+      GNUNET_free (p);
+      return GNUNET_YES;
+    }
+    /* binary exists, but not SUID */
 #else
 #else
-  GNUNET_free (p);
-  rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
-  if (INVALID_SOCKET == rawsock)
-  {
-    DWORD err = GetLastError ();
+    STARTUPINFO start;
+    char parameters[512];
+    PROCESS_INFORMATION proc;
+    DWORD exit_value;
+
+    GNUNET_snprintf (parameters,
+                    sizeof (parameters),
+                    "-d %s", params);
+    memset (&start, 0, sizeof (start));
+    start.cb = sizeof (start);
+    memset (&proc, 0, sizeof (proc));
+
+
+    // Start the child process.
+    if ( ! (CreateProcess( p,   // current windows (2k3 and up can handle / instead of \ in paths))
+        parameters,           // execute dryrun/priviliege checking mode
+        NULL,           // Process handle not inheritable
+        NULL,           // Thread handle not inheritable
+        FALSE,          // Set handle inheritance to FALSE
+        CREATE_DEFAULT_ERROR_MODE, // No creation flags
+        NULL,           // Use parent's environment block
+        NULL,           // Use parent's starting directory
+        &start,            // Pointer to STARTUPINFO structure
+        &proc )           // Pointer to PROCESS_INFORMATION structure
+                               ))
+      {
+        LOG (GNUNET_ERROR_TYPE_ERROR,
+             _("CreateProcess failed for binary %s (%d).\n"),
+             p, GetLastError());
+        return GNUNET_SYSERR;
+    }
 
 
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                "socket (AF_INET, SOCK_RAW, IPPROTO_ICMP) failed! GLE = %d\n",
-                err);
-    return GNUNET_NO;           /* not running as administrator */
-  }
-  closesocket (rawsock);
-  return GNUNET_YES;
+    // Wait until child process exits.
+    WaitForSingleObject( proc.hProcess, INFINITE );
+
+    if ( ! GetExitCodeProcess (proc.hProcess, &exit_value)){
+        LOG (GNUNET_ERROR_TYPE_ERROR,
+             _("GetExitCodeProcess failed for binary %s (%d).\n"),
+             p, GetLastError() );
+        return GNUNET_SYSERR;
+      }
+    // Close process and thread handles.
+    CloseHandle( proc.hProcess );
+    CloseHandle( proc.hThread );
+
+    if (!exit_value)
+      return GNUNET_YES;
 #endif
 #endif
+    }
+  GNUNET_free (p);
+  return GNUNET_NO;
 }
 
 
 }