/* This file is part of GNUnet. Copyright (C) 2013-2019 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . SPDX-License-Identifier: AGPL3.0-or-later */ /** * @file util/gnunet-qr.c * @author Hartmut Goebel (original implementation) * @author Martin Schanzenbach (integrate gnunet-uri) * @author Christian Grothoff (error handling) */ #include #include #include #include #include "platform.h" #include "gnunet_util_lib.h" #if HAVE_PNG #include #endif /** * Global exit code. * Set to non-zero if an error occurs after the scheduler has started. */ static int exit_code = 0; /** * Video device to capture from. * Used by default if PNG support is disabled or no PNG file is specified. * Defaults to /dev/video0. */ static char *device = NULL; #if HAVE_PNG /** * Name of the file to read from. * If the file is not a PNG-encoded image of a QR code, an error will be * thrown. */ static char *pngfilename = NULL; #endif /** * Requested verbosity. */ static unsigned int verbosity = 0; /** * Child process handle. */ struct GNUNET_OS_Process *childproc = NULL; /** * Child process handle for waiting. */ static struct GNUNET_ChildWaitHandle *waitchildproc = NULL; /** * Macro to handle verbosity when printing messages. */ #define LOG(fmt, ...) \ do \ { \ if (0 < verbosity) \ { \ GNUNET_log (GNUNET_ERROR_TYPE_INFO, fmt, ##__VA_ARGS__); \ if (verbosity > 1) \ { \ fprintf (stdout, fmt, ##__VA_ARGS__); \ } \ } \ } \ while (0) /** * Executed when program is terminating. */ static void shutdown_program (void *cls) { if (NULL != waitchildproc) { GNUNET_wait_child_cancel (waitchildproc); } if (NULL != childproc) { /* A bit brutal, but this process is terminating so we're out of time */ GNUNET_OS_process_kill (childproc, SIGKILL); } } /** * Callback executed when the child process terminates. * * @param cls closure * @param type status of the child process * @param code the exit code of the child process */ static void wait_child (void *cls, enum GNUNET_OS_ProcessStatusType type, long unsigned int code) { GNUNET_OS_process_destroy (childproc); childproc = NULL; waitchildproc = NULL; char *uri = cls; if (0 != exit_code) { fprintf (stdout, _("Failed to add URI %s\n"), uri); } else { fprintf (stdout, _("Added URI %s\n"), uri); } GNUNET_free (uri); GNUNET_SCHEDULER_shutdown (); } /** * Dispatch URIs to the appropriate GNUnet helper process. * * @param cls closure * @param uri URI to dispatch * @param cfgfile name of the configuration file in use * @param cfg the configuration in use */ static void handle_uri (void *cls, const char *uri, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { const char *cursor = uri; if (0 != strncasecmp ("gnunet://", uri, strlen ("gnunet://"))) { fprintf (stderr, _("Invalid URI: does not start with `gnunet://'\n")); exit_code = 1; return; } cursor += strlen ("gnunet://"); const char *slash = strchr (cursor, '/'); if (NULL == slash) { fprintf (stderr, _("Invalid URI: fails to specify a subsystem\n")); exit_code = 1; return; } char *subsystem = GNUNET_strndup (cursor, slash - cursor); char *program = NULL; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "uri", subsystem, &program)) { fprintf (stderr, _("No known handler for subsystem `%s'\n"), subsystem); GNUNET_free (subsystem); exit_code = 1; return; } GNUNET_free (subsystem); char **childargv = NULL; unsigned int childargc = 0; for (const char *token=strtok (program, " "); NULL!=token; token=strtok(NULL, " ")) { GNUNET_array_append (childargv, childargc, GNUNET_strdup (token)); } GNUNET_array_append (childargv, childargc, GNUNET_strdup (uri)); GNUNET_array_append (childargv, childargc, NULL); childproc = GNUNET_OS_start_process_vap (GNUNET_OS_INHERIT_STD_ALL, NULL, NULL, NULL, childargv[0], childargv); for (size_t i=0; i