Tor  0.4.7.0-alpha-dev
subsysmgr.c
Go to the documentation of this file.
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"
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"
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. */
46  /** Index for this subsystem's options object, or IDX_NONE for none. */
48  /** Index for this subsystem's state object, or IDX_NONE for none. */
49  int state_idx;
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  **/
60 
61 /** Set <b>status</b> to a default (not set-up) state. */
62 static void
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
79 {
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",
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  }
103 
104  last_level = sys->level;
105  }
106 
108 }
109 
110 /**
111  * Initialize all the subsystems; exit on failure.
112  **/
113 int
115 {
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
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
196 {
198 }
199 
200 /**
201  * Shut down all the subsystems.
202  **/
203 void
205 {
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  }
230  }
231 }
232 
233 /**
234  * Run pre-fork code on all subsystems that declare any
235  **/
236 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
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
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
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
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
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
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
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 }
#define ARRAY_LENGTH(x)
void * config_mgr_get_obj_mutable(const config_mgr_t *mgr, void *toplevel, int idx)
Definition: confmgt.c:246
int config_mgr_add_format(config_mgr_t *mgr, const config_format_t *fmt)
Definition: confmgt.c:216
Header for confmgt.c.
Header for dispatch_naming.c.
Headers for log.c.
#define LD_GENERAL
Definition: log.h:62
#define LD_CONFIG
Definition: log.h:68
Headers for util_malloc.c.
Types used for messages in the dispatcher code.
#define ERROR_ID
Definition: msgtypes.h:34
uint16_t subsys_id_t
Definition: msgtypes.h:22
pubsub_connector_t * pubsub_connector_for_subsystem(pubsub_builder_t *builder, subsys_id_t subsys)
Definition: pubsub_build.c:89
Header used for constructing the OO publish-subscribe facility.
struct pubsub_builder_t pubsub_builder_t
Definition: pubsub_build.h:28
#define pubsub_connector_free(c)
Definition: pubsub_build.h:67
Header for functions that add relationships to a pubsub builder.
struct pubsub_connector_t pubsub_connector_t
int(* initialize)(void)
Definition: subsys.h:76
bool supported
Definition: subsys.h:54
int(* flush_state)(void *)
Definition: subsys.h:193
const struct config_format_t * options_format
Definition: subsys.h:144
const char * name
Definition: subsys.h:43
void(* postfork)(void)
Definition: subsys.h:114
int(* set_state)(void *)
Definition: subsys.h:183
void(* shutdown)(void)
Definition: subsys.h:135
void(* thread_cleanup)(void)
Definition: subsys.h:124
int(* set_options)(void *)
Definition: subsys.h:165
int(* add_pubsub)(struct pubsub_connector_t *)
Definition: subsys.h:86
int level
Definition: subsys.h:61
const char * location
Definition: subsys.h:48
const struct config_format_t * state_format
Definition: subsys.h:153
void(* prefork)(void)
Definition: subsys.h:100
bool initialized
Definition: subsysmgr.c:45
#define MAX_SUBSYS_LEVEL
Definition: subsys.h:222
#define MIN_SUBSYS_LEVEL
Definition: subsys.h:218
int subsystems_set_options(const config_mgr_t *mgr, struct or_options_t *options)
Definition: subsysmgr.c:410
void subsystems_prefork(void)
Definition: subsysmgr.c:237
int subsystems_add_pubsub_upto(pubsub_builder_t *builder, int target_level)
Definition: subsysmgr.c:160
int subsystems_add_pubsub(pubsub_builder_t *builder)
Definition: subsysmgr.c:195
int subsystems_register_state_formats(config_mgr_t *mgr)
Definition: subsysmgr.c:339
static subsys_status_t sys_status[N_SYS_STATUS]
Definition: subsysmgr.c:59
static bool subsystem_array_validated
Definition: subsysmgr.c:34
int subsystems_set_state(const config_mgr_t *mgr, struct or_state_t *state)
Definition: subsysmgr.c:437
#define IDX_NONE
Definition: subsysmgr.c:38
static void check_and_setup(void)
Definition: subsysmgr.c:78
void subsystems_shutdown(void)
Definition: subsysmgr.c:204
void subsystems_postfork(void)
Definition: subsysmgr.c:258
#define N_SYS_STATUS
Definition: subsysmgr.c:53
int subsystems_init_upto(int target_level)
Definition: subsysmgr.c:124
void subsystems_dump_list(void)
Definition: subsysmgr.c:301
int subsystems_flush_state(const config_mgr_t *mgr, struct or_state_t *state)
Definition: subsysmgr.c:461
int subsystems_register_options_formats(config_mgr_t *mgr)
Definition: subsysmgr.c:316
static void subsys_status_clear(subsys_status_t *status)
Definition: subsysmgr.c:63
void subsystems_shutdown_downto(int target_level)
Definition: subsysmgr.c:213
int subsystems_init(void)
Definition: subsysmgr.c:114
void subsystems_thread_cleanup(void)
Definition: subsysmgr.c:279
Header for subsysmgr.c.
const struct subsys_fns_t * tor_subsystems[]
Headers for torerr.c.
Macros to manage assertions, fatal and non-fatal.
#define tor_assert(expr)
Definition: util_bug.h:102