remove protocol violation
[oweals/gnunet.git] / src / arm / gnunet-service-arm.c
index b672503f2ec64e7d264695e4f31bd1dead7d9a6d..1249fe0030008cc488516bfb4e272aac12b068b9 100644 (file)
@@ -36,6 +36,7 @@
  */
 #define MAX_NOTIFY_QUEUE 1024
 
+
 /**
  * List of our services.
  */
@@ -159,7 +160,7 @@ struct ServiceList
 
   /**
    * Is this service to be started by default (or did a client tell us explicitly
-   * to start it)?  GNUNET_NO if the service is started only upon 'accept' on a
+   * to start it)?  #GNUNET_NO if the service is started only upon 'accept' on a
    * listen socket or possibly explicitly by a client changing the value.
    */
   int is_default;
@@ -217,6 +218,16 @@ static struct GNUNET_DISK_PipeHandle *sigpipe;
  */
 static int in_shutdown;
 
+/**
+ * Are we starting user services?
+ */
+static int start_user = GNUNET_YES;
+
+/**
+ * Are we starting system services?
+ */
+static int start_system = GNUNET_YES;
+
 /**
  * Handle to our server instance.  Our server is a bit special in that
  * its service is not immediately stopped once we get a shutdown
@@ -235,15 +246,13 @@ static struct GNUNET_SERVER_Handle *server;
 static struct GNUNET_SERVER_NotificationContext *notifier;
 
 
-#include "do_start_process.c"
-
 /**
  * Transmit a status result message.
  *
- * @param cls pointer to "unit16_t*" with message type
- * @param size number of bytes available in buf
+ * @param cls a `unit16_t *` with message type
+ * @param size number of bytes available in @a buf
  * @param buf where to copy the message, NULL on error
- * @return number of bytes copied to buf
+ * @return number of bytes copied to @a buf
  */
 static size_t
 write_result (void *cls, size_t size, void *buf)
@@ -251,7 +260,7 @@ write_result (void *cls, size_t size, void *buf)
   struct GNUNET_ARM_ResultMessage *msg = cls;
   size_t msize;
 
-  if (buf == NULL)
+  if (NULL == buf)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                _("Could not send status result to client\n"));
@@ -259,7 +268,8 @@ write_result (void *cls, size_t size, void *buf)
     return 0;                  /* error, not much we can do */
   }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Sending status response %u to client\n", (unsigned int) msg->result);
+             "Sending status response %u to client\n",
+             (unsigned int) msg->result);
   msize = msg->arm_msg.header.size;
   GNUNET_assert (size >= msize);
   msg->arm_msg.header.size = htons (msg->arm_msg.header.size);
@@ -271,35 +281,36 @@ write_result (void *cls, size_t size, void *buf)
   return msize;
 }
 
+
 /**
  * Transmit the list of running services.
- * 
- * @param cls pointer to struct GNUNET_ARM_ListResultMessage with the message
- * @param size number of bytes available in buf
+ *
+ * @param cls pointer to `struct GNUNET_ARM_ListResultMessage` with the message
+ * @param size number of bytes available in @a buf
  * @param buf where to copy the message, NULL on error
- * @return number of bytes copied to buf
+ * @return number of bytes copied to @a buf
  */
 static size_t
 write_list_result (void *cls, size_t size, void *buf)
 {
   struct GNUNET_ARM_ListResultMessage *msg = cls;
   size_t rslt_size;
-  
-  if (buf == NULL)
+
+  if (NULL == buf)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                 _("Could not send list result to client\n"));
     GNUNET_free (msg);
     return 0;                   /* error, not much we can do */
   }
-  
+
   rslt_size = msg->arm_msg.header.size;
   GNUNET_assert (size >= rslt_size);
   msg->arm_msg.header.size = htons (msg->arm_msg.header.size);
   msg->arm_msg.header.type = htons (msg->arm_msg.header.type);
   msg->arm_msg.request_id = GNUNET_htonll (msg->arm_msg.request_id);
   msg->count = htons (msg->count);
-  
+
   memcpy (buf, msg, rslt_size);
   GNUNET_free (msg);
   return rslt_size;
