GNUnet  0.10.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 
46  char *const *args;
47 
51  char *cfgfile;
52 
57 
61  void *task_cls;
62 
67 };
68 
69 
73 static void
74 shutdown_task(void *cls)
75 {
76  (void)cls;
78 }
79 
80 
85 static void
86 program_main(void *cls)
87 {
88  struct CommandContext *cc = cls;
89 
93  cc->task(cc->task_cls, cc->args, cc->cfgfile, cc->cfg);
94 }
95 
96 
104 static int
105 cmd_sorter(const void *a1, const void *a2)
106 {
107  const struct GNUNET_GETOPT_CommandLineOption *c1 = a1;
108  const struct GNUNET_GETOPT_CommandLineOption *c2 = a2;
109 
110  if (toupper((unsigned char)c1->shortName) >
111  toupper((unsigned char)c2->shortName))
112  return 1;
113  if (toupper((unsigned char)c1->shortName) <
114  toupper((unsigned char)c2->shortName))
115  return -1;
116  if (c1->shortName > c2->shortName)
117  return 1;
118  if (c1->shortName < c2->shortName)
119  return -1;
120  return 0;
121 }
122 
123 
139 int
141  char *const *argv,
142  const char *binaryName,
143  const char *binaryHelp,
146  void *task_cls,
147  int run_without_scheduler)
148 {
149  struct CommandContext cc;
150 
151 #if ENABLE_NLS
152  char *path;
153 #endif
154  char *loglev;
155  char *logfile;
156  char *cfg_fn;
157  const char *xdg;
158  int ret;
159  unsigned int cnt;
160  unsigned long long skew_offset;
161  unsigned long long skew_variance;
162  long long clock_offset;
165  struct GNUNET_GETOPT_CommandLineOption defoptions[] =
167  GNUNET_GETOPT_option_help(binaryHelp),
171  struct GNUNET_GETOPT_CommandLineOption *allopts;
172  const char *gargs;
173  char *lpfx;
174  char *spc;
175 
176  logfile = NULL;
177  gargs = getenv("GNUNET_ARGS");
178  if (NULL != gargs)
179  {
180  char **gargv;
181  unsigned int gargc;
182  char *cargs;
183 
184  gargv = NULL;
185  gargc = 0;
186  for (int i = 0; i < argc; i++)
187  GNUNET_array_append(gargv, gargc, GNUNET_strdup(argv[i]));
188  cargs = GNUNET_strdup(gargs);
189  for (char *tok = strtok(cargs, " "); NULL != tok; tok = strtok(NULL, " "))
190  GNUNET_array_append(gargv, gargc, GNUNET_strdup(tok));
191  GNUNET_free(cargs);
192  GNUNET_array_append(gargv, gargc, NULL);
193  argv = (char *const *)gargv;
194  argc = gargc - 1;
195  }
196  memset(&cc, 0, sizeof(cc));
197  loglev = NULL;
198  cc.task = task;
199  cc.task_cls = task_cls;
200  cc.cfg = cfg = GNUNET_CONFIGURATION_create();
201  /* prepare */
202 #if ENABLE_NLS
203  if (NULL != pd->gettext_domain)
204  {
205  setlocale(LC_ALL, "");
206  path = (NULL == pd->gettext_path)
209  if (NULL != path)
210  {
211  bindtextdomain(pd->gettext_domain, path);
212  GNUNET_free(path);
213  }
215  }
216 #endif
217  cnt = 0;
218  while (NULL != options[cnt].name)
219  cnt++;
220  allopts =
221  GNUNET_malloc((cnt + 1) * sizeof(struct GNUNET_GETOPT_CommandLineOption) +
222  sizeof(defoptions));
223  GNUNET_memcpy(allopts, defoptions, sizeof(defoptions));
224  GNUNET_memcpy(&allopts[sizeof(defoptions) /
225  sizeof(struct GNUNET_GETOPT_CommandLineOption)],
226  options,
227  (cnt + 1) * sizeof(struct GNUNET_GETOPT_CommandLineOption));
228  cnt += sizeof(defoptions) / sizeof(struct GNUNET_GETOPT_CommandLineOption);
229  qsort(allopts,
230  cnt,
231  sizeof(struct GNUNET_GETOPT_CommandLineOption),
232  &cmd_sorter);
233  loglev = NULL;
234  xdg = getenv("XDG_CONFIG_HOME");
235  if (NULL != xdg)
236  GNUNET_asprintf(&cfg_fn,
237  "%s%s%s",
238  xdg,
240  pd->config_file);
241  else
242  cfg_fn = GNUNET_strdup(pd->user_config_file);
243  lpfx = GNUNET_strdup(binaryName);
244  if (NULL != (spc = strstr(lpfx, " ")))
245  *spc = '\0';
246  ret = GNUNET_GETOPT_run(binaryName, allopts, (unsigned int)argc, argv);
247  if ((GNUNET_OK > ret) ||
248  (GNUNET_OK != GNUNET_log_setup(lpfx, loglev, logfile)))
249  {
250  GNUNET_free(allopts);
251  GNUNET_free(lpfx);
252  goto cleanup;
253  }
254  if (NULL != cc.cfgfile)
255  {
258  {
260  _(
261  "Unreadable or malformed configuration file `%s', exit ...\n"),
262  cc.cfgfile);
263  ret = GNUNET_SYSERR;
264  GNUNET_free(allopts);
265  GNUNET_free(lpfx);
266  goto cleanup;
267  }
268  }
269  else
270  {
271  if (GNUNET_YES == GNUNET_DISK_file_test(cfg_fn))
272  {
273  if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load(cfg, cfg_fn))
274  {
275  GNUNET_log(
277  _(
278  "Unreadable or malformed default configuration file `%s', exit ...\n"),
279  cfg_fn);
280  ret = GNUNET_SYSERR;
281  GNUNET_free(allopts);
282  GNUNET_free(lpfx);
283  goto cleanup;
284  }
285  }
286  else
287  {
288  GNUNET_free(cfg_fn);
289  cfg_fn = NULL;
290  if (GNUNET_OK != GNUNET_CONFIGURATION_load(cfg, NULL))
291  {
293  _("Unreadable or malformed configuration, exit ...\n"));
294  ret = GNUNET_SYSERR;
295  GNUNET_free(allopts);
296  GNUNET_free(lpfx);
297  goto cleanup;
298  }
299  }
300  }
301  GNUNET_free(allopts);
302  GNUNET_free(lpfx);
304  "testing",
305  "skew_offset",
306  &skew_offset) &&
308  "testing",
309  "skew_variance",
310  &skew_variance)))
311  {
312  clock_offset = skew_offset - skew_variance;
313  GNUNET_TIME_set_offset(clock_offset);
314  }
315  /* ARM needs to know which configuration file to use when starting
316  services. If we got a command-line option *and* if nothing is
317  specified in the configuration, remember the command-line option
318  in "cfg". This is typically really only having an effect if we
319  are running code in src/arm/, as obviously the rest of the code
320  has little business with ARM-specific options. */
321  if (GNUNET_YES != GNUNET_CONFIGURATION_have_value(cfg, "arm", "CONFIG"))
322  {
323  if (NULL != cc.cfgfile)
324  GNUNET_CONFIGURATION_set_value_string(cfg, "arm", "CONFIG", cc.cfgfile);
325  else if (NULL != cfg_fn)
326  GNUNET_CONFIGURATION_set_value_string(cfg, "arm", "CONFIG", cfg_fn);
327  }
328 
329  /* run */
330  cc.args = &argv[ret];
331  if ((NULL == cc.cfgfile) && (NULL != cfg_fn))
332  cc.cfgfile = GNUNET_strdup(cfg_fn);
333  if (GNUNET_NO == run_without_scheduler)
334  {
336  }
337  else
338  {
340  cc.task(cc.task_cls, cc.args, cc.cfgfile, cc.cfg);
341  }
342  ret = GNUNET_OK;
343 cleanup:
346  GNUNET_free_non_null(cfg_fn);
347  GNUNET_free_non_null(loglev);
348  GNUNET_free_non_null(logfile);
349  return ret;
350 }
351 
352 
366 int
368  char *const *argv,
369  const char *binaryName,
370  const char *binaryHelp,
373  void *task_cls)
374 {
375  return GNUNET_PROGRAM_run2(argc,
376  argv,
377  binaryName,
378  binaryHelp,
379  options,
380  task,
381  task_cls,
382  GNUNET_NO);
383 }
384 
385 
386 /* end of program.c */
int 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:541
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.
void(* GNUNET_PROGRAM_Main)(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
Main function that will be run.
int 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.
char * gettext_path
Gettext directory, e.g.
Context for the command.
Definition: program.c:42
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)
Run a standard GNUnet command startup sequence (initialize loggers and configuration, parse options).
Definition: program.c:140
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:1284
static void program_main(void *cls)
Initial task called by the scheduler for each program.
Definition: program.c:86
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
void GNUNET_SCHEDULER_run(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Initialize and run scheduler.
Definition: scheduler.c:707
const char * user_config_file
Configuration file name to use (if $XDG_CONFIG_HOME is not set).
#define GNUNET_NO
Definition: gnunet_common.h:78
#define bindtextdomain(Domainname, Dirname)
Definition: gettext.h:57
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
#define GNUNET_free_non_null(ptr)
Free the memory pointed to by ptr if ptr is not NULL.
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:53
static int ret
Final status code.
Definition: gnunet-arm.c:89
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:46
int GNUNET_CONFIGURATION_load(struct GNUNET_CONFIGURATION_Handle *cfg, const char *filename)
Load configuration.
#define _(String)
GNU gettext support macro.
Definition: platform.h:181
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)
int GNUNET_asprintf(char **buf, const char *format,...)
Like asprintf, just portable.
static void shutdown_task(void *cls)
task run when the scheduler shuts down
Definition: program.c:74
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:105
#define DIR_SEPARATOR_STR
Definition: platform.h:168
int 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 * 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:51
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:886
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
void * task_cls
Closure for task.
Definition: program.c:61
GNUNET_PROGRAM_Main task
Main function to run.
Definition: program.c:56
const char * name
char * getenv()
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_cfgfile(char **fn)
Allow user to specify configuration file name (-c option)
#define GNUNET_array_append(arr, size, element)
Append an element to a list (growing the list by one).
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
Definition: configuration.c:83
#define GNUNET_log(kind,...)
const struct GNUNET_OS_ProjectData * GNUNET_OS_project_data_get(void)
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)
Run a standard GNUnet command startup sequence (initialize loggers and configuration, parse options).
Definition: program.c:367
#define GNUNET_YES
Definition: gnunet_common.h:77
const struct GNUNET_CONFIGURATION_Handle * cfg
Configuration to use.
Definition: program.c:66
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:252
#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