GNUnet  0.11.x
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 
94  cc->task (cc->task_cls, cc->args, cc->cfgfile, cc->cfg);
95 }
96 
97 
105 static int
106 cmd_sorter (const void *a1, const void *a2)
107 {
108  const struct GNUNET_GETOPT_CommandLineOption *c1 = a1;
109  const struct GNUNET_GETOPT_CommandLineOption *c2 = a2;
110 
111  if (toupper ((unsigned char) c1->shortName) >
112  toupper ((unsigned char) c2->shortName))
113  return 1;
114  if (toupper ((unsigned char) c1->shortName) <
115  toupper ((unsigned char) c2->shortName))
116  return -1;
117  if (c1->shortName > c2->shortName)
118  return 1;
119  if (c1->shortName < c2->shortName)
120  return -1;
121  return 0;
122 }
123 
124 
127  char *const *argv,
128  const char *binaryName,
129  const char *binaryHelp,
132  void *task_cls,
133  int run_without_scheduler)
134 {
135  struct CommandContext cc;
136 
137 #if ENABLE_NLS
138  char *path;
139 #endif
140  char *loglev;
141  char *logfile;
142  char *cfg_fn;
144  int iret;
145  unsigned int cnt;
146  unsigned long long skew_offset;
147  unsigned long long skew_variance;
148  long long clock_offset;
151  struct GNUNET_GETOPT_CommandLineOption defoptions[] = {
153  GNUNET_GETOPT_option_help (binaryHelp),
155  GNUNET_GETOPT_option_logfile (&logfile),
157  };
158  struct GNUNET_GETOPT_CommandLineOption *allopts;
159  const char *gargs;
160  char *lpfx;
161  char *spc;
162 
163  logfile = NULL;
164  gargs = getenv ("GNUNET_ARGS");
165  if (NULL != gargs)
166  {
167  char **gargv;
168  unsigned int gargc;
169  char *cargs;
170 
171  gargv = NULL;
172  gargc = 0;
173  for (int i = 0; i < argc; i++)
174  GNUNET_array_append (gargv, gargc, GNUNET_strdup (argv[i]));
175  cargs = GNUNET_strdup (gargs);
176  for (char *tok = strtok (cargs, " "); NULL != tok; tok = strtok (NULL, " "))
177  GNUNET_array_append (gargv, gargc, GNUNET_strdup (tok));
178  GNUNET_free (cargs);
179  GNUNET_array_append (gargv, gargc, NULL);
180  argv = (char *const *) gargv;
181  argc = gargc - 1;
182  }
183  memset (&cc, 0, sizeof(cc));
184  loglev = NULL;
185  cc.task = task;
186  cc.task_cls = task_cls;
187  cc.cfg = cfg = GNUNET_CONFIGURATION_create ();
188  /* prepare */
189 #if ENABLE_NLS
190  if (NULL != pd->gettext_domain)
191  {
192  setlocale (LC_ALL, "");
193  path = (NULL == pd->gettext_path)
195  : GNUNET_strdup (pd->gettext_path);
196  if (NULL != path)
197  {
198  bindtextdomain (pd->gettext_domain, path);
199  GNUNET_free (path);
200  }
202  }
203 #endif
204  cnt = 0;
205  while (NULL != options[cnt].name)
206  cnt++;
207  allopts =
208  GNUNET_malloc ((cnt + 1) * sizeof(struct GNUNET_GETOPT_CommandLineOption)
209  + sizeof(defoptions));
210  GNUNET_memcpy (allopts, defoptions, sizeof(defoptions));
211  GNUNET_memcpy (&allopts[sizeof(defoptions)
212  / sizeof(struct GNUNET_GETOPT_CommandLineOption)],
213  options,
214  (cnt + 1) * sizeof(struct GNUNET_GETOPT_CommandLineOption));
215  cnt += sizeof(defoptions) / sizeof(struct GNUNET_GETOPT_CommandLineOption);
216  qsort (allopts,
217  cnt,
218  sizeof(struct GNUNET_GETOPT_CommandLineOption),
219  &cmd_sorter);
220  loglev = NULL;
221  if ((NULL != pd->config_file) && (NULL != pd->user_config_file))
223  else
224  cfg_fn = NULL;
225  lpfx = GNUNET_strdup (binaryName);
226  if (NULL != (spc = strstr (lpfx, " ")))
227  *spc = '\0';
228  iret = GNUNET_GETOPT_run (binaryName,
229  allopts,
230  (unsigned int) argc,
231  argv);
232  if ((GNUNET_OK > iret) ||
233  (GNUNET_OK != GNUNET_log_setup (lpfx,
234  loglev,
235  logfile)))
236  {
237  GNUNET_free (allopts);
238  GNUNET_free (lpfx);
239  ret = (enum GNUNET_GenericReturnValue) iret;
240  goto cleanup;
241  }
242  if (NULL != cc.cfgfile)
243  {
245  "Loading configuration from entry point specified as option (%s)\n",
246  cc.cfgfile);
247  if ((GNUNET_YES != GNUNET_DISK_file_test (cc.cfgfile)) ||
249  {
251  _ (
252  "Unreadable or malformed configuration file `%s', exit ...\n"),
253  cc.cfgfile);
254  ret = GNUNET_SYSERR;
255  GNUNET_free (allopts);
256  GNUNET_free (lpfx);
257  goto cleanup;
258  }
259  }
260  else
261  {
263  "Loading configuration default entry point (%s)\n",
264  cc.cfgfile);
265  if ((NULL != cfg_fn) && (GNUNET_YES == GNUNET_DISK_file_test (cfg_fn)))
266  {
267  if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, cfg_fn))
268  {
269  GNUNET_log (
271  _ (
272  "Unreadable or malformed default configuration file `%s', exit ...\n"),
273  cfg_fn);
274  ret = GNUNET_SYSERR;
275  GNUNET_free (allopts);
276  GNUNET_free (lpfx);
277  goto cleanup;
278  }
279  }
280  else if (NULL != cfg_fn)
281  {
283  "Loading configuration without entry point\n");
284  GNUNET_free (cfg_fn);
285  if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, NULL))
286  {
288  _ ("Unreadable or malformed configuration, exit ...\n"));
289  ret = GNUNET_SYSERR;
290  GNUNET_free (allopts);
291  GNUNET_free (lpfx);
292  goto cleanup;
293  }
294  }
295  }
296  GNUNET_free (allopts);
297  GNUNET_free (lpfx);
298  if ((GNUNET_OK ==
300  "testing",
301  "skew_offset",
302  &skew_offset)) &&
303  (GNUNET_OK ==
305  "testing",
306  "skew_variance",
307  &skew_variance)))
308  {
309  clock_offset = skew_offset - skew_variance;
310  GNUNET_TIME_set_offset (clock_offset);
311  }
312  /* ARM needs to know which configuration file to use when starting
313  services. If we got a command-line option *and* if nothing is
314  specified in the configuration, remember the command-line option
315  in "cfg". This is typically really only having an effect if we
316  are running code in src/arm/, as obviously the rest of the code
317  has little business with ARM-specific options. */
318  if (GNUNET_YES !=
320  "arm",
321  "CONFIG"))
322  {
323  if (NULL != cc.cfgfile)
325  "arm",
326  "CONFIG",
327  cc.cfgfile);
328  else if (NULL != cfg_fn)
330  "arm",
331  "CONFIG",
332  cfg_fn);
333  }
334 
335  /* run */
336  cc.args = &argv[iret];
337  if ((NULL == cc.cfgfile) && (NULL != cfg_fn))
338  cc.cfgfile = GNUNET_strdup (cfg_fn);
339  if (GNUNET_NO == run_without_scheduler)
340  {
342  }
343  else
344  {
346  cc.task (cc.task_cls, cc.args, cc.cfgfile, cc.cfg);
347  }
348  ret = GNUNET_OK;
349  cleanup:
351  GNUNET_free (cc.cfgfile);
352  GNUNET_free (cfg_fn);
353  GNUNET_free (loglev);
354  GNUNET_free (logfile);
355  return ret;
356 }
357 
358 
361  char *const *argv,
362  const char *binaryName,
363  const char *binaryHelp,
366  void *task_cls)
367 {
368  return GNUNET_PROGRAM_run2 (argc,
369  argv,
370  binaryName,
371  binaryHelp,
372  options,
373  task,
374  task_cls,
375  GNUNET_NO);
376 }
377 
378 
379 /* end of program.c */
Return the directory where translations are installed (share/locale/)
const char * config_file
Configuration file name (in $XDG_CONFIG_HOME) to use.
char * gettext_domain
Gettext domain for localisation, e.g.
Project-specific data used to help the OS subsystem find installation paths.
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, parse options).
Definition: program.c:360
void(* GNUNET_PROGRAM_Main)(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
Main function that will be run.
#define GNUNET_array_append(arr, len, element)
Append an element to an array (growing the array by one).
char * gettext_path
Gettext directory, e.g.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_load(struct GNUNET_CONFIGURATION_Handle *cfg, const char *filename)
Load configuration.
Context for the command.
Definition: program.c:42
struct GNUNET_GETOPT_CommandLineOption options[]
Definition: 002.c:5
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_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, or when GNUNET_SCHEDULER_shutdown() is being invoked.
Definition: scheduler.c:1331
static void program_main(void *cls)
Initial task called by the scheduler for each program.
Definition: program.c:87
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
void GNUNET_SCHEDULER_run(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Initialize and run scheduler.
Definition: scheduler.c:720
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.
GNUNET_GenericReturnValue
Named constants for return values.
Definition: gnunet_common.h:83
const char * user_config_file
Configuration file name to use (if $XDG_CONFIG_HOME is not set).
#define bindtextdomain(Domainname, Dirname)
Definition: gettext.h:57
Definition of a command line option.
struct GNUNET_CONFIGURATION_Handle * GNUNET_CONFIGURATION_create(void)
Create a new configuration object.
void GNUNET_TIME_set_offset(long long offset)
Set the timestamp offset for this instance.
Definition: time.c:48
const char shortName
Short name of the option.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_logfile(char **logfn)
Allow user to specify log file name (-l option)
char *const * args
Argv argument.
Definition: program.c:47
#define _(String)
GNU gettext support macro.
Definition: platform.h:178
const char * version
String identifying the current project version.
#define textdomain(Domainname)
Definition: gettext.h:56
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_version(const char *version)
Define the option to print the version of the application (-v option)
static void shutdown_task(void *cls)
task run when the scheduler shuts down
Definition: program.c:75
static int cmd_sorter(const void *a1, const void *a2)
Compare function for &#39;qsort&#39; to sort command-line arguments by the short option.
Definition: program.c:106
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, the current running apps installation directory.
void GNUNET_CONFIGURATION_destroy(struct GNUNET_CONFIGURATION_Handle *cfg)
Destroy configuration object.
static void cleanup(void *cls)
Function scheduled as very last function, cleans up after us.
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_loglevel(char **level)
Define the &#39;-L&#39; log level option.
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.
char * cfgfile
Name of the configuration file used, can be NULL!
Definition: program.c:52
char * GNUNET_CONFIGURATION_default_filename(void)
Return the filename of the default configuration filename that is used when no explicit configuration...
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
void * task_cls
Closure for task.
Definition: program.c:62
GNUNET_PROGRAM_Main task
Main function to run.
Definition: program.c:57
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.
char * getenv()
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_cfgfile(char **fn)
Allow user to specify configuration file name (-c option)
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, parse options).
Definition: program.c:126
int GNUNET_SPEEDUP_start_(const struct GNUNET_CONFIGURATION_Handle *cfg)
Start task that may speed up our system clock artificially.
Definition: speedup.c:65
configuration data
const char * name
#define GNUNET_log(kind,...)
const struct GNUNET_OS_ProjectData * GNUNET_OS_project_data_get(void)
const struct GNUNET_CONFIGURATION_Handle * cfg
Configuration to use.
Definition: program.c:67
int GNUNET_log_setup(const char *comp, const char *loglevel, const char *logfile)
Setup logging.
void GNUNET_RESOLVER_connect(const struct GNUNET_CONFIGURATION_Handle *cfg)
Create the connection to the resolver service.
Definition: resolver_api.c:257
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
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_free(ptr)
Wrapper around free.
void GNUNET_SPEEDUP_stop_()
Stop tasks that modify clock behavior.
Definition: speedup.c:105