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.
*/
static int in_shutdown;
+/**
+ * Return value from main
+ */
+static int global_ret;
+
/**
* Are we starting user services?
*/
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.
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);
"%s %s",
fin_options,
optpos);
+ GNUNET_free (fin_options);
GNUNET_free (optpos);
}
else
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;
}
static void
trigger_shutdown (void *cls)
{
+ (void) cls;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Triggering shutdown\n");
GNUNET_SCHEDULER_shutdown ();
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;
}
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),
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);
struct ServiceList *nxt;
struct ServiceListeningInfo *sli;
+ (void) cls;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"First shutdown phase\n");
if (NULL != child_restart_task)
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;
* 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)
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;
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)
struct sockaddr **addrs;
socklen_t *addr_lens;
int ret;
- unsigned int i;
+ (void) cls;
if (0 == strcasecmp (section,
"arm"))
return;
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)
{
if (GNUNET_YES ==
GNUNET_CONFIGURATION_get_value_yesno (cfg,
section,
- "FORCESTART"))
+ "IMMEDIATE_START"))
{
sl->force_start = GNUNET_YES;
if (GNUNET_YES ==
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);
/* 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;
}
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;
}
{
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. */
/**
* Process arm requests.
*
- * @param cls closure
+ * @param cls closure, NULL
* @param serv the initialized service
* @param c configuration to use
*/
{
struct ServiceList *sl;
+ (void) cls;
cfg = c;
service = serv;
GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
else
final_option = GNUNET_CONFIGURATION_expand_dollar (cfg,
final_option);
- if (GNUNET_YES ==
- GNUNET_CONFIGURATION_get_value_yesno (cfg,
+ 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,
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,
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,
&client_connect_cb,
&client_disconnect_cb,
NULL,
- handlers);
+ handlers))
+ global_ret = 2;
#if HAVE_WAIT4
if (NULL != wait_file)
{
shc_chld = NULL;
GNUNET_DISK_pipe_close (sigpipe);
sigpipe = NULL;
- return ret;
+ return global_ret;
}