gnunet

Main GNUnet Logic
Log | Files | Refs | Submodules | README | LICENSE

gnunet-uri.c (5689B)


      1 /*
      2      This file is part of GNUnet.
      3      Copyright (C) 2012 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  */
     20 
     21 /**
     22  * @file util/gnunet-uri.c
     23  * @brief tool to dispatch URIs to the appropriate GNUnet helper process
     24  * @author Christian Grothoff
     25  */
     26 
     27 #include "platform.h"
     28 #include "gnunet_util_lib.h"
     29 
     30 /**
     31  * Handler exit code
     32  */
     33 static long unsigned int exit_code = 0;
     34 
     35 /**
     36  * Helper process we started.
     37  */
     38 static struct GNUNET_Process *p;
     39 
     40 /**
     41  * Pipe used to communicate shutdown via signal.
     42  */
     43 static struct GNUNET_DISK_PipeHandle *sigpipe;
     44 
     45 
     46 /**
     47  * Task triggered whenever we receive a SIGCHLD (child
     48  * process died) or when user presses CTRL-C.
     49  *
     50  * @param cls closure, NULL
     51  */
     52 static void
     53 maint_child_death (void *cls)
     54 {
     55   enum GNUNET_OS_ProcessStatusType type;
     56 
     57   (void) cls;
     58   if ((GNUNET_OK !=
     59        GNUNET_process_wait (p,
     60                             false,
     61                             &type,
     62                             &exit_code)) ||
     63       (type != GNUNET_OS_PROCESS_EXITED))
     64     GNUNET_break (GNUNET_OK ==
     65                   GNUNET_process_kill (p,
     66                                        GNUNET_TERM_SIG));
     67   GNUNET_process_destroy (p);
     68 }
     69 
     70 
     71 /**
     72  * Main function that will be run by the scheduler.
     73  *
     74  * @param cls closure
     75  * @param args remaining command-line arguments
     76  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
     77  * @param cfg configuration
     78  */
     79 static void
     80 run (void *cls,
     81      char *const *args,
     82      const char *cfgfile,
     83      const struct GNUNET_CONFIGURATION_Handle *cfg)
     84 {
     85   const char *uri;
     86   const char *slash;
     87   char *program;
     88   struct GNUNET_SCHEDULER_Task *rt;
     89 
     90   (void) cls;
     91   (void) cfgfile;
     92   if (NULL == (uri = args[0]))
     93   {
     94     fprintf (stderr,
     95              _ ("No URI specified on command line\n"));
     96     return;
     97   }
     98   if (0 != strncasecmp ("gnunet://",
     99                         uri,
    100                         strlen ("gnunet://")))
    101   {
    102     fprintf (stderr,
    103              _ ("Invalid URI: does not start with `%s'\n"),
    104              "gnunet://");
    105     return;
    106   }
    107   uri += strlen ("gnunet://");
    108   if (NULL == (slash = strchr (uri, '/')))
    109   {
    110     fprintf (stderr,
    111              _ ("Invalid URI: fails to specify subsystem\n"));
    112     return;
    113   }
    114 
    115   {
    116     char *subsystem;
    117 
    118     subsystem = GNUNET_strndup (uri,
    119                                 slash - uri);
    120     if (GNUNET_OK !=
    121         GNUNET_CONFIGURATION_get_value_string (cfg,
    122                                                "uri",
    123                                                subsystem,
    124                                                &program))
    125     {
    126       fprintf (stderr,
    127                _ ("No handler known for subsystem `%s'\n"),
    128                subsystem);
    129       GNUNET_free (subsystem);
    130       return;
    131     }
    132     GNUNET_free (subsystem);
    133   }
    134   rt = GNUNET_SCHEDULER_add_read_file (
    135     GNUNET_TIME_UNIT_FOREVER_REL,
    136     GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ),
    137     &maint_child_death,
    138     NULL);
    139   p = GNUNET_process_create (GNUNET_OS_INHERIT_STD_NONE);
    140   if (GNUNET_OK !=
    141       GNUNET_process_run_command_va (p,
    142                                      program,
    143                                      program,
    144                                      args[0],
    145                                      NULL))
    146   {
    147     GNUNET_process_destroy (p);
    148     p = NULL;
    149     GNUNET_SCHEDULER_cancel (rt);
    150   }
    151   GNUNET_free (program);
    152 }
    153 
    154 
    155 /**
    156  * Signal handler called for SIGCHLD.  Triggers the
    157  * respective handler by writing to the trigger pipe.
    158  */
    159 static void
    160 sighandler_child_death ()
    161 {
    162   static char c;
    163   int old_errno = errno; /* back-up errno */
    164 
    165   GNUNET_break (
    166     1 ==
    167     GNUNET_DISK_file_write (
    168       GNUNET_DISK_pipe_handle (sigpipe,
    169                                GNUNET_DISK_PIPE_END_WRITE),
    170       &c,
    171       sizeof(c)));
    172   errno = old_errno; /* restore errno */
    173 }
    174 
    175 
    176 /**
    177  * The main function to handle gnunet://-URIs.
    178  *
    179  * @param argc number of arguments from the command line
    180  * @param argv command line arguments
    181  * @return 0 ok, 1 on error
    182  */
    183 int
    184 main (int argc,
    185       char *const *argv)
    186 {
    187   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
    188     GNUNET_GETOPT_OPTION_END
    189   };
    190   struct GNUNET_SIGNAL_Context *shc_chld;
    191   int ret;
    192 
    193   sigpipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE);
    194   GNUNET_assert (sigpipe != NULL);
    195   shc_chld =
    196     GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD,
    197                                    &sighandler_child_death);
    198   ret = GNUNET_PROGRAM_run (GNUNET_OS_project_data_gnunet (),
    199                             argc,
    200                             argv,
    201                             "gnunet-uri URI",
    202                             gettext_noop (
    203                               "Perform default-actions for GNUnet URIs"),
    204                             options,
    205                             &run,
    206                             NULL);
    207   GNUNET_SIGNAL_handler_uninstall (shc_chld);
    208   shc_chld = NULL;
    209   GNUNET_DISK_pipe_close (sigpipe);
    210   sigpipe = NULL;
    211   return ((GNUNET_OK == ret) && (0 == exit_code)) ? 0 : 1;
    212 }
    213 
    214 
    215 /* end of gnunet-uri.c */