GNUnet  0.11.x
gnunet-qr.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2013-2019 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 PURPOSE. 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  */
26 #include <stdio.h>
27 #include <zbar.h>
28 #include <stdbool.h>
29 #include "platform.h"
30 #include "gnunet_util_lib.h"
31 
32 #define LOG(fmt, ...) \
33  if (verbose) \
34  printf (fmt, ## __VA_ARGS__)
35 
39 static char *device;
40 
44 static unsigned int verbose;
45 
49 static int silent = false;
50 
54 static long unsigned int exit_code = 0;
55 
59 static struct GNUNET_OS_Process *p;
60 
65 
70 
75 static pid_t my_pid;
76 
83 static void
84 maint_child_death (void *cls)
85 {
87 
88  if ((GNUNET_OK != GNUNET_OS_process_status (p, &type, &exit_code)) ||
89  (type != GNUNET_OS_PROCESS_EXITED))
92  shc_chld = NULL;
93  if (NULL != sigpipe)
94  {
95  GNUNET_DISK_pipe_close (sigpipe);
96  sigpipe = NULL;
97  }
99 }
100 
101 
105 static void
107 {
108  static char c;
109  int old_errno = errno; /* backup errno */
110 
111  if (getpid () != my_pid)
112  _exit (1); /* we have fork'ed since the signal handler was created,
113  * ignore the signal, see https://gnunet.org/vfork discussion */
115  (sigpipe, GNUNET_DISK_PIPE_END_WRITE),
116  &c, sizeof(c));
117  errno = old_errno;
118 }
119 
120 
129 static void
130 gnunet_uri (void *cls,
131  const char *uri,
132  const char *cfgfile,
133  const struct GNUNET_CONFIGURATION_Handle *cfg)
134 {
135  const char *orig_uri;
136  const char *slash;
137  char *subsystem;
138  char *program;
139  struct GNUNET_SCHEDULER_Task *rt;
140 
141  orig_uri = uri;
142  if (0 != strncasecmp ("gnunet://", uri, strlen ("gnunet://")))
143  {
144  fprintf (stderr,
145  _ ("Invalid URI: does not start with `%s'\n"),
146  "gnunet://");
147  return;
148  }
149  uri += strlen ("gnunet://");
150  if (NULL == (slash = strchr (uri, '/')))
151  {
152  fprintf (stderr, _ ("Invalid URI: fails to specify subsystem\n"));
153  return;
154  }
155  subsystem = GNUNET_strndup (uri, slash - uri);
156  if (GNUNET_OK !=
157  GNUNET_CONFIGURATION_get_value_string (cfg, "uri", subsystem, &program))
158  {
159  fprintf (stderr, _ ("No handler known for subsystem `%s'\n"), subsystem);
160  GNUNET_free (subsystem);
161  return;
162  }
163  GNUNET_free (subsystem);
165  GNUNET_assert (NULL != sigpipe);
170  NULL);
171  my_pid = getpid ();
172  shc_chld = GNUNET_SIGNAL_handler_install (SIGCHLD,
173  &sighandler_chld);
174 
175  {
176  char **argv = NULL;
177  unsigned int argc = 0;
178  char *u = GNUNET_strdup (program);
179 
180  for (const char *tok = strtok (u, " ");
181  NULL != tok;
182  tok = strtok (NULL, " "))
183  GNUNET_array_append (argv,
184  argc,
185  GNUNET_strdup (tok));
186  GNUNET_array_append (argv,
187  argc,
188  GNUNET_strdup (orig_uri));
189  GNUNET_array_append (argv,
190  argc,
191  NULL);
193  NULL,
194  NULL,
195  NULL,
196  argv[0],
197  argv);
198  for (unsigned int i = 0; i<argc - 1; i++)
199  GNUNET_free (argv[i]);
200  GNUNET_array_grow (argv,
201  argc,
202  0);
203  GNUNET_free (u);
204  }
205  if (NULL == p)
207  GNUNET_free (program);
208 }
209 
210 
217 static const zbar_symbol_t *
218 get_symbol (zbar_processor_t *proc)
219 {
220  const zbar_symbol_set_t *symbols;
221  int rc;
222  int n;
223 
224  if (0 != zbar_processor_parse_config (proc, "enable"))
225  {
226  GNUNET_break (0);
227  return NULL;
228  }
229 
230  /* initialize the Processor */
231  if (NULL == device)
232  device = GNUNET_strdup ("/dev/video0");
233  if (0 != (rc = zbar_processor_init (proc, device, 1)))
234  {
236  "Failed to open device `%s': %d\n",
237  device,
238  rc);
239  return NULL;
240  }
241 
242  /* enable the preview window */
243  if ((0 != (rc = zbar_processor_set_visible (proc, 1))) ||
244  (0 != (rc = zbar_processor_set_active (proc, 1))))
245  {
246  GNUNET_break (0);
247  return NULL;
248  }
249 
250  /* read at least one barcode (or until window closed) */
251  LOG ("Capturing\n");
252  n = zbar_process_one (proc, -1);
253 
254  /* hide the preview window */
255  (void) zbar_processor_set_active (proc, 0);
256  (void) zbar_processor_set_visible (proc, 0);
257  if (-1 == n)
258  return NULL; /* likely user closed the window */
259  LOG ("Got %i images\n", n);
260  /* extract results */
261  symbols = zbar_processor_get_results (proc);
262  if (NULL == symbols)
263  {
264  GNUNET_break (0);
265  return NULL;
266  }
267  return zbar_symbol_set_first_symbol (symbols);
268 }
269 
270 
276 static char *
278 {
279  zbar_processor_t *proc;
280  const char *data;
281  char *ret;
282  const zbar_symbol_t *symbol;
283 
284  /* configure the Processor */
285  proc = zbar_processor_create (1);
286  if (NULL == proc)
287  {
288  GNUNET_break (0);
289  return NULL;
290  }
291 
292  symbol = get_symbol (proc);
293  if (NULL == symbol)
294  {
295  zbar_processor_destroy (proc);
296  return NULL;
297  }
298  data = zbar_symbol_get_data (symbol);
299  if (NULL == data)
300  {
301  GNUNET_break (0);
302  zbar_processor_destroy (proc);
303  return NULL;
304  }
305  LOG ("Found %s \"%s\"\n",
306  zbar_get_symbol_name (zbar_symbol_get_type (symbol)),
307  data);
308  ret = GNUNET_strdup (data);
309  /* clean up */
310  zbar_processor_destroy (proc);
312  return ret;
313 }
314 
315 
324 static void
325 run (void *cls,
326  char *const *args,
327  const char *cfgfile,
328  const struct GNUNET_CONFIGURATION_Handle *cfg)
329 {
330  char *data;
331 
332  data = run_zbar ();
333  if (NULL == data)
334  return;
335  gnunet_uri (cls, data, cfgfile, cfg);
336  if (exit_code != 0)
337  {
338  printf ("Failed to add URI %s\n", data);
339  }
340  else
341  {
342  printf ("Added URI %s\n", data);
343  }
344  GNUNET_free (data);
345 };
346 
347 
348 int
349 main (int argc, char *const *argv)
350 {
351  int ret;
352  struct GNUNET_GETOPT_CommandLineOption options[] = {
354  'd',
355  "device",
356  "DEVICE",
357  gettext_noop ("use video-device DEVICE (default: /dev/video0"),
358  &device),
361  "silent",
362  gettext_noop ("do not show preview windows"),
363  &silent),
365  };
366 
367  ret = GNUNET_PROGRAM_run (
368  argc,
369  argv,
370  "gnunet-qr",
371  gettext_noop (
372  "Scan a QR code using a video device and import the uri read"),
373  options,
374  &run,
375  NULL);
376  return ((GNUNET_OK == ret) && (0 == exit_code)) ? 0 : 1;
377 }
No special options, use non-blocking read/write operations.
static char * subsystem
Set to subsystem that we&#39;re going to get stats for (or NULL for all).
static void sighandler_chld()
Signal handler called for signals that causes us to wait for the child process.
Definition: gnunet-qr.c:106
struct GNUNET_OS_Process * GNUNET_OS_start_process_vap(enum GNUNET_OS_InheritStdioFlags std_inheritance, struct GNUNET_DISK_PipeHandle *pipe_stdin, struct GNUNET_DISK_PipeHandle *pipe_stdout, struct GNUNET_DISK_PipeHandle *pipe_stderr, const char *filename, char *const argv[])
Start a process.
Definition: os_priority.c:604
static const struct GNUNET_CONFIGURATION_Handle * cfg
Configuration we are using.
Definition: gnunet-abd.c:36
#define GNUNET_array_append(arr, len, element)
Append an element to an array (growing the array by one).
static struct GNUNET_DISK_PipeHandle * sigpipe
Pipe used to communicate child death via signal.
Definition: gnunet-qr.c:69
void GNUNET_OS_process_destroy(struct GNUNET_OS_Process *proc)
Cleans up process structure contents (OS-dependent) and deallocates it.
Definition: os_priority.c:287
static char * device
Video device to capture from.
Definition: gnunet-qr.c:39
int GNUNET_OS_process_status(struct GNUNET_OS_Process *proc, enum GNUNET_OS_ProcessStatusType *type, unsigned long *code)
Retrieve the status of a process.
Definition: os_priority.c:946
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_verbose(unsigned int *level)
Define the &#39;-V&#39; verbosity option.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
static const zbar_symbol_t * get_symbol(zbar_processor_t *proc)
Obtain QR code &#39;symbol&#39; from proc.
Definition: gnunet-qr.c:218
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_read_file(struct GNUNET_TIME_Relative delay, const struct GNUNET_DISK_FileHandle *rfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition: scheduler.c:1667
void GNUNET_SIGNAL_handler_uninstall(struct GNUNET_SIGNAL_Context *ctx)
Uninstall a previously installed signal hander.
Definition: signal.c:77
Definition of a command line option.
static void gnunet_uri(void *cls, const char *uri, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
Dispatch URIs to the appropriate GNUnet helper process.
Definition: gnunet-qr.c:130
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
const struct GNUNET_DISK_FileHandle * GNUNET_DISK_pipe_handle(const struct GNUNET_DISK_PipeHandle *p, enum GNUNET_DISK_PipeEnd n)
Get the handle to a particular pipe end.
Definition: disk.c:1672
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_OPTION_END
Definition: 002.c:13
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_string(char shortName, const char *name, const char *argumentHelp, const char *description, char **str)
Allow user to specify a string.
#define _(String)
GNU gettext support macro.
Definition: platform.h:184
static struct GNUNET_FS_Uri * uri
Value of URI provided on command-line (when not publishing a file but just creating UBlocks to refer ...
Use this option to have all of the standard streams (stdin, stdout and stderror) be inherited...
int main(int argc, char *const *argv)
Definition: gnunet-qr.c:349
#define GNUNET_array_grow(arr, size, tsize)
Grow a well-typed (!) array.
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-qr.c:59
static int silent
–silent option
Definition: gnunet-qr.c:49
ssize_t GNUNET_DISK_file_write(const struct GNUNET_DISK_FileHandle *h, const void *buffer, size_t n)
Write a buffer to a file.
Definition: disk.c:820
GNUNET_OS_ProcessStatusType
Process status types.
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
The writing-end of a pipe.
The reading-end of a pipe.
The process exited with a return code.
struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe(enum GNUNET_DISK_PipeFlags pf)
Creates an interprocess channel.
Definition: disk.c:1456
int GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
static char * run_zbar()
Run zbar QR code parser.
Definition: gnunet-qr.c:277
struct GNUNET_SIGNAL_Context * GNUNET_SIGNAL_handler_install(int signal, GNUNET_SIGNAL_Handler handler)
Install a signal handler that will be run if the given signal is received.
Definition: signal.c:51
static unsigned int verbose
–verbose option
Definition: gnunet-qr.c:44
int GNUNET_DISK_pipe_close(struct GNUNET_DISK_PipeHandle *p)
Closes an interprocess channel.
Definition: disk.c:1634
#define GNUNET_strndup(a, length)
Wrapper around GNUNET_xstrndup_.
#define LOG(fmt,...)
Definition: gnunet-qr.c:32
configuration data
Definition: configuration.c:84
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_flag(char shortName, const char *name, const char *description, int *val)
Allow user to specify a flag (which internally means setting an integer to 1/GNUNET_YES/GNUNET_OK.
#define GNUNET_log(kind,...)
Entry in list of pending tasks.
Definition: scheduler.c:134
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
static struct GNUNET_SIGNAL_Context * shc_chld
Child signal handler.
Definition: gnunet-qr.c:64
enum GNUNET_TESTBED_UnderlayLinkModelType type
the type of this model
static pid_t my_pid
Process ID of this process at the time we installed the various signal handlers.
Definition: gnunet-qr.c:75
#define GNUNET_TERM_SIG
The termination signal.
Definition: platform.h:246
uint32_t data
The data value.
static void run(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
Main function that will be run by the scheduler.
Definition: gnunet-qr.c:325
Handle used to manage a pipe.
Definition: disk.c:68
#define GNUNET_free(ptr)
Wrapper around free.
static void maint_child_death(void *cls)
Task triggered whenever we receive a SIGCHLD (child process died) or when user presses CTRL-C...
Definition: gnunet-qr.c:84
#define gettext_noop(String)
Definition: gettext.h:69
int GNUNET_OS_process_kill(struct GNUNET_OS_Process *proc, int sig)
Sends a signal to the process.
Definition: os_priority.c:225
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:972
static long unsigned int exit_code
Handler exit code.
Definition: gnunet-qr.c:54