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 */