tor_runner.c (2733B)
1 /* Copyright (c) 2001 Matej Pfajfar. 2 * Copyright (c) 2001-2004, Roger Dingledine. 3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. 4 * Copyright (c) 2007-2021, The Tor Project, Inc. */ 5 /* See LICENSE for licensing information */ 6 7 /** 8 * @file tor_runner.c 9 * @brief Experimental module to emulate tor_run_main() API with fork+exec 10 * 11 * The functions here are meant to allow the application developer to 12 * use the tor_run_main() API without having to care whether Tor is 13 * running in-process or out-of-process. For in-process usage, the 14 * developer can link Tor as a library and call tor_run_main(); for 15 * out-of-process usage, the developer can link this library instead. 16 * 17 * This interface is EXPERIMENTAL; please let us know if you would like 18 * to depend on it. We don't know yet whether it will be reliable in 19 * practice. 20 */ 21 22 /* NOTE: This module is supposed to work without the standard Tor utility 23 * functions. Don't add more dependencies! 24 */ 25 26 #include "feature/api/tor_api.h" 27 #include "feature/api/tor_api_internal.h" 28 29 #include "orconfig.h" 30 #ifdef HAVE_UNISTD_H 31 #include <unistd.h> 32 #endif 33 #ifdef HAVE_SYS_WAIT_H 34 #include <sys/wait.h> 35 #endif 36 #ifdef HAVE_SYS_SOCKET_H 37 #include <sys/socket.h> 38 #endif 39 #include <stdlib.h> 40 #include <string.h> 41 42 #ifndef __GNUC__ 43 #define __attribute__(x) 44 #endif 45 46 static void child(const tor_main_configuration_t *cfg) 47 __attribute__((noreturn)); 48 49 const char * 50 tor_api_get_provider_version(void) 51 { 52 return "libtorrunner " VERSION; 53 } 54 55 int 56 tor_run_main(const tor_main_configuration_t *cfg) 57 { 58 pid_t pid = fork(); 59 if (pid == 0) { 60 child(cfg); 61 exit(0); /* Unreachable */ 62 } 63 64 pid_t stopped_pid; 65 int status = 0; 66 do { 67 stopped_pid = waitpid(pid, &status, 0); 68 } while (stopped_pid == -1); 69 70 /* Note: these return values are not documented. No return value is 71 * documented! */ 72 73 if (stopped_pid != pid) { 74 return -99999; 75 } 76 if (WIFSTOPPED(status)) { 77 return WEXITSTATUS(status); 78 } 79 if (WIFSIGNALED(status)) { 80 return -WTERMSIG(status); 81 } 82 83 return -999988; 84 } 85 86 /* circumlocution to avoid getting warned about calling calloc instead of 87 * tor_calloc. */ 88 #define real_calloc calloc 89 #define real_free free 90 91 static void 92 child(const tor_main_configuration_t *cfg) 93 { 94 /* XXXX Close unused file descriptors. */ 95 96 char **args = real_calloc(cfg->argc + cfg->argc_owned+1, sizeof(char *)); 97 memcpy(args, cfg->argv, cfg->argc * sizeof(char *)); 98 if (cfg->argc_owned) 99 memcpy(args + cfg->argc, cfg->argv_owned, 100 cfg->argc_owned * sizeof(char *)); 101 102 args[cfg->argc + cfg->argc_owned] = NULL; 103 104 int rv = execv(BINDIR "/tor", args); 105 106 if (rv < 0) { 107 real_free(args); 108 exit(254); 109 } else { 110 abort(); /* Unreachable */ 111 } 112 }