tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

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 }