subsysmgr.c (13090B)
1 /* Copyright (c) 2003-2004, Roger Dingledine 2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. 3 * Copyright (c) 2007-2021, The Tor Project, Inc. */ 4 /* See LICENSE for licensing information */ 5 6 /** 7 * @file subsysmgr.c 8 * @brief Manager for Tor's subsystems. 9 * 10 * This code is responsible for initializing, configuring, and shutting 11 * down all of Tor's individual subsystems. 12 **/ 13 14 #include "orconfig.h" 15 #include "app/main/subsysmgr.h" 16 17 #include "lib/confmgt/confmgt.h" 18 #include "lib/dispatch/dispatch_naming.h" 19 #include "lib/dispatch/msgtypes.h" 20 #include "lib/err/torerr.h" 21 #include "lib/log/log.h" 22 #include "lib/log/util_bug.h" 23 #include "lib/malloc/malloc.h" 24 #include "lib/pubsub/pubsub_build.h" 25 #include "lib/pubsub/pubsub_connect.h" 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 31 /** 32 * True iff we have checked tor_subsystems for consistency. 33 **/ 34 static bool subsystem_array_validated = false; 35 36 /** Index value indicating that a subsystem has no options/state object, and 37 * so that object does not have an index. */ 38 #define IDX_NONE (-1) 39 40 /** 41 * Runtime status of a single subsystem. 42 **/ 43 typedef struct subsys_status_t { 44 /** True if the given subsystem is initialized. */ 45 bool initialized; 46 /** Index for this subsystem's options object, or IDX_NONE for none. */ 47 int options_idx; 48 /** Index for this subsystem's state object, or IDX_NONE for none. */ 49 int state_idx; 50 } subsys_status_t; 51 52 /** An overestimate of the number of subsystems. */ 53 #define N_SYS_STATUS 128 54 /** 55 * True if a given subsystem is initialized. Expand this array if there 56 * are more than this number of subsystems. (We'd rather not 57 * dynamically allocate in this module.) 58 **/ 59 static subsys_status_t sys_status[N_SYS_STATUS]; 60 61 /** Set <b>status</b> to a default (not set-up) state. */ 62 static void 63 subsys_status_clear(subsys_status_t *status) 64 { 65 if (!status) 66 return; 67 memset(status, 0, sizeof(*status)); 68 status->initialized = false; 69 status->state_idx = IDX_NONE; 70 status->options_idx = IDX_NONE; 71 } 72 73 /** 74 * Exit with a raw assertion if the subsystems list is inconsistent; 75 * initialize the subsystem_initialized array. 76 **/ 77 static void 78 check_and_setup(void) 79 { 80 if (subsystem_array_validated) 81 return; 82 83 raw_assert(ARRAY_LENGTH(sys_status) >= n_tor_subsystems); 84 memset(sys_status, 0, sizeof(sys_status)); 85 86 int last_level = MIN_SUBSYS_LEVEL; 87 88 for (unsigned i = 0; i < n_tor_subsystems; ++i) { 89 const subsys_fns_t *sys = tor_subsystems[i]; 90 if (sys->level < MIN_SUBSYS_LEVEL || sys->level > MAX_SUBSYS_LEVEL) { 91 fprintf(stderr, "BUG: Subsystem %s (at %u) has an invalid level %d. " 92 "It is supposed to be between %d and %d (inclusive).\n", 93 sys->name, i, sys->level, MIN_SUBSYS_LEVEL, MAX_SUBSYS_LEVEL); 94 raw_assert_unreached_msg("There is a bug in subsystem_list.c"); 95 } 96 if (sys->level < last_level) { 97 fprintf(stderr, "BUG: Subsystem %s (at #%u) is in the wrong position. " 98 "Its level is %d; but the previous subsystem's level was %d.\n", 99 sys->name, i, sys->level, last_level); 100 raw_assert_unreached_msg("There is a bug in subsystem_list.c"); 101 } 102 subsys_status_clear(&sys_status[i]); 103 104 last_level = sys->level; 105 } 106 107 subsystem_array_validated = true; 108 } 109 110 /** 111 * Initialize all the subsystems; exit on failure. 112 **/ 113 int 114 subsystems_init(void) 115 { 116 return subsystems_init_upto(MAX_SUBSYS_LEVEL); 117 } 118 119 /** 120 * Initialize all the subsystems whose level is less than or equal to 121 * <b>target_level</b>; exit on failure. 122 **/ 123 int 124 subsystems_init_upto(int target_level) 125 { 126 check_and_setup(); 127 128 for (unsigned i = 0; i < n_tor_subsystems; ++i) { 129 const subsys_fns_t *sys = tor_subsystems[i]; 130 if (!sys->supported) 131 continue; 132 if (sys->level > target_level) 133 break; 134 if (sys_status[i].initialized) 135 continue; 136 int r = 0; 137 if (sys->initialize) { 138 // Note that the logging subsystem is designed so that it does no harm 139 // to log a message in an uninitialized state. These messages will be 140 // discarded for now, however. 141 log_debug(LD_GENERAL, "Initializing %s", sys->name); 142 r = sys->initialize(); 143 } 144 if (r < 0) { 145 fprintf(stderr, "BUG: subsystem %s (at %u) initialization failed.\n", 146 sys->name, i); 147 raw_assert_unreached_msg("A subsystem couldn't be initialized."); 148 } 149 sys_status[i].initialized = true; 150 } 151 152 return 0; 153 } 154 155 /** 156 * Add publish/subscribe relationships to <b>builder</b> for all 157 * initialized subsystems of level no more than <b>target_level</b>. 158 **/ 159 int 160 subsystems_add_pubsub_upto(pubsub_builder_t *builder, 161 int target_level) 162 { 163 for (unsigned i = 0; i < n_tor_subsystems; ++i) { 164 const subsys_fns_t *sys = tor_subsystems[i]; 165 if (!sys->supported) 166 continue; 167 if (sys->level > target_level) 168 break; 169 if (! sys_status[i].initialized) 170 continue; 171 int r = 0; 172 if (sys->add_pubsub) { 173 subsys_id_t sysid = get_subsys_id(sys->name); 174 raw_assert(sysid != ERROR_ID); 175 pubsub_connector_t *connector; 176 connector = pubsub_connector_for_subsystem(builder, sysid); 177 r = sys->add_pubsub(connector); 178 pubsub_connector_free(connector); 179 } 180 if (r < 0) { 181 fprintf(stderr, "BUG: subsystem %s (at %u) could not connect to " 182 "publish/subscribe system.", sys->name, sys->level); 183 raw_assert_unreached_msg("A subsystem couldn't be connected."); 184 } 185 } 186 187 return 0; 188 } 189 190 /** 191 * Add publish/subscribe relationships to <b>builder</b> for all 192 * initialized subsystems. 193 **/ 194 int 195 subsystems_add_pubsub(pubsub_builder_t *builder) 196 { 197 return subsystems_add_pubsub_upto(builder, MAX_SUBSYS_LEVEL); 198 } 199 200 /** 201 * Shut down all the subsystems. 202 **/ 203 void 204 subsystems_shutdown(void) 205 { 206 subsystems_shutdown_downto(MIN_SUBSYS_LEVEL - 1); 207 } 208 209 /** 210 * Shut down all the subsystems whose level is above <b>target_level</b>. 211 **/ 212 void 213 subsystems_shutdown_downto(int target_level) 214 { 215 check_and_setup(); 216 217 for (int i = (int)n_tor_subsystems - 1; i >= 0; --i) { 218 const subsys_fns_t *sys = tor_subsystems[i]; 219 if (!sys->supported) 220 continue; 221 if (sys->level <= target_level) 222 break; 223 if (! sys_status[i].initialized) 224 continue; 225 if (sys->shutdown) { 226 log_debug(LD_GENERAL, "Shutting down %s", sys->name); 227 sys->shutdown(); 228 } 229 subsys_status_clear(&sys_status[i]); 230 } 231 } 232 233 /** 234 * Run pre-fork code on all subsystems that declare any 235 **/ 236 void 237 subsystems_prefork(void) 238 { 239 check_and_setup(); 240 241 for (int i = (int)n_tor_subsystems - 1; i >= 0; --i) { 242 const subsys_fns_t *sys = tor_subsystems[i]; 243 if (!sys->supported) 244 continue; 245 if (! sys_status[i].initialized) 246 continue; 247 if (sys->prefork) { 248 log_debug(LD_GENERAL, "Pre-fork: %s", sys->name); 249 sys->prefork(); 250 } 251 } 252 } 253 254 /** 255 * Run post-fork code on all subsystems that declare any 256 **/ 257 void 258 subsystems_postfork(void) 259 { 260 check_and_setup(); 261 262 for (unsigned i = 0; i < n_tor_subsystems; ++i) { 263 const subsys_fns_t *sys = tor_subsystems[i]; 264 if (!sys->supported) 265 continue; 266 if (! sys_status[i].initialized) 267 continue; 268 if (sys->postfork) { 269 log_debug(LD_GENERAL, "Post-fork: %s", sys->name); 270 sys->postfork(); 271 } 272 } 273 } 274 275 /** 276 * Run thread-cleanup code on all subsystems that declare any 277 **/ 278 void 279 subsystems_thread_cleanup(void) 280 { 281 check_and_setup(); 282 283 for (int i = (int)n_tor_subsystems - 1; i >= 0; --i) { 284 const subsys_fns_t *sys = tor_subsystems[i]; 285 if (!sys->supported) 286 continue; 287 if (! sys_status[i].initialized) 288 continue; 289 if (sys->thread_cleanup) { 290 log_debug(LD_GENERAL, "Thread cleanup: %s", sys->name); 291 sys->thread_cleanup(); 292 } 293 } 294 } 295 296 /** 297 * Dump a human- and machine-readable list of all the subsystems to stdout, 298 * in their initialization order, prefixed with their level. 299 **/ 300 void 301 subsystems_dump_list(void) 302 { 303 for (unsigned i = 0; i < n_tor_subsystems; ++i) { 304 const subsys_fns_t *sys = tor_subsystems[i]; 305 printf("% 4d\t%16s\t%s\n", sys->level, sys->name, 306 sys->location?sys->location:""); 307 } 308 } 309 310 /** 311 * Register all subsystem-declared options formats in <b>mgr</b>. 312 * 313 * Return 0 on success, -1 on failure. 314 **/ 315 int 316 subsystems_register_options_formats(config_mgr_t *mgr) 317 { 318 tor_assert(mgr); 319 check_and_setup(); 320 321 for (unsigned i = 0; i < n_tor_subsystems; ++i) { 322 const subsys_fns_t *sys = tor_subsystems[i]; 323 if (sys->options_format) { 324 int options_idx = config_mgr_add_format(mgr, sys->options_format); 325 sys_status[i].options_idx = options_idx; 326 log_debug(LD_CONFIG, "Added options format for %s with index %d", 327 sys->name, options_idx); 328 } 329 } 330 return 0; 331 } 332 333 /** 334 * Register all subsystem-declared state formats in <b>mgr</b>. 335 * 336 * Return 0 on success, -1 on failure. 337 **/ 338 int 339 subsystems_register_state_formats(config_mgr_t *mgr) 340 { 341 tor_assert(mgr); 342 check_and_setup(); 343 344 for (unsigned i = 0; i < n_tor_subsystems; ++i) { 345 const subsys_fns_t *sys = tor_subsystems[i]; 346 if (sys->state_format) { 347 int state_idx = config_mgr_add_format(mgr, sys->state_format); 348 sys_status[i].state_idx = state_idx; 349 log_debug(LD_CONFIG, "Added state format for %s with index %d", 350 sys->name, state_idx); 351 } 352 } 353 return 0; 354 } 355 356 #ifdef TOR_UNIT_TESTS 357 /** 358 * Helper: look up the index for <b>sys</b>. Return -1 if the subsystem 359 * is not recognized. 360 **/ 361 static int 362 subsys_get_idx(const subsys_fns_t *sys) 363 { 364 for (unsigned i = 0; i < n_tor_subsystems; ++i) { 365 if (sys == tor_subsystems[i]) 366 return (int)i; 367 } 368 return -1; 369 } 370 371 /** 372 * Return the current state-manager's index for any state held by the 373 * subsystem <b>sys</b>. If <b>sys</b> has no options, return -1. 374 * 375 * Using raw indices can be error-prone: only do this from the unit 376 * tests. If you need a way to access another subsystem's configuration, 377 * that subsystem should provide access functions. 378 **/ 379 int 380 subsystems_get_options_idx(const subsys_fns_t *sys) 381 { 382 int i = subsys_get_idx(sys); 383 tor_assert(i >= 0); 384 return sys_status[i].options_idx; 385 } 386 387 /** 388 * Return the current state-manager's index for any state held by the 389 * subsystem <b>sys</b>. If <b>sys</b> has no state, return -1. 390 * 391 * Using raw indices can be error-prone: only do this from the unit 392 * tests. If you need a way to access another subsystem's state 393 * that subsystem should provide access functions. 394 **/ 395 int 396 subsystems_get_state_idx(const subsys_fns_t *sys) 397 { 398 int i = subsys_get_idx(sys); 399 tor_assert(i >= 0); 400 return sys_status[i].state_idx; 401 } 402 #endif /* defined(TOR_UNIT_TESTS) */ 403 404 /** 405 * Call all appropriate set_options() methods to tell the various subsystems 406 * about a new set of torrc options. Return 0 on success, -1 on 407 * nonrecoverable failure. 408 **/ 409 int 410 subsystems_set_options(const config_mgr_t *mgr, struct or_options_t *options) 411 { 412 /* XXXX This does not yet handle reversible option assignment; I'll 413 * do that later in this branch. */ 414 415 for (unsigned i = 0; i < n_tor_subsystems; ++i) { 416 const subsys_fns_t *sys = tor_subsystems[i]; 417 if (sys_status[i].options_idx >= 0 && sys->set_options) { 418 void *obj = config_mgr_get_obj_mutable(mgr, options, 419 sys_status[i].options_idx); 420 int rv = sys->set_options(obj); 421 if (rv < 0) { 422 log_err(LD_CONFIG, "Error when handling option for %s; " 423 "cannot proceed.", sys->name); 424 return -1; 425 } 426 } 427 } 428 return 0; 429 } 430 431 /** 432 * Call all appropriate set_state() methods to tell the various subsystems 433 * about an initial DataDir/state file. Return 0 on success, -1 on 434 * nonrecoverable failure. 435 **/ 436 int 437 subsystems_set_state(const config_mgr_t *mgr, struct or_state_t *state) 438 { 439 for (unsigned i = 0; i < n_tor_subsystems; ++i) { 440 const subsys_fns_t *sys = tor_subsystems[i]; 441 if (sys_status[i].state_idx >= 0 && sys->set_state) { 442 void *obj = config_mgr_get_obj_mutable(mgr, state, 443 sys_status[i].state_idx); 444 int rv = sys->set_state(obj); 445 if (rv < 0) { 446 log_err(LD_CONFIG, "Error when handling state for %s; " 447 "cannot proceed.", sys->name); 448 return -1; 449 } 450 } 451 } 452 return 0; 453 } 454 455 /** 456 * Call all appropriate flush_state() methods to tell the various subsystems 457 * to update the state objects in <b>state</b>. Return 0 on success, 458 * -1 on failure. 459 **/ 460 int 461 subsystems_flush_state(const config_mgr_t *mgr, struct or_state_t *state) 462 { 463 int result = 0; 464 for (unsigned i = 0; i < n_tor_subsystems; ++i) { 465 const subsys_fns_t *sys = tor_subsystems[i]; 466 if (sys_status[i].state_idx >= 0 && sys->flush_state) { 467 void *obj = config_mgr_get_obj_mutable(mgr, state, 468 sys_status[i].state_idx); 469 int rv = sys->flush_state(obj); 470 if (rv < 0) { 471 log_warn(LD_CONFIG, "Error when flushing state to state object for %s", 472 sys->name); 473 result = -1; 474 } 475 } 476 } 477 return result; 478 }