RECLAIM/OIDC: code cleanup
[oweals/gnunet.git] / src / arm / gnunet-service-arm.c
index 995cd44895cce402cdb76ffabe652570bdf42c06..17304d3b3f29f2d4c0252ff4664f8432077f8eff 100644 (file)
@@ -2,20 +2,20 @@
      This file is part of GNUnet.
      Copyright (C) 2009-2011, 2015, 2016 GNUnet e.V.
 
-     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 3, or (at your
-     option) any later version.
+     GNUnet is free software: you can redistribute it and/or modify it
+     under the terms of the GNU Affero General Public License as published
+     by the Free Software Foundation, either version 3 of the License,
+     or (at your option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
      WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
+     Affero General Public License for more details.
 
-     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., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
+     You should have received a copy of the GNU Affero General Public License
+     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+     SPDX-License-Identifier: AGPL3.0-or-later
 */
 
 /**
 #include "gnunet_protocols.h"
 #include "arm.h"
 
+#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
+
+#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
+
+
 #if HAVE_WAIT4
 /**
  * Name of the file for writing resource utilization summaries to.
@@ -231,6 +236,11 @@ static struct GNUNET_DISK_PipeHandle *sigpipe;
  */
 static int in_shutdown;
 
+/**
+ * Return value from main
+ */
+static int global_ret;
+
 /**
  * Are we starting user services?
  */
@@ -259,6 +269,435 @@ static struct GNUNET_SERVICE_Handle *service;
 static struct GNUNET_NotificationContext *notifier;
 
 
+/**
+ * Add the given UNIX domain path as an address to the
+ * list (as the first entry).
+ *
+ * @param saddrs array to update
+ * @param saddrlens where to store the address length
+ * @param unixpath path to add
+ * @param abstract #GNUNET_YES to add an abstract UNIX domain socket.  This
+ *          parameter is ignore on systems other than LINUX
+ */
+static void
+add_unixpath (struct sockaddr **saddrs,
+              socklen_t *saddrlens,
+              const char *unixpath,
+              int abstract)
+{
+#ifdef AF_UNIX
+  struct sockaddr_un *un;
+
+  un = GNUNET_new (struct sockaddr_un);
+  un->sun_family = AF_UNIX;
+  strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
+#ifdef LINUX
+  if (GNUNET_YES == abstract)
+    un->sun_path[0] = '\0';
+#endif
+#if HAVE_SOCKADDR_UN_SUN_LEN
+  un->sun_len = (u_char) sizeof (struct sockaddr_un);
+#endif
+  *saddrs = (struct sockaddr *) un;
+  *saddrlens = sizeof (struct sockaddr_un);
+#else
+  /* this function should never be called
+   * unless AF_UNIX is defined! */
+  GNUNET_assert (0);
+#endif
+}
+
+
+/**
+ * Get the list of addresses that a server for the given service
+ * should bind to.
+ *
+ * @param service_name name of the service
+ * @param cfg configuration (which specifies the addresses)
+ * @param addrs set (call by reference) to an array of pointers to the
+ *              addresses the server should bind to and listen on; the
+ *              array will be NULL-terminated (on success)
+ * @param addr_lens set (call by reference) to an array of the lengths
+ *              of the respective `struct sockaddr` struct in the @a addrs
+ *              array (on success)
+ * @return number of addresses found on success,
+ *              #GNUNET_SYSERR if the configuration
+ *              did not specify reasonable finding information or
+ *              if it specified a hostname that could not be resolved;
+ *              #GNUNET_NO if the number of addresses configured is
+ *              zero (in this case, `*addrs` and `*addr_lens` will be
+ *              set to NULL).
+ */
+static int
+get_server_addresses (const char *service_name,
+                     const struct GNUNET_CONFIGURATION_Handle *cfg,
+                     struct sockaddr ***addrs,
+                     socklen_t ** addr_lens)
+{
+  int disablev6;
+  struct GNUNET_NETWORK_Handle *desc;
+  unsigned long long port;
+  char *unixpath;
+  struct addrinfo hints;
+  struct addrinfo *res;
+  struct addrinfo *pos;
+  struct addrinfo *next;
+  unsigned int i;
+  int resi;
+  int ret;
+  int abstract;
+  struct sockaddr **saddrs;
+  socklen_t *saddrlens;
+  char *hostname;
+
+  *addrs = NULL;
+  *addr_lens = NULL;
+  desc = NULL;
+  if (GNUNET_CONFIGURATION_have_value (cfg,
+                                      service_name,
+                                      "DISABLEV6"))
+  {
+    if (GNUNET_SYSERR ==
+        (disablev6 =
+         GNUNET_CONFIGURATION_get_value_yesno (cfg,
+                                              service_name,
+                                              "DISABLEV6")))
+      return GNUNET_SYSERR;
+  }
+  else
+    disablev6 = GNUNET_NO;
+
+  if (! disablev6)
+  {
+    /* probe IPv6 support */
+    desc = GNUNET_NETWORK_socket_create (PF_INET6,
+                                        SOCK_STREAM,
+                                        0);
+    if (NULL == desc)
+    {
+      if ( (ENOBUFS == errno) ||
+          (ENOMEM == errno) ||
+          (ENFILE == errno) ||
+          (EACCES == errno) )
+      {
+        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
+                     "socket");
+        return GNUNET_SYSERR;
+      }
+      LOG (GNUNET_ERROR_TYPE_INFO,
+           _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
+           service_name,
+          STRERROR (errno));
+      disablev6 = GNUNET_YES;
+    }
+    else
+    {
+      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
+      desc = NULL;
+    }
+  }
+
+  port = 0;
+  if (GNUNET_CONFIGURATION_have_value (cfg,
+                                      service_name,
+                                      "PORT"))
+  {
+    if (GNUNET_OK !=
+       GNUNET_CONFIGURATION_get_value_number (cfg,
+                                              service_name,
+                                              "PORT",
+                                              &port))
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR,
+           _("Require valid port number for service `%s' in configuration!\n"),
+           service_name);
+    }
+    if (port > 65535)
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR,
+           _("Require valid port number for service `%s' in configuration!\n"),
+           service_name);
+      return GNUNET_SYSERR;
+    }
+  }
+
+  if (GNUNET_CONFIGURATION_have_value (cfg,
+                                      service_name,
+                                      "BINDTO"))
+  {
+    GNUNET_break (GNUNET_OK ==
+                  GNUNET_CONFIGURATION_get_value_string (cfg,
+                                                        service_name,
+                                                         "BINDTO",
+                                                        &hostname));
+  }
+  else
+    hostname = NULL;
+
+  unixpath = NULL;
+  abstract = GNUNET_NO;
+#ifdef AF_UNIX
+  if ((GNUNET_YES ==
+       GNUNET_CONFIGURATION_have_value (cfg,
+                                       service_name,
+                                       "UNIXPATH")) &&
+      (GNUNET_OK ==
+       GNUNET_CONFIGURATION_get_value_filename (cfg,
+                                               service_name,
+                                               "UNIXPATH",
+                                               &unixpath)) &&
+      (0 < strlen (unixpath)))
+  {
+    /* probe UNIX support */
+    struct sockaddr_un s_un;
+
+    if (strlen (unixpath) >= sizeof (s_un.sun_path))
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING,
+           _("UNIXPATH `%s' too long, maximum length is %llu\n"),
+          unixpath,
+           (unsigned long long) sizeof (s_un.sun_path));
+      unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
+      LOG (GNUNET_ERROR_TYPE_INFO,
+          _("Using `%s' instead\n"),
+           unixpath);
+    }
+#ifdef LINUX
+    abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
+                                                     "TESTING",
+                                                     "USE_ABSTRACT_SOCKETS");
+    if (GNUNET_SYSERR == abstract)
+      abstract = GNUNET_NO;
+#endif
+    if ( (GNUNET_YES != abstract) &&
+        (GNUNET_OK !=
+         GNUNET_DISK_directory_create_for_file (unixpath)) )
+      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+                               "mkdir",
+                               unixpath);
+  }
+  if (NULL != unixpath)
+  {
+    desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
+    if (NULL == desc)
+    {
+      if ( (ENOBUFS == errno) ||
+          (ENOMEM == errno) ||
+          (ENFILE == errno) ||
+          (EACCES == errno) )
+      {
+        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
+        GNUNET_free_non_null (hostname);
+        GNUNET_free (unixpath);
+        return GNUNET_SYSERR;
+      }
+      LOG (GNUNET_ERROR_TYPE_INFO,
+           _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
+           service_name,
+           STRERROR (errno));
+      GNUNET_free (unixpath);
+      unixpath = NULL;
+    }
+    else
+    {
+      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
+      desc = NULL;
+    }
+  }
+#endif
+
+  if ( (0 == port) &&
+       (NULL == unixpath) )
+  {
+    if (GNUNET_YES ==
+       GNUNET_CONFIGURATION_get_value_yesno (cfg,
+                                             service_name,
+                                             "START_ON_DEMAND"))
+      LOG (GNUNET_ERROR_TYPE_ERROR,
+          _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
+          service_name);
+    GNUNET_free_non_null (hostname);
+    return GNUNET_SYSERR;
+  }
+  if (0 == port)
+  {
+    saddrs = GNUNET_new_array (2,
+                              struct sockaddr *);
+    saddrlens = GNUNET_new_array (2,
+                                 socklen_t);
+    add_unixpath (saddrs,
+                 saddrlens,
+                 unixpath,
+                 abstract);
+    GNUNET_free_non_null (unixpath);
+    GNUNET_free_non_null (hostname);
+    *addrs = saddrs;
+    *addr_lens = saddrlens;
+    return 1;
+  }
+
+  if (NULL != hostname)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Resolving `%s' since that is where `%s' will bind to.\n",
+         hostname,
+         service_name);
+    memset (&hints, 0, sizeof (struct addrinfo));
+    if (disablev6)
+      hints.ai_family = AF_INET;
+    hints.ai_protocol = IPPROTO_TCP;
+    if ((0 != (ret = getaddrinfo (hostname,
+                                 NULL,
+                                 &hints,
+                                 &res))) ||
+        (NULL == res))
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR,
+           _("Failed to resolve `%s': %s\n"),
+           hostname,
+           gai_strerror (ret));
+      GNUNET_free (hostname);
+      GNUNET_free_non_null (unixpath);
+      return GNUNET_SYSERR;
+    }
+    next = res;
+    i = 0;
+    while (NULL != (pos = next))
+    {
+      next = pos->ai_next;
+      if ((disablev6) && (pos->ai_family == AF_INET6))
+        continue;
+      i++;
+    }
+    if (0 == i)
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR,
+           _("Failed to find %saddress for `%s'.\n"),
+           disablev6 ? "IPv4 " : "",
+           hostname);
+      freeaddrinfo (res);
+      GNUNET_free (hostname);
+      GNUNET_free_non_null (unixpath);
+      return GNUNET_SYSERR;
+    }
+    resi = i;
+    if (NULL != unixpath)
+      resi++;
+    saddrs = GNUNET_new_array (resi + 1,
+                              struct sockaddr *);
+    saddrlens = GNUNET_new_array (resi + 1,
+                                 socklen_t);
+    i = 0;
+    if (NULL != unixpath)
+    {
+      add_unixpath (saddrs, saddrlens, unixpath, abstract);
+      i++;
+    }
+    next = res;
+    while (NULL != (pos = next))
+    {
+      next = pos->ai_next;
+      if ((disablev6) && (AF_INET6 == pos->ai_family))
+        continue;
+      if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
+        continue;               /* not TCP */
+      if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
+        continue;               /* huh? */
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
+           service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
+      if (AF_INET == pos->ai_family)
+      {
+        GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
+        saddrlens[i] = pos->ai_addrlen;
+        saddrs[i] = GNUNET_malloc (saddrlens[i]);
+        GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
+        ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
+      }
+      else
+      {
+        GNUNET_assert (AF_INET6 == pos->ai_family);
+        GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
+        saddrlens[i] = pos->ai_addrlen;
+        saddrs[i] = GNUNET_malloc (saddrlens[i]);
+        GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
+        ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
+      }
+      i++;
+    }
+    GNUNET_free (hostname);
+    freeaddrinfo (res);
+    resi = i;
+  }
+  else
+  {
+    /* will bind against everything, just set port */
+    if (disablev6)
+    {
+      /* V4-only */
+      resi = 1;
+      if (NULL != unixpath)
+        resi++;
+      i = 0;
+      saddrs = GNUNET_new_array (resi + 1,
+                                struct sockaddr *);
+      saddrlens = GNUNET_new_array (resi + 1,
+                                   socklen_t);
+      if (NULL != unixpath)
+      {
+        add_unixpath (saddrs, saddrlens, unixpath, abstract);
+        i++;
+      }
+      saddrlens[i] = sizeof (struct sockaddr_in);
+      saddrs[i] = GNUNET_malloc (saddrlens[i]);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+      ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
+#endif
+      ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
+      ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
+    }
+    else
+    {
+      /* dual stack */
+      resi = 2;
+      if (NULL != unixpath)
+        resi++;
+      saddrs = GNUNET_new_array (resi + 1,
+                                struct sockaddr *);
+      saddrlens = GNUNET_new_array (resi + 1,
+                                   socklen_t);
+      i = 0;
+      if (NULL != unixpath)
+      {
+        add_unixpath (saddrs,
+                     saddrlens,
+                     unixpath,
+                     abstract);
+        i++;
+      }
+      saddrlens[i] = sizeof (struct sockaddr_in6);
+      saddrs[i] = GNUNET_malloc (saddrlens[i]);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+      ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
+#endif
+      ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
+      ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
+      i++;
+      saddrlens[i] = sizeof (struct sockaddr_in);
+      saddrs[i] = GNUNET_malloc (saddrlens[i]);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+      ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
+#endif
+      ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
+      ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
+    }
+  }
+  GNUNET_free_non_null (unixpath);
+  *addrs = saddrs;
+  *addr_lens = saddrlens;
+  return resi;
+}
+
+
 /**
  * Signal our client that we will start or stop the
  * service.
@@ -278,6 +717,7 @@ signal_result (struct GNUNET_SERVICE_Client *client,
   struct GNUNET_MQ_Envelope *env;
   struct GNUNET_ARM_ResultMessage *msg;
 
+  (void) name;
   env = GNUNET_MQ_msg (msg,
                        GNUNET_MESSAGE_TYPE_ARM_RESULT);
   msg->result = htonl (result);
@@ -318,9 +758,10 @@ broadcast_status (const char *name,
                  namelen);
   if (NULL == unicast)
   {
-    GNUNET_notification_context_broadcast (notifier,
-                                           &msg->header,
-                                           GNUNET_YES);
+    if (NULL != notifier)
+      GNUNET_notification_context_broadcast (notifier,
+                                             &msg->header,
+                                             GNUNET_YES);
     GNUNET_MQ_discard (env);
   }
   else
@@ -379,18 +820,23 @@ start_process (struct ServiceList *sl,
 
   /* obtain configuration */
   if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_filename (cfg,
-                                               sl->name,
-                                               "PREFIX",
-                                               &loprefix))
+      GNUNET_CONFIGURATION_get_value_string (cfg,
+                                             sl->name,
+                                             "PREFIX",
+                                             &loprefix))
     loprefix = GNUNET_strdup (prefix_command);
