-Merge branch 'master' of ssh://gnunet.org/gnunet into gsoc2018/rest_api
[oweals/gnunet.git] / src / util / program.c
index 930b934229036139c9228f82283ec07d5936c42d..2a9b4fac9c935153778d17386473e984050afa60 100644 (file)
@@ -1,21 +1,19 @@
 /*
      This file is part of GNUnet.
-     (C) 2009 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2009-2013 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 PURPROSE.  See the GNU
-     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., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
+     Affero General Public License for more details.
+    
+     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/>.
 */
 
 /**
 #include "gnunet_util_lib.h"
 #include "gnunet_resolver_service.h"
 #include "gnunet_constants.h"
+#include "speedup.h"
 #include <gcrypt.h>
 
-#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
+#define LOG(kind,...) GNUNET_log_from (kind, "util-program", __VA_ARGS__)
 
-#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
+#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-program", syscall, filename)
 
 /**
  * Context for the command.
@@ -55,7 +54,7 @@ struct CommandContext
   GNUNET_PROGRAM_Main task;
 
   /**
-   * Closure for task.
+   * Closure for @e task.
    */
   void *task_cls;
 
@@ -66,11 +65,16 @@ struct CommandContext
 
 };
 
-int
-GNUNET_SPEEDUP_start_ (const struct GNUNET_CONFIGURATION_Handle *cfg);
 
-int
-GNUNET_SPEEDUP_stop_ (void);
+/**
+ * task run when the scheduler shuts down
+ */
+static void
+shutdown_task (void *cls)
+{
+  (void) cls;
+  GNUNET_SPEEDUP_stop_ ();
+}
 
 
 /**
@@ -78,13 +82,12 @@ GNUNET_SPEEDUP_stop_ (void);
  * program.  Runs the program-specific main task.
  */
 static void