@@ -317,8 +328,10 @@ write_list_result (void *cls, size_t size, void *buf)
  * @return NULL if it was not found
  */
 static void
-signal_result (struct GNUNET_SERVER_Client *client, const char *name,
-              uint64_t request_id, enum GNUNET_ARM_Result result)
+signal_result (struct GNUNET_SERVER_Client *client,
+              const char *name,
+              uint64_t request_id,
+              enum GNUNET_ARM_Result result)
 {
   struct GNUNET_ARM_ResultMessage *msg;
   size_t msize;
@@ -331,7 +344,8 @@ signal_result (struct GNUNET_SERVER_Client *client, const char *name,
   msg->arm_msg.request_id = request_id;
 
   GNUNET_SERVER_notify_transmit_ready (client, msize,
-      GNUNET_TIME_UNIT_FOREVER_REL, write_result, msg);
+                                      GNUNET_TIME_UNIT_FOREVER_REL,
+                                      write_result, msg);
 }
 
 
@@ -344,8 +358,9 @@ signal_result (struct GNUNET_SERVER_Client *client, const char *name,
  *                otherwise, send to all clients in the notifier
  */
 static void
-broadcast_status (const char *name, enum GNUNET_ARM_ServiceStatus status,
-    struct GNUNET_SERVER_Client *unicast)
+broadcast_status (const char *name,
+                 enum GNUNET_ARM_ServiceStatus status,
+                 struct GNUNET_SERVER_Client *unicast)
 {
   struct GNUNET_ARM_StatusMessage *msg;
   size_t namelen;
@@ -381,7 +396,9 @@ broadcast_status (const char *name, enum GNUNET_ARM_ServiceStatus status,
  *                   being started. 0 if starting was not requested.
  */
 static void
-start_process (struct ServiceList *sl, struct GNUNET_SERVER_Client *client, uint64_t request_id)
+start_process (struct ServiceList *sl,
+               struct GNUNET_SERVER_Client *client,
+               uint64_t request_id)
 {
   char *loprefix;
   char *options;
@@ -395,6 +412,7 @@ start_process (struct ServiceList *sl, struct GNUNET_SERVER_Client *client, uint
   SOCKTYPE *lsocks;
   unsigned int ls;
   char *binary;
+  char *quotedbinary;
 
   /* calculate listen socket list */
   lsocks = NULL;
@@ -467,44 +485,59 @@ start_process (struct ServiceList *sl, struct GNUNET_SERVER_Client *client, uint
              "Starting service `%s' using binary `%s' and configuration `%s'\n",
              sl->name, sl->binary, sl->config);
   binary = GNUNET_OS_get_libexec_binary_path (sl->binary);
+  GNUNET_asprintf (&quotedbinary,
+                  "\"%s\"",
+                  binary);
+
   GNUNET_assert (NULL == sl->proc);
   if (GNUNET_YES == use_debug)
   {
     if (NULL == sl->config)
       sl->proc =
-       do_start_process (sl->pipe_control, GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
-                         lsocks, loprefix, binary, "-L",
-                         "DEBUG", options, NULL);
+       GNUNET_OS_start_process_s (sl->pipe_control,
+                                   GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
+                                   lsocks, loprefix, quotedbinary, "-L",
+                                   "DEBUG", options, NULL);
     else
       sl->proc =
-       do_start_process (sl->pipe_control, GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
-                         lsocks, loprefix, binary, "-c", sl->config, "-L",
-                         "DEBUG", options, NULL);
+          GNUNET_OS_start_process_s (sl->pipe_control,
+                                     GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
+                                     lsocks, loprefix, quotedbinary, "-c",
+                                     sl->config, "-L",
+                                     "DEBUG", options, NULL);
   }
   else
   {
     if (NULL == sl->config)
       sl->proc =
-       do_start_process (sl->pipe_control, GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
-                         lsocks, loprefix, binary, 
-                         options, NULL);
+          GNUNET_OS_start_process_s (sl->pipe_control,
+                                     GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
+                                     lsocks, loprefix, quotedbinary,
+                                     options, NULL);
     else
       sl->proc =
-       do_start_process (sl->pipe_control, GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
-                         lsocks, loprefix, binary, "-c", sl->config,
-                         options, NULL);
+          GNUNET_OS_start_process_s (sl->pipe_control,
+                                     GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
+                                     lsocks, loprefix, quotedbinary, "-c",
+                                     sl->config, options, NULL);
   }
   GNUNET_free (binary);
+  GNUNET_free (quotedbinary);
   if (sl->proc == NULL)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to start service `%s'\n"),
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                _("Failed to start service `%s'\n"),
                sl->name);
     if (client)
-      signal_result (client, sl->name, request_id, GNUNET_ARM_RESULT_START_FAILED);
+      signal_result (client,
+                     sl->name,
+                     request_id,
+                     GNUNET_ARM_RESULT_START_FAILED);
   }
   else
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting service `%s'\n"),
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                _("Starting service `%s'\n"),
                sl->name);
     broadcast_status (sl->name, GNUNET_ARM_SERVICE_STARTING, NULL);
     if (client)
@@ -544,7 +577,7 @@ find_service (const char *name)
  * First connection has come to the listening socket associated with the service,
  * create the service in order to relay the incoming connection to it
  *
- * @param cls callback data, struct ServiceListeningInfo describing a listen socket
+ * @param cls callback data, `struct ServiceListeningInfo` describing a listen socket
  * @param tc context
  */
 static void
@@ -566,7 +599,7 @@ accept_connection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  * wait for the first incoming connection to it
  *
  * @param sa address associated with the service
- * @param addr_len length of sa
+ * @param addr_len length of @a sa
  * @param sl service entry for the service in question
  */
 static void
@@ -576,34 +609,38 @@ create_listen_socket (struct sockaddr *sa, socklen_t addr_len,
   static int on = 1;
   struct GNUNET_NETWORK_Handle *sock;
   struct ServiceListeningInfo *sli;
+#ifndef WINDOWS
+  int match_uid;
+  int match_gid;
+#endif
 
   switch (sa->sa_family)
-    {
-    case AF_INET:
-      sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0);
-      break;
-    case AF_INET6:
-      sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
-      break;
-    case AF_UNIX:
-      if (strcmp (GNUNET_a2s (sa, addr_len), "@") == 0)        /* Do not bind to blank UNIX path! */
-       return;
-      sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
-      break;
-    default:
-      GNUNET_break (0);
-      sock = NULL;
-      errno = EAFNOSUPPORT;
-      break;
-    }
-  if (NULL == sock)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Unable to create socket for service `%s': %s\n"),
-                 sl->name, STRERROR (errno));
-      GNUNET_free (sa);
+  {
+  case AF_INET:
+    sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0);
+    break;
+  case AF_INET6:
+    sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
+    break;
+  case AF_UNIX:
+    if (strcmp (GNUNET_a2s (sa, addr_len), "@") == 0)  /* Do not bind to blank UNIX path! */
       return;
-    }
+    sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
+    break;
+  default:
+    GNUNET_break (0);
+    sock = NULL;
+    errno = EAFNOSUPPORT;
+    break;
+  }
+  if (NULL == sock)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                _("Unable to create socket for service `%s': %s\n"),
+                sl->name, STRERROR (errno));
+    GNUNET_free (sa);
+    return;
+  }
   if (GNUNET_NETWORK_socket_setsockopt
       (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
@@ -616,28 +653,48 @@ create_listen_socket (struct sockaddr *sa, socklen_t addr_len,
                         "setsockopt");
 #endif
 
-  if (GNUNET_NETWORK_socket_bind
-      (sock, (const struct sockaddr *) sa, addr_len) != GNUNET_OK)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                 _
-                 ("Unable to bind listening socket for service `%s' to address `%s': %s\n"),
-                 sl->name, GNUNET_a2s (sa, addr_len), STRERROR (errno));
-      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
-      GNUNET_free (sa);
-      return;
-    }
+  if (GNUNET_OK !=
+      GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) sa, addr_len))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                _
+                ("Unable to bind listening socket for service `%s' to address `%s': %s\n"),
+                sl->name, GNUNET_a2s (sa, addr_len), STRERROR (errno));
+    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
+    GNUNET_free (sa);
+    return;
+  }
+#ifndef WINDOWS
+  if ((AF_UNIX == sa->sa_family)
+#ifdef LINUX
+      /* Permission settings are not required when abstract sockets are used */
+      && ('\0' != ((const struct sockaddr_un *)sa)->sun_path[0])
+#endif      
+      )
+  {
+    match_uid =
+      GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name,
+                                            "UNIX_MATCH_UID");
+    match_gid =
+      GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name,
+                                            "UNIX_MATCH_GID");
+    GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sa)->sun_path,
+                                 match_uid,
+                                 match_gid);
+
+  }
+#endif
   if (GNUNET_NETWORK_socket_listen (sock, 5) != GNUNET_OK)