+  else
+    loprefix = GNUNET_CONFIGURATION_expand_dollar (cfg,
+                                                   loprefix);
   if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_filename (cfg,
-                                               sl->name,
-                                               "OPTIONS",
-                                               &options))
+      GNUNET_CONFIGURATION_get_value_string (cfg,
+                                             sl->name,
+                                             "OPTIONS",
+                                             &options))
     options = NULL;
-
+  else
+    options = GNUNET_CONFIGURATION_expand_dollar (cfg,
+                                                  options);
   {
     char *new_options;
     char *optpos;
@@ -419,6 +865,7 @@ start_process (struct ServiceList *sl,
                        "%s %s",
                        fin_options,
                        optpos);
+      GNUNET_free (fin_options);
       GNUNET_free (optpos);
     }
     else
@@ -789,17 +1236,8 @@ static int
 check_start (void *cls,
              const struct GNUNET_ARM_Message *amsg)
 {
-  uint16_t size;
-  const char *servicename;
-
-  size = ntohs (amsg->header.size) - sizeof (struct GNUNET_ARM_Message);
-  servicename = (const char *) &amsg[1];
-  if ( (0 == size) ||
-       (servicename[size - 1] != '\0') )
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
+  (void) cls;
+  GNUNET_MQ_check_zero_termination (amsg);
   return GNUNET_OK;
 }
 