-program_main (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+program_main (void *cls)
 {
   struct CommandContext *cc = cls;
 
-  if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
-    return;
   GNUNET_SPEEDUP_start_(cc->cfg);
+  GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
   GNUNET_RESOLVER_connect (cc->cfg);
   cc->task (cc->task_cls, cc->args, cc->cfgfile, cc->cfg);
 }
@@ -121,23 +124,26 @@ cmd_sorter (const void *a1, const void *a2)
  * Run a standard GNUnet command startup sequence (initialize loggers
  * and configuration, parse options).
  *
- * @param argc number of command line arguments
+ * @param argc number of command line arguments in @a argv
  * @param argv command line arguments
  * @param binaryName our expected name
  * @param binaryHelp help text for the program
  * @param options command line options
  * @param task main function to run
- * @param task_cls closure for task
- * @param run_without_scheduler GNUNET_NO start the scheduler, GNUNET_YES do not
+ * @param task_cls closure for @a task
+ * @param run_without_scheduler #GNUNET_NO start the scheduler, #GNUNET_YES do not
  *        start the scheduler just run the main task
- * @return GNUNET_SYSERR on error, GNUNET_OK on success
+ * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
  */
 int
-GNUNET_PROGRAM_run2 (int argc, char *const *argv, const char *binaryName,
-                    const char *binaryHelp,
-                    const struct GNUNET_GETOPT_CommandLineOption *options,
-                    GNUNET_PROGRAM_Main task, void *task_cls,
-                    int run_without_scheduler)
+GNUNET_PROGRAM_run2 (int argc,
+                    char *const *argv,
+                    const char *binaryName,
+                     const char *binaryHelp,
+                     const struct GNUNET_GETOPT_CommandLineOption *options,
+                     GNUNET_PROGRAM_Main task,
+                    void *task_cls,
+                     int run_without_scheduler)
 {
   struct CommandContext cc;
 #if ENABLE_NLS
@@ -153,13 +159,12 @@ GNUNET_PROGRAM_run2 (int argc, char *const *argv, const char *binaryName,
   unsigned long long skew_variance;
   long long clock_offset;
   struct GNUNET_CONFIGURATION_Handle *cfg;
-
   struct GNUNET_GETOPT_CommandLineOption defoptions[] = {
-    GNUNET_GETOPT_OPTION_CFG_FILE (&cc.cfgfile),
-    GNUNET_GETOPT_OPTION_HELP (binaryHelp),
-    GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev),
-    GNUNET_GETOPT_OPTION_LOGFILE (&logfile),
-    GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION)
+    GNUNET_GETOPT_option_cfgfile (&cc.cfgfile),
+    GNUNET_GETOPT_option_help (binaryHelp),
+    GNUNET_GETOPT_option_loglevel (&loglev),
+    GNUNET_GETOPT_option_logfile (&logfile),
+    GNUNET_GETOPT_option_version (PACKAGE_VERSION " " VCS_VERSION)
   };
   struct GNUNET_GETOPT_CommandLineOption *allopts;
   const char *gargs;
@@ -168,31 +173,35 @@ GNUNET_PROGRAM_run2 (int argc, char *const *argv, const char *binaryName,
 
   logfile = NULL;
   gargs = getenv ("GNUNET_ARGS");
-  if (gargs != NULL)
+  if (NULL != gargs)
   {
     char **gargv;
     unsigned int gargc;
-    int i;
-    char *tok;
     char *cargs;
 
     gargv = NULL;
     gargc = 0;
-    for (i = 0; i < argc; i++)
-      GNUNET_array_append (gargv, gargc, GNUNET_strdup (argv[i]));
+    for (int i = 0; i < argc; i++)
+      GNUNET_array_append (gargv,
+                          gargc,
+                          GNUNET_strdup (argv[i]));
     cargs = GNUNET_strdup (gargs);
-    tok = strtok (cargs, " ");
-    while (NULL != tok)
-    {
-      GNUNET_array_append (gargv, gargc, GNUNET_strdup (tok));
-      tok = strtok (NULL, " ");
-    }
+    for (char *tok = strtok (cargs, " ");
+        NULL != tok;
+        tok = strtok (NULL, " "))
+      GNUNET_array_append (gargv,
+                          gargc,
+                          GNUNET_strdup (tok));
     GNUNET_free (cargs);
-    GNUNET_array_append (gargv, gargc, NULL);
+    GNUNET_array_append (gargv,
+                        gargc,
+                        NULL);
     argv = (char *const *) gargv;
     argc = gargc - 1;
   }
-  memset (&cc, 0, sizeof (cc));
+  memset (&cc,
+         0,
+         sizeof (cc));
   loglev = NULL;
   cc.task = task;
   cc.task_cls = task_cls;
@@ -201,27 +210,32 @@ GNUNET_PROGRAM_run2 (int argc, char *const *argv, const char *binaryName,
 #if ENABLE_NLS
   setlocale (LC_ALL, "");
   path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LOCALEDIR);
-  if (path != NULL)
+  if (NULL != path)
   {
-    BINDTEXTDOMAIN ("GNUnet", path);
+    BINDTEXTDOMAIN ("GNUnet",
+                   path);
     GNUNET_free (path);
   }
   textdomain ("GNUnet");
 #endif
   cnt = 0;
-  while (options[cnt].name != NULL)
+  while (NULL != options[cnt].name)
     cnt++;
   allopts =
       GNUNET_malloc ((cnt +
                       1) * sizeof (struct GNUNET_GETOPT_CommandLineOption) +
                      sizeof (defoptions));
-  memcpy (allopts, defoptions, sizeof (defoptions));
-  memcpy (&allopts
-          [sizeof (defoptions) /
-           sizeof (struct GNUNET_GETOPT_CommandLineOption)], options,
-          (cnt + 1) * sizeof (struct GNUNET_GETOPT_CommandLineOption));
+  GNUNET_memcpy (allopts,
+                defoptions,
+                sizeof (defoptions));
+  GNUNET_memcpy (&allopts
+                [sizeof (defoptions) /
+                 sizeof (struct GNUNET_GETOPT_CommandLineOption)], options,
+                (cnt + 1) * sizeof (struct GNUNET_GETOPT_CommandLineOption));
   cnt += sizeof (defoptions) / sizeof (struct GNUNET_GETOPT_CommandLineOption);
-  qsort (allopts, cnt, sizeof (struct GNUNET_GETOPT_CommandLineOption),
+  qsort (allopts,
+        cnt,
+        sizeof (struct GNUNET_GETOPT_CommandLineOption),
          &cmd_sorter);
   loglev = NULL;
   xdg = getenv ("XDG_CONFIG_HOME");
@@ -230,84 +244,121 @@ GNUNET_PROGRAM_run2 (int argc, char *const *argv, const char *binaryName,
                      "%s%s%s",
                      xdg,
                      DIR_SEPARATOR_STR,
-                     "gnunet.conf");
+                     GNUNET_OS_project_data_get ()->config_file);
   else
-    cfg_fn = GNUNET_strdup (GNUNET_DEFAULT_USER_CONFIG_FILE);
+    cfg_fn = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
   lpfx = GNUNET_strdup (binaryName);
   if (NULL != (spc = strstr (lpfx, " ")))
     *spc = '\0';
-  ret = GNUNET_GETOPT_run (binaryName, allopts, (unsigned int) argc, argv);
+  ret = GNUNET_GETOPT_run (binaryName,
+                          allopts,
+                          (unsigned int) argc,
+                          argv);
   if ((GNUNET_OK > ret) ||
-      (GNUNET_OK != GNUNET_log_setup (lpfx, loglev, logfile)))
+      (GNUNET_OK !=
+       GNUNET_log_setup (lpfx,
+                        loglev,
+                        logfile)))
   {
-    GNUNET_CONFIGURATION_destroy (cfg);
-    GNUNET_free_non_null (cc.cfgfile);
-    GNUNET_free_non_null (loglev);
-    GNUNET_free_non_null (logfile);
-    GNUNET_free (cfg_fn);
     GNUNET_free (allopts);
     GNUNET_free (lpfx);
-    return (ret == GNUNET_SYSERR) ? GNUNET_SYSERR : GNUNET_OK;
+    goto cleanup;
   }
   if (NULL == cc.cfgfile)
     cc.cfgfile = GNUNET_strdup (cfg_fn);
   if (GNUNET_YES ==
       GNUNET_DISK_file_test (cc.cfgfile))
   {
-    if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, cc.cfgfile))
+    if (GNUNET_SYSERR ==
+       GNUNET_CONFIGURATION_load (cfg,
+                                  cc.cfgfile))
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                   _("Malformed configuration file `%s', exit ...\n"),
                   cc.cfgfile);
