GNUnet  0.17.6
program.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2009-2013 GNUnet e.V.
4 
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.
9 
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.
14 
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/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
30 #include "gnunet_constants.h"
31 #include "speedup.h"
32 #include <gcrypt.h>
33 
34 #define LOG(kind, ...) GNUNET_log_from (kind, "util-program", __VA_ARGS__)
35 
36 #define LOG_STRERROR_FILE(kind, syscall, filename) \
37  GNUNET_log_from_strerror_file (kind, "util-program", syscall, filename)
38 
43 {
47  char *const *args;
48 
52  char *cfgfile;
53 
58 
62  void *task_cls;
63 
68 };
69 
70 
74 static void
75 shutdown_task (void *cls)
76 {
77  (void) cls;
79 }
80 
81 
86 static void
87 program_main (void *cls)
88 {
89  struct CommandContext *cc = cls;
90 
93  NULL);
95  cc->task (cc->task_cls,
96  cc->args,
97  cc->cfgfile,
98  cc->cfg);
99 }
100 
101 
109 static int
110 cmd_sorter (const void *a1,
111  const void *a2)
112 {
113  const struct GNUNET_GETOPT_CommandLineOption *c1 = a1;
114  const struct GNUNET_GETOPT_CommandLineOption *c2 = a2;
115 
116  if (toupper ((unsigned char) c1->shortName) >
117  toupper ((unsigned char) c2->shortName))
118  return 1;
119  if (toupper ((unsigned char) c1->shortName) <
120  toupper ((unsigned char) c2->shortName))
121  return -1;
122  if (c1->shortName > c2->shortName)
123  return 1;
124  if (c1->shortName < c2->shortName)
125  return -1;
126  return 0;
127 }
128 
129 
131 GNUNET_PROGRAM_run2 (int argc,
132  char *const *argv,
133  const char *binaryName,
134  const char *binaryHelp,
136  GNUNET_PROGRAM_Main task,
137  void *task_cls,
138  int run_without_scheduler)
139 {
140  struct CommandContext cc;
141 
142 #if ENABLE_NLS
143  char *path;
144 #endif
145  char *loglev;
146  char *logfile;
147  char *cfg_fn;
149  int iret;
150  unsigned int cnt;
151  unsigned long long skew_offset;
152  unsigned long long skew_variance;
153  long long clock_offset;
156  const struct GNUNET_GETOPT_CommandLineOption defoptions[] = {
157  GNUNET_GETOPT_option_cfgfile (&cc.cfgfile),
158  GNUNET_GETOPT_option_help (binaryHelp),
160  GNUNET_GETOPT_option_logfile (&logfile),
162  };
163  unsigned int deflen = sizeof(defoptions) / sizeof(defoptions[0]);
164  struct GNUNET_GETOPT_CommandLineOption *allopts;
165  const char *gargs;
166  char *lpfx;
167  char *spc;
168 
169  logfile = NULL;
170  gargs = getenv ("GNUNET_ARGS");
171  if (NULL != gargs)
172  {
173  char **gargv;
174  unsigned int gargc;
175  char *cargs;
176 
177  gargv = NULL;
178  gargc = 0;
179  for (int i = 0; i < argc; i++)
180  GNUNET_array_append (gargv,
181  gargc,
182  GNUNET_strdup (argv[i]));
183  cargs = GNUNET_strdup (gargs);
184  for (char *tok = strtok (cargs, " ");
185  NULL != tok;
186  tok = strtok (NULL, " "))
187  GNUNET_array_append (gargv, gargc, GNUNET_strdup (tok));
188  GNUNET_free (cargs);
189  GNUNET_array_append (gargv, gargc, NULL);
190  argv = (char *const *) gargv;
191  argc = gargc - 1;
192  }
193  memset (&cc, 0, sizeof(cc));
194  loglev = NULL;
195  cc.task = task;
196  cc.task_cls = task_cls;
197  cc.cfg = cfg = GNUNET_CONFIGURATION_create ();
198  /* prepare */
199 #if ENABLE_NLS
200  if (NULL != pd->gettext_domain)
201  {
202  setlocale (LC_ALL, "");
203  path = (NULL == pd->gettext_path)
205  : GNUNET_strdup (pd->gettext_path);
206  if (NULL != path)
207  {
208  bindtextdomain (pd->gettext_domain, path);
209  GNUNET_free (path);
210  }
212  }
213 #endif
214  cnt = 0;
215  while (NULL != options[cnt].name)
216  cnt++;
217  allopts = GNUNET_new_array (cnt + deflen + 1,
219  GNUNET_memcpy (allopts,
220  options,
221  cnt * sizeof(struct GNUNET_GETOPT_CommandLineOption));
222  {
223  unsigned int xtra = 0;
224 
225  for (unsigned int i = 0;
226  i<sizeof (defoptions) / sizeof(struct GNUNET_GETOPT_CommandLineOption);
227  i++)
228  {
229  bool found = false;
230 
231  for (unsigned int j = 0; j<cnt; j++)
232  {
233  found |= ( (options[j].shortName == defoptions[i].shortName) &&
234  (0 != options[j].shortName) );
235  found |= ( (NULL != options[j].name) &&
236  (NULL != defoptions[i].name) &&
237  (0 == strcmp (options[j].name,
238  defoptions[i].name)) );
239  if (found)
240  break;
241  }
242  if (found)
243  continue;
244  GNUNET_memcpy (&allopts[cnt + xtra],
245  &defoptions[i],
246  sizeof (struct GNUNET_GETOPT_CommandLineOption));
247  xtra++;
248  }
249  cnt += xtra;
250  }
251  qsort (allopts,
252  cnt,
253  sizeof(struct GNUNET_GETOPT_CommandLineOption),
254  &cmd_sorter);
255  loglev = NULL;
256  if ((NULL != pd->config_file) && (NULL != pd->user_config_file))
258  else
259  cfg_fn = NULL;
260  lpfx = GNUNET_strdup (binaryName);
261  if (NULL != (spc = strstr (lpfx, " ")))
262  *spc = '\0';
263  iret = GNUNET_GETOPT_run (binaryName,
264  allopts,
265  (unsigned int) argc,
266  argv);
267  if ((GNUNET_OK > iret) ||
268  (GNUNET_OK != GNUNET_log_setup (lpfx,
269  loglev,
270  logfile)))
271  {
272  GNUNET_free (allopts);
273  GNUNET_free (lpfx);
274  ret = (enum GNUNET_GenericReturnValue) iret;
275  goto cleanup;
276  }
277  if (NULL != cc.cfgfile)
278  {
280  "Loading configuration from entry point specified as option (%s)\n",
281  cc.cfgfile);
282  if (GNUNET_YES !=
283  GNUNET_DISK_file_test (cc.cfgfile))
284  {
286  _ ("Unreadable configuration file `%s', exiting ...\n"),
287  cc.cfgfile);
288  ret = GNUNET_SYSERR;
289  GNUNET_free (allopts);
290  GNUNET_free (lpfx);
291  goto cleanup;
292  }
293  if (GNUNET_SYSERR ==
295  cc.cfgfile))
296  {
298  _ ("Malformed configuration file `%s', exiting ...\n"),
299  cc.cfgfile);
300  ret = GNUNET_SYSERR;
301  GNUNET_free (allopts);
302  GNUNET_free (lpfx);
303  goto cleanup;
304  }
305  }
306  else
307  {
308  if ( (NULL != cfg_fn) &&
309  (GNUNET_YES !=
310  GNUNET_DISK_file_test (cfg_fn)) )
311  {
313  _ ("Unreadable configuration file `%s'. Exiting ...\n"),
314  cfg_fn);
315  ret = GNUNET_SYSERR;
316  GNUNET_free (allopts);
317  GNUNET_free (lpfx);
318  goto cleanup;
319  }
321  "Loading configuration from entry point `%s'\n",
322  cc.cfgfile);
323  if (GNUNET_SYSERR ==
325  cfg_fn))
326  {
328  _ ("Malformed configuration. Exiting ...\n"));
329  ret = GNUNET_SYSERR;
330  GNUNET_free (allopts);
331  GNUNET_free (lpfx);
332  goto cleanup;
333  }
334  }
335  GNUNET_free (allopts);
336  GNUNET_free (lpfx);
337  if ((GNUNET_OK ==
339  "testing",
340  "skew_offset",
341  &skew_offset)) &&
342  (GNUNET_OK ==
344  "testing",
345  "skew_variance",
346  &skew_variance)))
347  {
348  clock_offset = skew_offset - skew_variance;
349  GNUNET_TIME_set_offset (clock_offset);
350  }
351  /* ARM needs to know which configuration file to use when starting
352  services. If we got a command-line option *and* if nothing is
353  specified in the configuration, remember the command-line option
354  in "cfg". This is typically really only having an effect if we
355  are running code in src/arm/, as obviously the rest of the code
356  has little business with ARM-specific options. */
357  if (GNUNET_YES !=
359  "arm",
360  "CONFIG"))
361  {
362  if (NULL != cc.cfgfile)
364  "arm",
365  "CONFIG",
366  cc.cfgfile);
367  else if (NULL != cfg_fn)
369  "arm",
370  "CONFIG",
371  cfg_fn);
372  }
373 
374  /* run */
375  cc.args = &argv[iret];
376  if ((NULL == cc.cfgfile) && (NULL != cfg_fn))
377  cc.cfgfile = GNUNET_strdup (cfg_fn);
378  if (GNUNET_NO == run_without_scheduler)
379  {
381  }
382  else
383  {
384  GNUNET_RESOLVER_connect (cc.cfg);
385  cc.task (cc.task_cls, cc.args, cc.cfgfile, cc.cfg);
386  }
387  ret = GNUNET_OK;
388 cleanup:
390  GNUNET_free (cc.cfgfile);
391  GNUNET_free (cfg_fn);
392  GNUNET_free (loglev);
393  GNUNET_free (logfile);
394  return ret;
395 }
396 
397 
399 GNUNET_PROGRAM_run (int argc,
400  char *const *argv,
401  const char *binaryName,
402  const char *binaryHelp,
404  GNUNET_PROGRAM_Main task,
405  void *task_cls)
406 {
407  return GNUNET_PROGRAM_run2 (argc,
408  argv,
409  binaryName,
410  binaryHelp,
411  options,
412  task,
413  task_cls,
414  GNUNET_NO);
415 }
416 
417 
418 /* end of program.c */
struct GNUNET_GETOPT_CommandLineOption options[]
Definition: 002.c:5
char * getenv()
#define textdomain(Domainname)
Definition: gettext.h:56
#define bindtextdomain(Domainname, Dirname)
Definition: gettext.h:57
static const struct GNUNET_CONFIGURATION_Handle * cfg
Configuration we are using.
Definition: gnunet-abd.c:36
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
static void cleanup(void *cls)
Function scheduled as very last function, cleans up after us.
void GNUNET_CONFIGURATION_set_value_string(struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, const char *value)
Set a configuration value that should be a string.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_number(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, unsigned long long *number)
Get a configuration value that should be a number.
struct GNUNET_CONFIGURATION_Handle * GNUNET_CONFIGURATION_create(void)
Create a new configuration object.
void GNUNET_CONFIGURATION_destroy(struct GNUNET_CONFIGURATION_Handle *cfg)
Destroy configuration object.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_load(struct GNUNET_CONFIGURATION_Handle *cfg, const char *filename)
Load configuration.
char * GNUNET_CONFIGURATION_default_filename(void)
Return the filename of the default configuration filename that is used when no explicit configuration...
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_have_value(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Test if we have a value for a particular option.
enum GNUNET_GenericReturnValue GNUNET_DISK_file_test(const char *fil)
Check that fil corresponds to a filename (of a file that exists and that is not a directory).
Definition: disk.c:482
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_cfgfile(char **fn)
Allow user to specify configuration file name (-c option)
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_logfile(char **logfn)
Allow user to specify log file name (-l option)
int GNUNET_GETOPT_run(const char *binaryOptions, const struct GNUNET_GETOPT_CommandLineOption *allOptions, unsigned int argc, char *const *argv)
Parse the command line.
Definition: getopt.c:883
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_help(const char *about)
Defining the option to print the command line help text (-h option).
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_loglevel(char **level)
Define the '-L' log level option.
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_version(const char *version)
Define the option to print the version of the application (-v option)
#define GNUNET_log(kind,...)
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
GNUNET_GenericReturnValue
Named constants for return values.
Definition: gnunet_common.h:96
@ GNUNET_OK
Definition: gnunet_common.h:99
@ GNUNET_YES
@ GNUNET_NO
Definition: gnunet_common.h:98
@ GNUNET_SYSERR
Definition: gnunet_common.h:97
int GNUNET_log_setup(const char *comp, const char *loglevel, const char *logfile)
Setup logging.
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
#define GNUNET_array_append(arr, len, element)
Append an element to an array (growing the array by one).
#define GNUNET_free(ptr)
Wrapper around free.
const struct GNUNET_OS_ProjectData * GNUNET_OS_project_data_get(void)
char * GNUNET_OS_installation_get_path(enum GNUNET_OS_InstallationPathKind dirkind)
Get the path to a specific GNUnet installation directory or, with GNUNET_OS_IPK_SELF_PREFIX,...
@ GNUNET_OS_IPK_LOCALEDIR
Return the directory where translations are installed (share/locale/)
enum GNUNET_GenericReturnValue 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)
Run a standard GNUnet command startup sequence (initialize loggers and configuration,...
Definition: program.c:131
void(* GNUNET_PROGRAM_Main)(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
Main function that will be run.
enum GNUNET_GenericReturnValue 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)
Run a standard GNUnet command startup sequence (initialize loggers and configuration,...
Definition: program.c:399
void GNUNET_RESOLVER_connect(const struct GNUNET_CONFIGURATION_Handle *cfg)
Create the connection to the resolver service.
Definition: resolver_api.c:257
void GNUNET_SCHEDULER_run(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Initialize and run scheduler.
Definition: scheduler.c:705
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received,...
Definition: scheduler.c:1316
void GNUNET_TIME_set_offset(long long offset)
Set the timestamp offset for this instance.
Definition: time.c:48
#define _(String)
GNU gettext support macro.
Definition: platform.h:177
const char * name
static void shutdown_task(void *cls)
task run when the scheduler shuts down
Definition: program.c:75
static void program_main(void *cls)
Initial task called by the scheduler for each program.
Definition: program.c:87
static int cmd_sorter(const void *a1, const void *a2)
Compare function for 'qsort' to sort command-line arguments by the short option.
Definition: program.c:110
int GNUNET_SPEEDUP_start_(const struct GNUNET_CONFIGURATION_Handle *cfg)
Start task that may speed up our system clock artificially.
Definition: speedup.c:65
void GNUNET_SPEEDUP_stop_()
Stop tasks that modify clock behavior.
Definition: speedup.c:105
Context for the command.
Definition: program.c:43
void * task_cls
Closure for task.
Definition: program.c:62
char *const * args
Argv argument.
Definition: program.c:47
const struct GNUNET_CONFIGURATION_Handle * cfg
Configuration to use.
Definition: program.c:67
GNUNET_PROGRAM_Main task
Main function to run.
Definition: program.c:57
char * cfgfile
Name of the configuration file used, can be NULL!
Definition: program.c:52
Definition of a command line option.
const char * name
Long name of the option (may not be NULL)
const char shortName
Short name of the option.
Project-specific data used to help the OS subsystem find installation paths.
char * gettext_path
Gettext directory, e.g.
const char * user_config_file
Configuration file name to use (if $XDG_CONFIG_HOME is not set).
const char * config_file
Configuration file name (in $XDG_CONFIG_HOME) to use.
char * gettext_domain
Gettext domain for localisation, e.g.
const char * version
String identifying the current project version.