@@ -862,6 +1300,7 @@ handle_start (void *cls,
 static void
 trigger_shutdown (void *cls)
 {
+  (void) cls;
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Triggering shutdown\n");
   GNUNET_SCHEDULER_shutdown ();
@@ -880,17 +1319,8 @@ static int
 check_stop (void *cls,
             const struct GNUNET_ARM_Message *amsg)
 {
-  uint16_t size;
-  const char *servicename;
-
-  size = ntohs (amsg->header.size) - sizeof (struct GNUNET_ARM_Message);
-  servicename = (const char *) &amsg[1];
-  if ( (0 == size) ||
-       (servicename[size - 1] != '\0') )
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
+  (void) cls;
+  GNUNET_MQ_check_zero_termination (amsg);
   return GNUNET_OK;
 }
 
@@ -1059,6 +1489,7 @@ handle_test (void *cls,
   struct GNUNET_MQ_Envelope *env;
   struct GNUNET_MessageHeader *msg;
 
+  (void) message;
   env = GNUNET_MQ_msg (msg,
                        GNUNET_MESSAGE_TYPE_ARM_TEST);
   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
@@ -1106,7 +1537,7 @@ list_count (struct ServiceList *running_head)
   struct ServiceList *i;
   unsigned int res;
 
-  for (res = 0, i = running_head; i; i = i->next, res++)
+  for (res = 0, i = running_head; NULL != i; i = i->next, res++)
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "%s\n",
                i->name);
@@ -1126,6 +1557,7 @@ shutdown_task (void *cls)
   struct ServiceList *nxt;
   struct ServiceListeningInfo *sli;
 
+  (void) cls;
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "First shutdown phase\n");
   if (NULL != child_restart_task)
@@ -1197,6 +1629,7 @@ delayed_restart_task (void *cls)
   struct GNUNET_TIME_Relative lowestRestartDelay;
   struct ServiceListeningInfo *sli;
 
+  (void) cls;
   child_restart_task = NULL;
   GNUNET_assert (GNUNET_NO == in_shutdown);
   lowestRestartDelay = GNUNET_TIME_UNIT_FOREVER_REL;
@@ -1264,7 +1697,7 @@ delayed_restart_task (void *cls)
  * Task triggered whenever we receive a SIGCHLD (child
  * process died).
  *
- * @param cls closure, NULL if we need to self-restart
+ * @param cls closure, NULL
  */
 static void
 maint_child_death (void *cls)
@@ -1280,6 +1713,7 @@ maint_child_death (void *cls)
   unsigned long statusCode;
   const struct GNUNET_DISK_FileHandle *pr;
 
+  (void) cls;
   pr = GNUNET_DISK_pipe_handle (sigpipe,
                                GNUNET_DISK_PIPE_END_READ);
   child_death_task = NULL;
@@ -1439,7 +1873,21 @@ maint_child_death (void *cls)
                    statcode,
                    GNUNET_STRINGS_relative_time_to_string (pos->backoff,
                                                            GNUNET_YES));