-    {
-      GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen");
-      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
-      GNUNET_free (sa);
-      return;
-    }
+  {
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen");
+    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
+    GNUNET_free (sa);
+    return;
+  }
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
              _("ARM now monitors connections to service `%s' at `%s'\n"),
              sl->name, GNUNET_a2s (sa, addr_len));
-  sli = GNUNET_malloc (sizeof (struct ServiceListeningInfo));
+  sli = GNUNET_new (struct ServiceListeningInfo);
   sli->service_addr = sa;
   sli->service_addr_len = addr_len;
   sli->listen_socket = sock;
@@ -674,8 +731,8 @@ free_service (struct ServiceList *sl)
  * @param cls closure (always NULL)
  * @param client identification of the client
  * @param message the actual message
- * @return GNUNET_OK to keep the connection open,
- *         GNUNET_SYSERR to close it (signal serious error)
+ * @return #GNUNET_OK to keep the connection open,
+ *         #GNUNET_SYSERR to close it (signal serious error)
  */
 static void
 handle_start (void *cls, struct GNUNET_SERVER_Client *client,
@@ -687,37 +744,40 @@ handle_start (void *cls, struct GNUNET_SERVER_Client *client,
   uint64_t request_id;
   struct GNUNET_ARM_Message *amsg;
 
-  amsg = (struct GNUNET_ARM_Message *) message;  
+  amsg = (struct GNUNET_ARM_Message *) message;
   request_id = GNUNET_ntohll (amsg->request_id);
   size = ntohs (amsg->header.size);
   size -= sizeof (struct GNUNET_ARM_Message);
   servicename = (const char *) &amsg[1];
   if ((size == 0) || (servicename[size - 1] != '\0'))
-    {
-      GNUNET_break (0);
-      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-      return;
-    }
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
   if (GNUNET_YES == in_shutdown)
-    {
-      signal_result (client, servicename, request_id, GNUNET_ARM_RESULT_IN_SHUTDOWN);
-      GNUNET_SERVER_receive_done (client, GNUNET_OK);
-      return;
-    }
+  {
+    signal_result (client, servicename, request_id,
+                  GNUNET_ARM_RESULT_IN_SHUTDOWN);
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    return;
+  }
   sl = find_service (servicename);
   if (NULL == sl)
-    {
-      signal_result (client, servicename, request_id, GNUNET_ARM_RESULT_IS_NOT_KNOWN);
-      GNUNET_SERVER_receive_done (client, GNUNET_OK);
-      return;
-    }
+  {
+    signal_result (client, servicename, request_id,
+                  GNUNET_ARM_RESULT_IS_NOT_KNOWN);
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    return;
+  }
   sl->is_default = GNUNET_YES;
-  if (sl->proc != NULL)
-    {
-      signal_result (client, servicename, request_id, GNUNET_ARM_RESULT_IS_STARTED_ALREADY);
-      GNUNET_SERVER_receive_done (client, GNUNET_OK);
-      return;
-    }
+  if (NULL != sl->proc)
+  {
+    signal_result (client, servicename, request_id,
+                  GNUNET_ARM_RESULT_IS_STARTED_ALREADY);
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    return;
+  }
   start_process (sl, client, request_id);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
@@ -743,8 +803,8 @@ trigger_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  * @param cls closure (always NULL)
  * @param client identification of the client
  * @param message the actual message
- * @return GNUNET_OK to keep the connection open,
- *         GNUNET_SYSERR to close it (signal serious error)
+ * @return #GNUNET_OK to keep the connection open,
+ *         #GNUNET_SYSERR to close it (signal serious error)
  */
 static void
 handle_stop (void *cls, struct GNUNET_SERVER_Client *client,
@@ -756,7 +816,7 @@ handle_stop (void *cls, struct GNUNET_SERVER_Client *client,
   uint64_t request_id;
   struct GNUNET_ARM_Message *amsg;
 
-  amsg = (struct GNUNET_ARM_Message *) message;  
+  amsg = (struct GNUNET_ARM_Message *) message;
   request_id = GNUNET_ntohll (amsg->request_id);
   size = ntohs (amsg->header.size);
   size -= sizeof (struct GNUNET_ARM_Message);
@@ -768,7 +828,8 @@ handle_stop (void *cls, struct GNUNET_SERVER_Client *client,
       return;
     }
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-             _("Preparing to stop `%s'\n"), servicename);
+             _("Preparing to stop `%s'\n"),
+             servicename);
   if (0 == strcasecmp (servicename, "arm"))
   {
     broadcast_status (servicename, GNUNET_ARM_SERVICE_STOPPING, NULL);
@@ -793,29 +854,29 @@ handle_stop (void *cls, struct GNUNET_SERVER_Client *client,
       GNUNET_SERVER_receive_done (client, GNUNET_OK);
       return;
     }
-  if (sl->killing_client != NULL)
-    {
-      /* killing already in progress */
-      signal_result (client, servicename, request_id,
-          GNUNET_ARM_RESULT_IS_STOPPING_ALREADY);
-      GNUNET_SERVER_receive_done (client, GNUNET_OK);
-      return;
-    }
-  if (sl->proc == NULL)
-    {
-      /* process is down */
-      signal_result (client, servicename, request_id,
-          GNUNET_ARM_RESULT_IS_STOPPED_ALREADY);
-      GNUNET_SERVER_receive_done (client, GNUNET_OK);
-      return;
-    }
+  if (NULL != sl->killing_client)
+  {
+    /* killing already in progress */
+    signal_result (client, servicename, request_id,
+                  GNUNET_ARM_RESULT_IS_STOPPING_ALREADY);
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    return;
+  }
+  if (NULL == sl->proc)
+  {
+    /* process is down */
+    signal_result (client, servicename, request_id,
+                  GNUNET_ARM_RESULT_IS_STOPPED_ALREADY);
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    return;
+  }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Sending kill signal to service `%s', waiting for process to die.\n",
              servicename);
   broadcast_status (servicename, GNUNET_ARM_SERVICE_STOPPING, NULL);
   /* no signal_start - only when it's STOPPED */
   sl->killed_at = GNUNET_TIME_absolute_get ();
-  if (0 != GNUNET_OS_process_kill (sl->proc, SIGTERM))
+  if (0 != GNUNET_OS_process_kill (sl->proc, GNUNET_TERM_SIG))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
   sl->killing_client = client;
   sl->killing_client_request_id = request_id;
@@ -823,6 +884,7 @@ handle_stop (void *cls, struct GNUNET_SERVER_Client *client,
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
+
 /**
  * Handle LIST-message.
  *
@@ -840,17 +902,18 @@ handle_list (void *cls, struct GNUNET_SERVER_Client *client,
   size_t total_size;
   struct ServiceList *sl;
   uint16_t count;
-  
+
   if (NULL == client)
     return;
-  
+
   request = (struct GNUNET_ARM_Message *) message;
+  GNUNET_break (0 == ntohl (request->reserved));
   count = 0;
   string_list_size = 0;
   /* first count the running processes get their name's size */
-  for (sl = running_head; sl != NULL; sl = sl->next)
+  for (sl = running_head; NULL != sl; sl = sl->next)
   {
-    if (sl->proc != NULL)
+    if (NULL != sl->proc)
     {
       string_list_size += strlen (sl->name);
       string_list_size += strlen (sl->binary);
@@ -859,32 +922,33 @@ handle_list (void *cls, struct GNUNET_SERVER_Client *client,
     }
   }
 
-  total_size = sizeof (struct GNUNET_ARM_ListResultMessage) 
+  total_size = sizeof (struct GNUNET_ARM_ListResultMessage)
                + string_list_size;
   msg = GNUNET_malloc (total_size);
   msg->arm_msg.header.size = total_size;
   msg->arm_msg.header.type = GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT;
+  msg->arm_msg.reserved = htonl (0);
   msg->arm_msg.request_id = GNUNET_ntohll (request->request_id);
   msg->count = count;
-  
+
   char *pos = (char *)&msg[1];
-  for (sl = running_head; sl != NULL; sl = sl->next) 
+  for (sl = running_head; NULL != sl; sl = sl->next)
   {
-    if (sl->proc != NULL)
+    if (NULL != sl->proc)
     {
       size_t s = strlen (sl->name) + strlen (sl->binary) + 4;
-      GNUNET_snprintf(pos, s, "%s (%s)", sl->name, sl->binary);
+      GNUNET_snprintf (pos, s, "%s (%s)", sl->name, sl->binary);
       pos += s;
     }
   }
-  
   GNUNET_SERVER_notify_transmit_ready (client,
                                        total_size,
                                        GNUNET_TIME_UNIT_FOREVER_REL,
-                                       write_list_result, msg);
+                                       &write_list_result, msg);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
+
 /**
  * We are done with everything.  Stop remaining
  * tasks, signal handler and the server.
@@ -910,16 +974,27 @@ do_shutdown ()
     }
 }
 
-unsigned int
+
+/**
+ * Count how many services are still active.
+ *
+ * @param running_head list of services
+ * @return number of active services found
+ */
+static unsigned int
 list_count (struct ServiceList *running_head)
 {
   struct ServiceList *i;
   unsigned int res = 0;
+
   for (res = 0, i = running_head; i; i = i->next, res++)
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s\n", i->name);
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+               "%s\n",
+               i->name);
   return res;
 }
 
+
 /**
  * Task run for shutdown.
  *
@@ -933,7 +1008,8 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   struct ServiceList *nxt;
   struct ServiceListeningInfo *sli;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "First shutdown phase\n");
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "First shutdown phase\n");
   if (GNUNET_SCHEDULER_NO_TASK != child_restart_task)
   {
     GNUNET_SCHEDULER_cancel (child_restart_task);
@@ -965,10 +1041,11 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     nxt = pos->next;
     if (pos->proc != NULL)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stopping service `%s'\n",
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                 "Stopping service `%s'\n",
                  pos->name);
       pos->killed_at = GNUNET_TIME_absolute_get ();
-      if (0 != GNUNET_OS_process_kill (pos->proc, SIGTERM))
+      if (0 != GNUNET_OS_process_kill (pos->proc, GNUNET_TERM_SIG))
        GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
     }
     else
@@ -981,7 +1058,8 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     do_shutdown ();
   else
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-        "Delaying shutdown, have %u childs still running\n", list_count (running_head));
+               "Delaying shutdown, have %u childs still running\n",
+               list_count (running_head));
 }
 
 
