2 This file is part of GNUnet.
3 Copyright (C) 2009-2013 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPROSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @file util/program.c
23 * @brief standard code for GNUnet startup and shutdown
24 * @author Christian Grothoff
28 #include "gnunet_util_lib.h"
29 #include "gnunet_resolver_service.h"
30 #include "gnunet_constants.h"
34 #define LOG(kind,...) GNUNET_log_from (kind, "util-program", __VA_ARGS__)
36 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-program", syscall, filename)
39 * Context for the command.
49 * Name of the configuration file used, can be NULL!
54 * Main function to run.
56 GNUNET_PROGRAM_Main task;
59 * Closure for @e task.
64 * Configuration to use.
66 const struct GNUNET_CONFIGURATION_Handle *cfg;
72 * task run when the scheduler shuts down
75 shutdown_task (void *cls)
78 GNUNET_SPEEDUP_stop_ ();
83 * Initial task called by the scheduler for each
84 * program. Runs the program-specific main task.
87 program_main (void *cls)
89 struct CommandContext *cc = cls;
91 GNUNET_SPEEDUP_start_(cc->cfg);
92 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
94 GNUNET_RESOLVER_connect (cc->cfg);
95 cc->task (cc->task_cls,
103 * Compare function for 'qsort' to sort command-line arguments by the
106 * @param a1 first command line option
107 * @param a2 second command line option
110 cmd_sorter (const void *a1,
113 const struct GNUNET_GETOPT_CommandLineOption *c1 = a1;
114 const struct GNUNET_GETOPT_CommandLineOption *c2 = a2;
116 if (toupper ((unsigned char) c1->shortName) >
117 toupper ((unsigned char) c2->shortName))
119 if (toupper ((unsigned char) c1->shortName) <
120 toupper ((unsigned char) c2->shortName))
122 if (c1->shortName > c2->shortName)
124 if (c1->shortName < c2->shortName)
131 * Run a standard GNUnet command startup sequence (initialize loggers
132 * and configuration, parse options).
134 * @param argc number of command line arguments in @a argv
135 * @param argv command line arguments
136 * @param binaryName our expected name
137 * @param binaryHelp help text for the program
138 * @param options command line options
139 * @param task main function to run
140 * @param task_cls closure for @a task
141 * @param run_without_scheduler #GNUNET_NO start the scheduler, #GNUNET_YES do not
142 * start the scheduler just run the main task
143 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
146 GNUNET_PROGRAM_run2 (int argc,
148 const char *binaryName,
149 const char *binaryHelp,
150 const struct GNUNET_GETOPT_CommandLineOption *options,
151 GNUNET_PROGRAM_Main task,
153 int run_without_scheduler)
155 struct CommandContext cc;
165 unsigned long long skew_offset;
166 unsigned long long skew_variance;
167 long long clock_offset;
168 struct GNUNET_CONFIGURATION_Handle *cfg;
169 struct GNUNET_GETOPT_CommandLineOption defoptions[] = {
170 GNUNET_GETOPT_option_cfgfile (&cc.cfgfile),
171 GNUNET_GETOPT_option_help (binaryHelp),
172 GNUNET_GETOPT_option_loglevel (&loglev),
173 GNUNET_GETOPT_option_logfile (&logfile),
174 GNUNET_GETOPT_option_version (PACKAGE_VERSION " " VCS_VERSION)
176 struct GNUNET_GETOPT_CommandLineOption *allopts;
182 gargs = getenv ("GNUNET_ARGS");
191 for (int i = 0; i < argc; i++)
192 GNUNET_array_append (gargv,
194 GNUNET_strdup (argv[i]));
195 cargs = GNUNET_strdup (gargs);
196 for (char *tok = strtok (cargs, " ");
198 tok = strtok (NULL, " "))
199 GNUNET_array_append (gargv,
201 GNUNET_strdup (tok));
203 GNUNET_array_append (gargv,
206 argv = (char *const *) gargv;
214 cc.task_cls = task_cls;
215 cc.cfg = cfg = GNUNET_CONFIGURATION_create ();
218 setlocale (LC_ALL, "");
219 path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LOCALEDIR);
222 BINDTEXTDOMAIN ("GNUnet",
226 textdomain ("GNUnet");
229 while (NULL != options[cnt].name)
232 GNUNET_malloc ((cnt +
233 1) * sizeof (struct GNUNET_GETOPT_CommandLineOption) +
234 sizeof (defoptions));
235 GNUNET_memcpy (allopts,
237 sizeof (defoptions));
238 GNUNET_memcpy (&allopts
239 [sizeof (defoptions) /
240 sizeof (struct GNUNET_GETOPT_CommandLineOption)], options,
241 (cnt + 1) * sizeof (struct GNUNET_GETOPT_CommandLineOption));
242 cnt += sizeof (defoptions) / sizeof (struct GNUNET_GETOPT_CommandLineOption);
245 sizeof (struct GNUNET_GETOPT_CommandLineOption),
248 xdg = getenv ("XDG_CONFIG_HOME");
250 GNUNET_asprintf (&cfg_fn,
254 GNUNET_OS_project_data_get ()->config_file);
256 cfg_fn = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
257 lpfx = GNUNET_strdup (binaryName);
258 if (NULL != (spc = strstr (lpfx, " ")))
260 ret = GNUNET_GETOPT_run (binaryName,
264 if ((GNUNET_OK > ret) ||
266 GNUNET_log_setup (lpfx,
270 GNUNET_free (allopts);
274 if (NULL != cc.cfgfile)
277 GNUNET_DISK_file_test (cc.cfgfile)) ||
279 GNUNET_CONFIGURATION_load (cfg,
282 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
283 _("Unreadable or malformed configuration file `%s', exit ...\n"),
286 GNUNET_free (allopts);
294 GNUNET_DISK_file_test (cfg_fn))
297 GNUNET_CONFIGURATION_load (cfg,
300 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
301 _("Unreadable or malformed default configuration file `%s', exit ...\n"),
304 GNUNET_free (allopts);
311 GNUNET_free (cfg_fn);
314 GNUNET_CONFIGURATION_load (cfg,
317 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
318 _("Unreadable or malformed configuration, exit ...\n"));
320 GNUNET_free (allopts);
326 GNUNET_free (allopts);
329 GNUNET_CONFIGURATION_get_value_number (cc.cfg,
334 GNUNET_CONFIGURATION_get_value_number (cc.cfg,
339 clock_offset = skew_offset - skew_variance;
340 GNUNET_TIME_set_offset (clock_offset);
342 /* ARM needs to know which configuration file to use when starting
343 services. If we got a command-line option *and* if nothing is
344 specified in the configuration, remember the command-line option
345 in "cfg". This is typically really only having an effect if we
346 are running code in src/arm/, as obviously the rest of the code
347 has little business with ARM-specific options. */
349 GNUNET_CONFIGURATION_have_value (cfg,
353 if (NULL != cc.cfgfile)
354 GNUNET_CONFIGURATION_set_value_string (cfg,
358 else if (NULL != cfg_fn)
359 GNUNET_CONFIGURATION_set_value_string (cfg,
366 cc.args = &argv[ret];
367 if ( (NULL == cc.cfgfile) &&
369 cc.cfgfile = GNUNET_strdup (cfg_fn);
370 if (GNUNET_NO == run_without_scheduler)
372 GNUNET_SCHEDULER_run (&program_main,
377 GNUNET_RESOLVER_connect (cc.cfg);
378 cc.task (cc.task_cls,
385 GNUNET_CONFIGURATION_destroy (cfg);
386 GNUNET_free_non_null (cc.cfgfile);
387 GNUNET_free_non_null (cfg_fn);
388 GNUNET_free_non_null (loglev);
389 GNUNET_free_non_null (logfile);
395 * Run a standard GNUnet command startup sequence (initialize loggers
396 * and configuration, parse options).
398 * @param argc number of command line arguments
399 * @param argv command line arguments
400 * @param binaryName our expected name
401 * @param binaryHelp help text for the program
402 * @param options command line options
403 * @param task main function to run
404 * @param task_cls closure for @a task
405 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
408 GNUNET_PROGRAM_run (int argc, char *const *argv,
409 const char *binaryName,
410 const char *binaryHelp,
411 const struct GNUNET_GETOPT_CommandLineOption *options,
412 GNUNET_PROGRAM_Main task,
415 return GNUNET_PROGRAM_run2 (argc, argv,
416 binaryName, binaryHelp,
423 /* end of program.c */