-        /* schedule restart */
+       {
+         /* Reduce backoff based on runtime of the process,
+            so that there is a cool-down if a process actually
+            runs for a while. */
+         struct GNUNET_TIME_Relative runtime;
+         unsigned int minutes;
+
+         runtime = GNUNET_TIME_absolute_get_duration (pos->restart_at);
+         minutes = runtime.rel_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us;
+         if (minutes > 31)
+           pos->backoff = GNUNET_TIME_UNIT_ZERO;
+         else
+           pos->backoff.rel_value_us <<= minutes;
+       }
+       /* schedule restart */
         pos->restart_at = GNUNET_TIME_relative_to_absolute (pos->backoff);
         pos->backoff = GNUNET_TIME_STD_BACKOFF (pos->backoff);
         if (NULL != child_restart_task)
@@ -1507,16 +1955,16 @@ setup_service (void *cls,
   struct sockaddr **addrs;
   socklen_t *addr_lens;
   int ret;
-  unsigned int i;
 
+  (void) cls;
   if (0 == strcasecmp (section,
                        "arm"))
     return;
   if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_filename (cfg,
-                                               section,
-                                               "BINARY",
-                                               &binary))
+      GNUNET_CONFIGURATION_get_value_string (cfg,
+                                             section,
+                                             "BINARY",
+                                             &binary))
   {
     /* not a service section */
     return;
@@ -1524,11 +1972,11 @@ setup_service (void *cls,
   if ((GNUNET_YES ==
        GNUNET_CONFIGURATION_have_value (cfg,
                                         section,
-                                        "USER_SERVICE")) &&
+                                        "RUN_PER_USER")) &&
       (GNUNET_YES ==
        GNUNET_CONFIGURATION_get_value_yesno (cfg,
                                              section,
-                                             "USER_SERVICE")))
+                                             "RUN_PER_USER")))
   {
     if (GNUNET_NO == start_user)
     {
@@ -1554,7 +2002,8 @@ setup_service (void *cls,
   }
   config = NULL;
   if (( (GNUNET_OK !=
-        GNUNET_CONFIGURATION_get_value_filename (cfg, section,
+        GNUNET_CONFIGURATION_get_value_filename (cfg,
+                                                  section,
                                                   "CONFIG",
                                                   &config)) &&
        (GNUNET_OK !=
@@ -1595,7 +2044,7 @@ setup_service (void *cls,
   if (GNUNET_YES ==
       GNUNET_CONFIGURATION_get_value_yesno (cfg,
                                             section,
-                                            "FORCESTART"))
+                                            "IMMEDIATE_START"))
   {
     sl->force_start = GNUNET_YES;
     if (GNUNET_YES ==
@@ -1609,16 +2058,16 @@ setup_service (void *cls,
     if (GNUNET_YES !=
         GNUNET_CONFIGURATION_get_value_yesno (cfg,
                                               section,
-                                              "AUTOSTART"))
+                                              "START_ON_DEMAND"))
       return;
   }
-  if (0 >= (ret = GNUNET_SERVICE_get_server_addresses (section,
-                                                       cfg,
-                                                      &addrs,
-                                                       &addr_lens)))
+  if (0 >= (ret = get_server_addresses (section,
+                                       cfg,
+                                       &addrs,
+                                       &addr_lens)))
     return;
   /* this will free (or capture) addrs[i] */
-  for (i = 0; i < ret; i++)
+  for (unsigned int i = 0; i < (unsigned int) ret; i++)
     create_listen_socket (addrs[i],
                           addr_lens[i],
                           sl);
@@ -1643,6 +2092,8 @@ client_connect_cb (void *cls,
   /* All clients are considered to be of the "monitor" kind
    * (that is, they don't affect ARM shutdown).
    */
+  (void) cls;
+  (void) mq;
   GNUNET_SERVICE_client_mark_monitor (client);
   return client;
 }
@@ -1660,11 +2111,9 @@ client_disconnect_cb (void *cls,
                       struct GNUNET_SERVICE_Client *client,
                       void *app_ctx)
 {
-  struct ServiceList *sl;
-
+  (void) cls;
   GNUNET_assert (client == app_ctx);
-
-  for (sl = running_head; NULL != sl; sl = sl->next)
+  for (struct ServiceList *sl = running_head; NULL != sl; sl = sl->next)
     if (sl->killing_client == client)
       sl->killing_client = NULL;
 }
@@ -1684,6 +2133,7 @@ handle_monitor (void *cls,
 {
   struct GNUNET_SERVICE_Client *client = cls;
 
+  (void) message;
   /* FIXME: might want to start by letting monitor know about
      services that are already running */
   /* Removal is handled by the server implementation, internally. */
@@ -1699,7 +2149,7 @@ handle_monitor (void *cls,
 /**
  * Process arm requests.
  *
- * @param cls closure
+ * @param cls closure, NULL
  * @param serv the initialized service
  * @param c configuration to use
  */
@@ -1710,6 +2160,7 @@ run (void *cls,
 {
   struct ServiceList *sl;
 
+  (void) cls;
   cfg = c;
   service = serv;
   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
@@ -1743,27 +2194,32 @@ run (void *cls,
                                              "GLOBAL_PREFIX",
                                              &prefix_command))
     prefix_command = GNUNET_strdup ("");
+  else
+    prefix_command = GNUNET_CONFIGURATION_expand_dollar (cfg,
+                                                         prefix_command);
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_string (cfg,
                                              "ARM",
                                              "GLOBAL_POSTFIX",
                                              &final_option))
     final_option = GNUNET_strdup ("");
-  if (GNUNET_YES ==
-      GNUNET_CONFIGURATION_get_value_yesno (cfg,
+  else
+    final_option = GNUNET_CONFIGURATION_expand_dollar (cfg,
+                                                       final_option);
+  start_user = GNUNET_CONFIGURATION_get_value_yesno (cfg,
                                             "ARM",
-                                            "USER_ONLY"))
-  {
-    GNUNET_break (GNUNET_YES == start_user);
-    start_system = GNUNET_NO;
-  }
-  if (GNUNET_YES ==
-      GNUNET_CONFIGURATION_get_value_yesno (cfg,
+                                            "START_USER_SERVICES");
+  start_system = GNUNET_CONFIGURATION_get_value_yesno (cfg,
                                             "ARM",
-                                            "SYSTEM_ONLY"))
+                                            "START_SYSTEM_SERVICES");
+  if ( (GNUNET_NO == start_user) &&
+       (GNUNET_NO == start_system) )
   {
-    GNUNET_break (GNUNET_YES == start_system);
-    start_user = GNUNET_NO;
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+       "Please configure either START_USER_SERVICES or START_SYSTEM_SERVICES or both.\n");
+    GNUNET_SCHEDULER_shutdown ();
+    global_ret = 1;
+    return;
   }
   GNUNET_CONFIGURATION_iterate_sections (cfg,
                                          &setup_service,
@@ -1790,7 +2246,6 @@ int
 main (int argc,
       char *const *argv)
 {
-  int ret;
   struct GNUNET_SIGNAL_Context *shc_chld;
   struct GNUNET_MQ_MessageHandler handlers[] = {
     GNUNET_MQ_hd_var_size (start,
@@ -1824,7 +2279,7 @@ main (int argc,
   shc_chld =
     GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD,
                                    &sighandler_child_death);
-  ret = GNUNET_SERVICE_ruN_ (argc,
+  if ( GNUNET_OK != GNUNET_SERVICE_run_ (argc,
                              argv,
                              "arm",
                              GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN,
@@ -1832,7 +2287,8 @@ main (int argc,
                              &client_connect_cb,
                              &client_disconnect_cb,
                              NULL,
-                             handlers);
+                             handlers))
+    global_ret = 2;
 #if HAVE_WAIT4
   if (NULL != wait_file)
   {
@@ -1849,7 +2305,7 @@ main (int argc,
   shc_chld = NULL;
   GNUNET_DISK_pipe_close (sigpipe);
   sigpipe = NULL;
-  return ret;
+  return global_ret;
 }