@@ -1012,8 +1090,7 @@ delayed_restart_task (void *cls,
     if (NULL != sl->proc)
       continue;
     /* service is currently not running */
-    if (GNUNET_TIME_absolute_get_remaining (sl->restart_at).rel_value ==
-       0)
+    if (0 == GNUNET_TIME_absolute_get_remaining (sl->restart_at).rel_value_us)
     {
       /* restart is now allowed */
       if (sl->is_default)
@@ -1046,14 +1123,14 @@ delayed_restart_task (void *cls,
                                  (sl->restart_at));
     }
   }
-  if (lowestRestartDelay.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
+  if (lowestRestartDelay.rel_value_us != GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Will restart process in %s\n",
                GNUNET_STRINGS_relative_time_to_string (lowestRestartDelay, GNUNET_YES));
     child_restart_task =
       GNUNET_SCHEDULER_add_delayed_with_priority (lowestRestartDelay,
-                                                 GNUNET_SCHEDULER_PRIORITY_IDLE, 
+                                                 GNUNET_SCHEDULER_PRIORITY_IDLE,
                                                  &delayed_restart_task, NULL);
   }
 }
@@ -1126,7 +1203,7 @@ maint_child_death (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
        statstr = _( /* process termination method */ "unknown");
        statcode = 0;
       }
