123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386 |
- /*
- This file is part of GNUnet.
- 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 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
- 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/>.
- SPDX-License-Identifier: AGPL3.0-or-later
- */
- /**
- * @file util/program.c
- * @brief standard code for GNUnet startup and shutdown
- * @author Christian Grothoff
- */
- #include "platform.h"
- #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-program", __VA_ARGS__)
- #define LOG_STRERROR_FILE(kind, syscall, filename) \
- GNUNET_log_from_strerror_file (kind, "util-program", syscall, filename)
- /**
- * Context for the command.
- */
- struct CommandContext
- {
- /**
- * Argv argument.
- */
- char *const *args;
- /**
- * Name of the configuration file used, can be NULL!
- */
- char *cfgfile;
- /**
- * Main function to run.
- */
- GNUNET_PROGRAM_Main task;
- /**
- * Closure for @e task.
- */
- void *task_cls;
- /**
- * Configuration to use.
- */
- const struct GNUNET_CONFIGURATION_Handle *cfg;
- };
- /**
- * task run when the scheduler shuts down
- */
- static void
- shutdown_task (void *cls)
- {
- (void) cls;
- GNUNET_SPEEDUP_stop_ ();
- }
- /**
- * Initial task called by the scheduler for each
- * program. Runs the program-specific main task.
- */
- static void
- program_main (void *cls)
- {
- struct CommandContext *cc = cls;
- 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);
- }
- /**
- * Compare function for 'qsort' to sort command-line arguments by the
- * short option.
- *
- * @param a1 first command line option
- * @param a2 second command line option
- */
- static int
- cmd_sorter (const void *a1, const void *a2)
- {
- const struct GNUNET_GETOPT_CommandLineOption *c1 = a1;
- const struct GNUNET_GETOPT_CommandLineOption *c2 = a2;
- if (toupper ((unsigned char) c1->shortName) >
- toupper ((unsigned char) c2->shortName))
- return 1;
- if (toupper ((unsigned char) c1->shortName) <
- toupper ((unsigned char) c2->shortName))
- return -1;
- if (c1->shortName > c2->shortName)
- return 1;
- if (c1->shortName < c2->shortName)
- return -1;
- return 0;
- }
- /**
- * Run a standard GNUnet command startup sequence (initialize loggers
- * and configuration, parse options).
- *
- * @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 @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
- */
- 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)
- {
- struct CommandContext cc;
- #if ENABLE_NLS
- char *path;
- #endif
- char *loglev;
- char *logfile;
- char *cfg_fn;
- const char *xdg;
- int ret;
- unsigned int cnt;
- unsigned long long skew_offset;
- unsigned long long skew_variance;
- long long clock_offset;
- struct GNUNET_CONFIGURATION_Handle *cfg;
- const struct GNUNET_OS_ProjectData *pd = GNUNET_OS_project_data_get ();
- struct GNUNET_GETOPT_CommandLineOption defoptions[] =
- { 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 (pd->version) };
- struct GNUNET_GETOPT_CommandLineOption *allopts;
- const char *gargs;
- char *lpfx;
- char *spc;
- logfile = NULL;
- gargs = getenv ("GNUNET_ARGS");
- if (NULL != gargs)
- {
- char **gargv;
- unsigned int gargc;
- char *cargs;
- gargv = NULL;
- gargc = 0;
- for (int i = 0; i < argc; i++)
- GNUNET_array_append (gargv, gargc, GNUNET_strdup (argv[i]));
- cargs = GNUNET_strdup (gargs);
- 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);
- argv = (char *const *) gargv;
- argc = gargc - 1;
- }
- memset (&cc, 0, sizeof(cc));
- loglev = NULL;
- cc.task = task;
- cc.task_cls = task_cls;
- cc.cfg = cfg = GNUNET_CONFIGURATION_create ();
- /* prepare */
- #if ENABLE_NLS
- if (NULL != pd->gettext_domain)
- {
- setlocale (LC_ALL, "");
- path = (NULL == pd->gettext_path)
- ? GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LOCALEDIR)
- : GNUNET_strdup (pd->gettext_path);
- if (NULL != path)
- {
- bindtextdomain (pd->gettext_domain, path);
- GNUNET_free (path);
- }
- textdomain (pd->gettext_domain);
- }
- #endif
- cnt = 0;
- while (NULL != options[cnt].name)
- cnt++;
- allopts =
- GNUNET_malloc ((cnt + 1) * sizeof(struct GNUNET_GETOPT_CommandLineOption)
- + sizeof(defoptions));
- 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),
- &cmd_sorter);
- loglev = NULL;
- xdg = getenv ("XDG_CONFIG_HOME");
- if (NULL != xdg)
- GNUNET_asprintf (&cfg_fn,
- "%s%s%s",
- xdg,
- DIR_SEPARATOR_STR,
- pd->config_file);
- else
- cfg_fn = GNUNET_strdup (pd->user_config_file);
- lpfx = GNUNET_strdup (binaryName);
- if (NULL != (spc = strstr (lpfx, " ")))
- *spc = '\0';
- ret = GNUNET_GETOPT_run (binaryName, allopts, (unsigned int) argc, argv);
- if ((GNUNET_OK > ret) ||
- (GNUNET_OK != GNUNET_log_setup (lpfx, loglev, logfile)))
- {
- GNUNET_free (allopts);
- GNUNET_free (lpfx);
- goto cleanup;
- }
- if (NULL != cc.cfgfile)
- {
- if ((GNUNET_YES != GNUNET_DISK_file_test (cc.cfgfile)) ||
- (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, cc.cfgfile)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _ (
- "Unreadable or malformed configuration file `%s', exit ...\n"),
- cc.cfgfile);
- ret = GNUNET_SYSERR;
- GNUNET_free (allopts);
- GNUNET_free (lpfx);
- goto cleanup;
- }
- }
- else
- {
- if (GNUNET_YES == GNUNET_DISK_file_test (cfg_fn))
- {
- if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, cfg_fn))
- {
- GNUNET_log (
- GNUNET_ERROR_TYPE_ERROR,
- _ (
- "Unreadable or malformed default configuration file `%s', exit ...\n"),
- cfg_fn);
- ret = GNUNET_SYSERR;
- GNUNET_free (allopts);
- GNUNET_free (lpfx);
- goto cleanup;
- }
- }
- else
- {
- GNUNET_free (cfg_fn);
- cfg_fn = NULL;
- if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, NULL))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _ ("Unreadable or malformed configuration, exit ...\n"));
- ret = GNUNET_SYSERR;
- GNUNET_free (allopts);
- GNUNET_free (lpfx);
- goto cleanup;
- }
- }
- }
- GNUNET_free (allopts);
- GNUNET_free (lpfx);
- if ((GNUNET_OK == 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)))
- {
- 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"))
- {
- if (NULL != cc.cfgfile)
- GNUNET_CONFIGURATION_set_value_string (cfg, "arm", "CONFIG", cc.cfgfile);
- else if (NULL != cfg_fn)
- GNUNET_CONFIGURATION_set_value_string (cfg, "arm", "CONFIG", cfg_fn);
- }
- /* run */
- cc.args = &argv[ret];
- if ((NULL == cc.cfgfile) && (NULL != cfg_fn))
- cc.cfgfile = GNUNET_strdup (cfg_fn);
- if (GNUNET_NO == run_without_scheduler)
- {
- GNUNET_SCHEDULER_run (&program_main, &cc);
- }
- else
- {
- GNUNET_RESOLVER_connect (cc.cfg);
- cc.task (cc.task_cls, cc.args, cc.cfgfile, cc.cfg);
- }
- ret = GNUNET_OK;
- cleanup:
- GNUNET_CONFIGURATION_destroy (cfg);
- GNUNET_free_non_null (cc.cfgfile);
- GNUNET_free_non_null (cfg_fn);
- GNUNET_free_non_null (loglev);
- GNUNET_free_non_null (logfile);
- return ret;
- }
- /**
- * Run a standard GNUnet command startup sequence (initialize loggers
- * and configuration, parse options).
- *
- * @param argc number of command line arguments
- * @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 @a task
- * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
- */
- int
- 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)
- {
- return GNUNET_PROGRAM_run2 (argc,
- argv,
- binaryName,
- binaryHelp,
- options,
- task,
- task_cls,
- GNUNET_NO);
- }
- /* end of program.c */
|