LCOV - code coverage report
Current view: top level - app/main - subsysmgr.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 149 188 79.3 %
Date: 2021-11-24 03:28:48 Functions: 18 20 90.0 %

          Line data    Source code
       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      120843 : subsys_status_clear(subsys_status_t *status)
      64             : {
      65      120843 :   if (!status)
      66             :     return;
      67      120843 :   memset(status, 0, sizeof(*status));
      68      120843 :   status->initialized = false;
      69      120843 :   status->state_idx = IDX_NONE;
      70      120843 :   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       14235 : check_and_setup(void)
      79             : {
      80       14235 :   if (subsystem_array_validated)
      81             :     return;
      82             : 
      83        5553 :   raw_assert(ARRAY_LENGTH(sys_status) >= n_tor_subsystems);
      84        5553 :   memset(sys_status, 0, sizeof(sys_status));
      85             : 
      86        5553 :   int last_level = MIN_SUBSYS_LEVEL;
      87             : 
      88      122166 :   for (unsigned i = 0; i < n_tor_subsystems; ++i) {
      89      116613 :     const subsys_fns_t *sys = tor_subsystems[i];
      90      116613 :     if (sys->level < MIN_SUBSYS_LEVEL || sys->level > MAX_SUBSYS_LEVEL) {
      91           0 :       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           0 :               sys->name, i, sys->level, MIN_SUBSYS_LEVEL, MAX_SUBSYS_LEVEL);
      94           0 :       raw_assert_unreached_msg("There is a bug in subsystem_list.c");
      95             :     }
      96      116613 :     if (sys->level < last_level) {
      97           0 :       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           0 :               sys->name, i, sys->level, last_level);
     100           0 :       raw_assert_unreached_msg("There is a bug in subsystem_list.c");
     101             :     }
     102      116613 :     subsys_status_clear(&sys_status[i]);
     103             : 
     104      116613 :     last_level = sys->level;
     105             :   }
     106             : 
     107        5553 :   subsystem_array_validated = true;
     108             : }
     109             : 
     110             : /**
     111             :  * Initialize all the subsystems; exit on failure.
     112             :  **/
     113             : int
     114         244 : subsystems_init(void)
     115             : {
     116         244 :   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        5553 : subsystems_init_upto(int target_level)
     125             : {
     126        5553 :   check_and_setup();
     127             : 
     128       79694 :   for (unsigned i = 0; i < n_tor_subsystems; ++i) {
     129       79450 :     const subsys_fns_t *sys = tor_subsystems[i];
     130       79450 :     if (!sys->supported)
     131       16659 :       continue;
     132       62791 :     if (sys->level > target_level)
     133             :       break;
     134       57482 :     if (sys_status[i].initialized)
     135           0 :       continue;
     136       57482 :     int r = 0;
     137       57482 :     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       57482 :       log_debug(LD_GENERAL, "Initializing %s", sys->name);
     142       57482 :       r = sys->initialize();
     143             :     }
     144       57482 :     if (r < 0) {
     145           0 :       fprintf(stderr, "BUG: subsystem %s (at %u) initialization failed.\n",
     146           0 :               sys->name, i);
     147           0 :       raw_assert_unreached_msg("A subsystem couldn't be initialized.");
     148             :     }
     149       57482 :     sys_status[i].initialized = true;
     150             :   }
     151             : 
     152        5553 :   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         245 : subsystems_add_pubsub_upto(pubsub_builder_t *builder,
     161             :                            int target_level)
     162             : {
     163        5390 :   for (unsigned i = 0; i < n_tor_subsystems; ++i) {
     164        5145 :     const subsys_fns_t *sys = tor_subsystems[i];
     165        5145 :     if (!sys->supported)
     166         735 :       continue;
     167        4410 :     if (sys->level > target_level)
     168             :       break;
     169        4410 :     if (! sys_status[i].initialized)
     170           0 :       continue;
     171        4410 :     int r = 0;
     172        4410 :     if (sys->add_pubsub) {
     173         490 :       subsys_id_t sysid = get_subsys_id(sys->name);
     174         490 :       raw_assert(sysid != ERROR_ID);
     175         490 :       pubsub_connector_t *connector;
     176         490 :       connector = pubsub_connector_for_subsystem(builder, sysid);
     177         490 :       r = sys->add_pubsub(connector);
     178         490 :       pubsub_connector_free(connector);
     179             :     }
     180         490 :     if (r < 0) {
     181           0 :       fprintf(stderr, "BUG: subsystem %s (at %u) could not connect to "
     182           0 :               "publish/subscribe system.", sys->name, sys->level);
     183           0 :       raw_assert_unreached_msg("A subsystem couldn't be connected.");
     184             :     }
     185             :   }
     186             : 
     187         245 :   return 0;
     188             : }
     189             : 
     190             : /**
     191             :  * Add publish/subscribe relationships to <b>builder</b> for all
     192             :  * initialized subsystems.
     193             :  **/
     194             : int
     195         245 : subsystems_add_pubsub(pubsub_builder_t *builder)
     196             : {
     197         245 :   return subsystems_add_pubsub_upto(builder, MAX_SUBSYS_LEVEL);
     198             : }
     199             : 
     200             : /**
     201             :  * Shut down all the subsystems.
     202             :  **/
     203             : void
     204         235 : subsystems_shutdown(void)
     205             : {
     206         235 :   subsystems_shutdown_downto(MIN_SUBSYS_LEVEL - 1);
     207         235 : }
     208             : 
     209             : /**
     210             :  * Shut down all the subsystems whose level is above <b>target_level</b>.
     211             :  **/
     212             : void
     213         235 : subsystems_shutdown_downto(int target_level)
     214             : {
     215         235 :   check_and_setup();
     216             : 
     217        5170 :   for (int i = (int)n_tor_subsystems - 1; i >= 0; --i) {
     218        4935 :     const subsys_fns_t *sys = tor_subsystems[i];
     219        4935 :     if (!sys->supported)
     220         705 :       continue;
     221        4230 :     if (sys->level <= target_level)
     222             :       break;
     223        4230 :     if (! sys_status[i].initialized)
     224           0 :       continue;
     225        4230 :     if (sys->shutdown) {
     226        3290 :       log_debug(LD_GENERAL, "Shutting down %s", sys->name);
     227        3290 :       sys->shutdown();
     228             :     }
     229        4230 :     subsys_status_clear(&sys_status[i]);
     230             :   }
     231         235 : }
     232             : 
     233             : /**
     234             :  * Run pre-fork code on all subsystems that declare any
     235             :  **/
     236             : void
     237         927 : subsystems_prefork(void)
     238             : {
     239         927 :   check_and_setup();
     240             : 
     241       20394 :   for (int i = (int)n_tor_subsystems - 1; i >= 0; --i) {
     242       19467 :     const subsys_fns_t *sys = tor_subsystems[i];
     243       19467 :     if (!sys->supported)
     244        2781 :       continue;
     245       16686 :     if (! sys_status[i].initialized)
     246           0 :       continue;
     247       16686 :     if (sys->prefork) {
     248         927 :       log_debug(LD_GENERAL, "Pre-fork: %s", sys->name);
     249         927 :       sys->prefork();
     250             :     }
     251             :   }
     252         927 : }
     253             : 
     254             : /**
     255             :  * Run post-fork code on all subsystems that declare any
     256             :  **/
     257             : void
     258        1854 : subsystems_postfork(void)
     259             : {
     260        1854 :   check_and_setup();
     261             : 
     262       40788 :   for (unsigned i = 0; i < n_tor_subsystems; ++i) {
     263       38934 :     const subsys_fns_t *sys = tor_subsystems[i];
     264       38934 :     if (!sys->supported)
     265        5562 :       continue;
     266       33372 :     if (! sys_status[i].initialized)
     267           0 :       continue;
     268       33372 :     if (sys->postfork) {
     269        3708 :       log_debug(LD_GENERAL, "Post-fork: %s", sys->name);
     270        3708 :       sys->postfork();
     271             :     }
     272             :   }
     273        1854 : }
     274             : 
     275             : /**
     276             :  * Run thread-cleanup code on all subsystems that declare any
     277             :  **/
     278             : void
     279           0 : subsystems_thread_cleanup(void)
     280             : {
     281           0 :   check_and_setup();
     282             : 
     283           0 :   for (int i = (int)n_tor_subsystems - 1; i >= 0; --i) {
     284           0 :     const subsys_fns_t *sys = tor_subsystems[i];
     285           0 :     if (!sys->supported)
     286           0 :       continue;
     287           0 :     if (! sys_status[i].initialized)
     288           0 :       continue;
     289           0 :     if (sys->thread_cleanup) {
     290           0 :       log_debug(LD_GENERAL, "Thread cleanup: %s", sys->name);
     291           0 :       sys->thread_cleanup();
     292             :     }
     293             :   }
     294           0 : }
     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           0 : subsystems_dump_list(void)
     302             : {
     303           0 :   for (unsigned i = 0; i < n_tor_subsystems; ++i) {
     304           0 :     const subsys_fns_t *sys = tor_subsystems[i];
     305           0 :     printf("% 4d\t%16s\t%s\n", sys->level, sys->name,
     306           0 :            sys->location?sys->location:"");
     307             :   }
     308           0 : }
     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        5553 : subsystems_register_options_formats(config_mgr_t *mgr)
     317             : {
     318        5553 :   tor_assert(mgr);
     319        5553 :   check_and_setup();
     320             : 
     321      122166 :   for (unsigned i = 0; i < n_tor_subsystems; ++i) {
     322      116613 :     const subsys_fns_t *sys = tor_subsystems[i];
     323      116613 :     if (sys->options_format) {
     324       16659 :       int options_idx = config_mgr_add_format(mgr, sys->options_format);
     325       16659 :       sys_status[i].options_idx = options_idx;
     326       16659 :       log_debug(LD_CONFIG, "Added options format for %s with index %d",
     327             :                 sys->name, options_idx);
     328             :     }
     329             :   }
     330        5553 :   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         113 : subsystems_register_state_formats(config_mgr_t *mgr)
     340             : {
     341         113 :   tor_assert(mgr);
     342         113 :   check_and_setup();
     343             : 
     344        2486 :   for (unsigned i = 0; i < n_tor_subsystems; ++i) {
     345        2373 :     const subsys_fns_t *sys = tor_subsystems[i];
     346        2373 :     if (sys->state_format) {
     347         113 :       int state_idx = config_mgr_add_format(mgr, sys->state_format);
     348         113 :       sys_status[i].state_idx = state_idx;
     349         113 :       log_debug(LD_CONFIG, "Added state format for %s with index %d",
     350             :                 sys->name, state_idx);
     351             :     }
     352             :   }
     353         113 :   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          10 : subsys_get_idx(const subsys_fns_t *sys)
     363             : {
     364         158 :   for (unsigned i = 0; i < n_tor_subsystems; ++i) {
     365         158 :     if (sys == tor_subsystems[i])
     366          10 :       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           9 : subsystems_get_options_idx(const subsys_fns_t *sys)
     381             : {
     382           9 :   int i = subsys_get_idx(sys);
     383           9 :   tor_assert(i >= 0);
     384           9 :   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           1 : subsystems_get_state_idx(const subsys_fns_t *sys)
     397             : {
     398           1 :   int i = subsys_get_idx(sys);
     399           1 :   tor_assert(i >= 0);
     400           1 :   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         216 : 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        4738 :   for (unsigned i = 0; i < n_tor_subsystems; ++i) {
     416        4523 :     const subsys_fns_t *sys = tor_subsystems[i];
     417        4523 :     if (sys_status[i].options_idx >= 0 && sys->set_options) {
     418         646 :       void *obj = config_mgr_get_obj_mutable(mgr, options,
     419             :                                              sys_status[i].options_idx);
     420         646 :       int rv = sys->set_options(obj);
     421         646 :       if (rv < 0) {
     422           1 :         log_err(LD_CONFIG, "Error when handling option for %s; "
     423             :                 "cannot proceed.", sys->name);
     424           1 :         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           4 : subsystems_set_state(const config_mgr_t *mgr, struct or_state_t *state)
     438             : {
     439          88 :   for (unsigned i = 0; i < n_tor_subsystems; ++i) {
     440          84 :     const subsys_fns_t *sys = tor_subsystems[i];
     441          84 :     if (sys_status[i].state_idx >= 0 && sys->set_state) {
     442           4 :       void *obj = config_mgr_get_obj_mutable(mgr, state,
     443             :                                              sys_status[i].state_idx);
     444           4 :       int rv = sys->set_state(obj);
     445           4 :       if (rv < 0) {
     446           0 :         log_err(LD_CONFIG, "Error when handling state for %s; "
     447             :                 "cannot proceed.", sys->name);
     448           0 :         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           4 : subsystems_flush_state(const config_mgr_t *mgr, struct or_state_t *state)
     462             : {
     463           4 :   int result = 0;
     464          88 :   for (unsigned i = 0; i < n_tor_subsystems; ++i) {
     465          84 :     const subsys_fns_t *sys = tor_subsystems[i];
     466          84 :     if (sys_status[i].state_idx >= 0 && sys->flush_state) {
     467           4 :       void *obj = config_mgr_get_obj_mutable(mgr, state,
     468             :                                              sys_status[i].state_idx);
     469           4 :       int rv = sys->flush_state(obj);
     470           4 :       if (rv < 0) {
     471           0 :         log_warn(LD_CONFIG, "Error when flushing state to state object for %s",
     472             :                 sys->name);
     473           0 :         result = -1;
     474             :       }
     475             :     }
     476             :   }
     477           4 :   return result;
     478             : }

Generated by: LCOV version 1.14