-      if (0 != pos->killed_at.abs_value)
+      if (0 != pos->killed_at.abs_value_us)
       {
        GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                    _("Service `%s' took %s to terminate\n"),
@@ -1143,21 +1220,13 @@ maint_child_death (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
         GNUNET_SERVER_client_drop (pos->killing_client);
         pos->killing_client = NULL;
         pos->killing_client_request_id = 0;
-        /* process can still be re-started on-demand, ensure it is re-started if there is demand */
-        for (sli = pos->listen_head; NULL != sli; sli = sli->next)
-        {
-          GNUNET_break (GNUNET_SCHEDULER_NO_TASK == sli->accept_task);
-          sli->accept_task =
-              GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
-                  sli->listen_socket, &accept_connection, sli);
-        }
       }
       if (GNUNET_YES != in_shutdown)
       {
         if ((statusType == GNUNET_OS_PROCESS_EXITED) && (statcode == 0))
         {
           /* process terminated normally, allow restart at any time */
-          pos->restart_at.abs_value = 0;
+          pos->restart_at.abs_value_us = 0;
           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               _("Service `%s' terminated normally, will restart at any time\n"),
               pos->name);
@@ -1227,7 +1296,7 @@ sighandler_child_death ()
  *
  * @param cls unused
  * @param section a section in the configuration file
- * @return GNUNET_OK (continue)
+ * @return #GNUNET_OK (continue)
  */
 static void
 setup_service (void *cls, const char *section)
@@ -1245,15 +1314,35 @@ setup_service (void *cls, const char *section)
     return;
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_string (cfg, section, "BINARY", &binary))
+  {
+    /* not a service section */
+    return;
+  }
+  if ((GNUNET_YES ==
+       GNUNET_CONFIGURATION_have_value (cfg, section, "USER_SERVICE")) &&
+      (GNUNET_YES ==
+       GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "USER_SERVICE")))
+  {
+    if (GNUNET_NO == start_user)
     {
-      /* not a service section */
-      return;
+      GNUNET_free (binary);
+      return; /* user service, and we don't deal with those */
+    }
+  }
+  else
+  {
+    if (GNUNET_NO == start_system)
+    {
+      GNUNET_free (binary);
+      return; /* system service, and we don't deal with those */
     }
+  }
   sl = find_service (section);
   if (NULL != sl)
   {
     /* got the same section twice!? */
     GNUNET_break (0);
+    GNUNET_free (binary);
     return;
   }
   config = NULL;