-      return GNUNET_SYSERR;
+      ret = GNUNET_SYSERR;
+      GNUNET_free (allopts);
+      GNUNET_free (lpfx);
+      goto cleanup;
     }
   }
   else
   {
-    if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL))
+    if (0 != strcmp (cc.cfgfile,
+                    cfg_fn))
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 _("Could not access configuration file `%s'\n"),
+                 cc.cfgfile);
+    if (GNUNET_SYSERR ==
+       GNUNET_CONFIGURATION_load (cfg,
+                                  NULL))
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                   _("Malformed configuration, exit ...\n"));
-      return GNUNET_SYSERR;
+      ret = GNUNET_SYSERR;
+      GNUNET_free (allopts);
+      GNUNET_free (lpfx);
+      goto cleanup;
     }
-    if (0 != strcmp (cc.cfgfile, cfg_fn))
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Could not access configuration file `%s'\n"),
-                 cc.cfgfile);
   }
   GNUNET_free (allopts);
   GNUNET_free (lpfx);
   if (GNUNET_OK ==
-      GNUNET_CONFIGURATION_get_value_number (cc.cfg, "testing", "skew_offset",
+      GNUNET_CONFIGURATION_get_value_number (cc.cfg,
+                                            "testing",
+                                            "skew_offset",
                                              &skew_offset) &&
       (GNUNET_OK ==
-       GNUNET_CONFIGURATION_get_value_number (cc.cfg, "testing",
-                                              "skew_variance", &skew_variance)))
+       GNUNET_CONFIGURATION_get_value_number (cc.cfg,
+                                             "testing",
+                                              "skew_variance",
+                                             &skew_variance)))
   {
     clock_offset = skew_offset - skew_variance;
     GNUNET_TIME_set_offset (clock_offset);
   }
+  /* ARM needs to know which configuration file to use when starting
+     services.  If we got a command-line option *and* if nothing is
+     specified in the configuration, remember the command-line option
+     in "cfg".  This is typically really only having an effect if we
+     are running code in src/arm/, as obviously the rest of the code
+     has little business with ARM-specific options. */
+  if (GNUNET_YES !=
+      GNUNET_CONFIGURATION_have_value (cfg,
+                                       "arm",
+                                       "CONFIG"))
+  {
+    GNUNET_CONFIGURATION_set_value_string (cfg,
+                                           "arm",
+                                          "CONFIG",
+                                           cc.cfgfile);
+  }
+
   /* run */
   cc.args = &argv[ret];
   if (GNUNET_NO == run_without_scheduler)
   {
-          GNUNET_SCHEDULER_run (&program_main, &cc);
+    GNUNET_SCHEDULER_run (&program_main, &cc);
   }
   else
   {
-          GNUNET_RESOLVER_connect (cc.cfg);
-          cc.task (cc.task_cls, cc.args, cc.cfgfile, cc.cfg);
+    GNUNET_RESOLVER_connect (cc.cfg);
+    cc.task (cc.task_cls,
+            cc.args,
+            cc.cfgfile,
+            cc.cfg);
   }
-  /* clean up */
-  GNUNET_SPEEDUP_stop_ ();
+  ret = GNUNET_OK;
+ cleanup:
   GNUNET_CONFIGURATION_destroy (cfg);
-  GNUNET_free (cc.cfgfile);
+  GNUNET_free_non_null (cc.cfgfile);
   GNUNET_free (cfg_fn);
   GNUNET_free_non_null (loglev);
   GNUNET_free_non_null (logfile);
-  return GNUNET_OK;
+  return ret;
 }
 
+
 /**
  * Run a standard GNUnet command startup sequence (initialize loggers
  * and configuration, parse options).
@@ -322,14 +373,19 @@ GNUNET_PROGRAM_run2 (int argc, char *const *argv, const char *binaryName,
  * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
  */
 int
-GNUNET_PROGRAM_run (int argc, char *const *argv, const char *binaryName,
+GNUNET_PROGRAM_run (int argc, char *const *argv,
+                    const char *binaryName,
                     const char *binaryHelp,
                     const struct GNUNET_GETOPT_CommandLineOption *options,
-                    GNUNET_PROGRAM_Main task, void *task_cls)
+                    GNUNET_PROGRAM_Main task,
+                    void *task_cls)
 {
-        return GNUNET_PROGRAM_run2 (argc, argv, binaryName, binaryHelp, options, task, task_cls, GNUNET_NO);
+  return GNUNET_PROGRAM_run2 (argc, argv,
+                              binaryName, binaryHelp,
+                              options,
+                              task, task_cls,
+                              GNUNET_NO);
 }
 
 
-
 /* end of program.c */