@@ -1267,14 +1356,14 @@ setup_service (void *cls, const char *section)
   {
     if (NULL != config)
     {
-      GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, 
+      GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
                                 section, "CONFIG",
                                 STRERROR (errno));
       GNUNET_free (config);
       config = NULL;
     }
   }
-  sl = GNUNET_malloc (sizeof (struct ServiceList));
+  sl = GNUNET_new (struct ServiceList);
   sl->name = GNUNET_strdup (section);
   sl->binary = binary;
   sl->config = config;
@@ -1285,8 +1374,9 @@ setup_service (void *cls, const char *section)
 #else
   if (GNUNET_CONFIGURATION_have_value (cfg, section, "PIPECONTROL"))
     sl->pipe_control = GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "PIPECONTROL");
-#endif  
+#endif
   GNUNET_CONTAINER_DLL_insert (running_head, running_tail, sl);
+
   if (GNUNET_YES !=
       GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "AUTOSTART"))
     return;
@@ -1317,14 +1407,15 @@ handle_client_connecting (void *cls, struct GNUNET_SERVER_Client *client)
     GNUNET_SERVER_client_mark_monitor (client);
 }
 
+
 /**
  * Handle MONITOR-message.
  *
  * @param cls closure (always NULL)
  * @param client identification of the client
  * @param message the actual message
- * @return GNUNET_OK to keep the connection open,
- *         GNUNET_SYSERR to close it (signal serious error)
+ * @return #GNUNET_OK to keep the connection open,
+ *         #GNUNET_SYSERR to close it (signal serious error)
  */
 static void
 handle_monitor (void *cls, struct GNUNET_SERVER_Client *client,
@@ -1339,6 +1430,7 @@ handle_monitor (void *cls, struct GNUNET_SERVER_Client *client,
   }
 }
 
+
 /**
  * Process arm requests.
  *
@@ -1353,9 +1445,9 @@ run (void *cls, struct GNUNET_SERVER_Handle *serv,
   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
     {&handle_start, NULL, GNUNET_MESSAGE_TYPE_ARM_START, 0},
     {&handle_stop, NULL, GNUNET_MESSAGE_TYPE_ARM_STOP, 0},
-    {&handle_monitor, NULL, GNUNET_MESSAGE_TYPE_ARM_MONITOR, 
+    {&handle_monitor, NULL, GNUNET_MESSAGE_TYPE_ARM_MONITOR,
      sizeof (struct GNUNET_MessageHeader)},
-    {&handle_list, NULL, GNUNET_MESSAGE_TYPE_ARM_LIST, 
+    {&handle_list, NULL, GNUNET_MESSAGE_TYPE_ARM_LIST,
      sizeof (struct GNUNET_ARM_Message)},
     {NULL, NULL, 0, 0}
   };
@@ -1365,8 +1457,9 @@ run (void *cls, struct GNUNET_SERVER_Handle *serv,
 
   cfg = c;
   server = serv;
-  GNUNET_assert (serv != NULL);
-  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
+  GNUNET_assert (NULL != serv);
+  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+                                &shutdown_task,
                                NULL);
   child_death_task =
     GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
@@ -1382,42 +1475,54 @@ run (void *cls, struct GNUNET_SERVER_Handle *serv,
       GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "GLOBAL_POSTFIX",
                                             &final_option))
     final_option = GNUNET_strdup ("");
-
+  if (GNUNET_YES ==
+      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, "ARM", "SYSTEM_ONLY"))
+  {
+    GNUNET_break (GNUNET_YES == start_system);
+    start_user = GNUNET_NO;
+  }
   GNUNET_CONFIGURATION_iterate_sections (cfg, &setup_service, NULL);
 
   /* start default services... */
   if (GNUNET_OK ==
-      GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "DEFAULTSERVICES",
+      GNUNET_CONFIGURATION_get_value_string (cfg,
+                                             "ARM",
+                                             "DEFAULTSERVICES",
                                             &defaultservices))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                _("Starting default services `%s'\n"),
+                defaultservices);
+    if (0 < strlen (defaultservices))
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                 _("Starting default services `%s'\n"), defaultservices);
-      if (0 < strlen (defaultservices))
-       {
-         for (pos = strtok (defaultservices, " "); NULL != pos;
-              pos = strtok (NULL, " "))
-           {
-             sl = find_service (pos);
-             if (NULL == sl)
-               {
-                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                             _
-                             ("Default service `%s' not configured correctly!\n"),
-                             pos);
-                 continue;
-               }
-             sl->is_default = GNUNET_YES;
-             start_process (sl, NULL, 0);
-           }
-       }
-      GNUNET_free (defaultservices);
+      for (pos = strtok (defaultservices, " "); NULL != pos;
+           pos = strtok (NULL, " "))
+      {
+        sl = find_service (pos);
+        if (NULL == sl)
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                      _("Default service `%s' not configured correctly!\n"),
+                      pos);
+          continue;
+        }
+        sl->is_default = GNUNET_YES;
+        start_process (sl, NULL, 0);
+      }
     }
+    GNUNET_free (defaultservices);
+  }
   else
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                 _
-                 ("No default services configured, GNUnet will not really start right now.\n"));
-    }
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                _("No default services configured, GNUnet will not really start right now.\n"));
+  }
 
   notifier =
       GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE);
@@ -1446,7 +1551,7 @@ main (int argc, char *const *argv)
     GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
   ret =
     (GNUNET_OK ==
-     GNUNET_SERVICE_run (argc, argv, "arm", 
+     GNUNET_SERVICE_run (argc, argv, "arm",
                         GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN, &run, NULL)) ? 0 : 1;
   GNUNET_SIGNAL_handler_uninstall (shc_chld);
   shc_chld = NULL;