Tor  0.4.3.1-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-2020, 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  * Register all subsystem-declared options formats in <b>mgr</b>.
298  *
299  * Return 0 on success, -1 on failure.
300  **/
301 int
303 {
304  tor_assert(mgr);
305  check_and_setup();
306 
307  for (unsigned i = 0; i < n_tor_subsystems; ++i) {
308  const subsys_fns_t *sys = tor_subsystems[i];
309  if (sys->options_format) {
310  int options_idx = config_mgr_add_format(mgr, sys->options_format);
311  sys_status[i].options_idx = options_idx;
312  log_debug(LD_CONFIG, "Added options format for %s with index %d",
313  sys->name, options_idx);
314  }
315  }
316  return 0;
317 }
318 
319 /**
320  * Register all subsystem-declared state formats in <b>mgr</b>.
321  *
322  * Return 0 on success, -1 on failure.
323  **/
324 int
326 {
327  tor_assert(mgr);
328  check_and_setup();
329 
330  for (unsigned i = 0; i < n_tor_subsystems; ++i) {
331  const subsys_fns_t *sys = tor_subsystems[i];
332  if (sys->state_format) {
333  int state_idx = config_mgr_add_format(mgr, sys->state_format);
334  sys_status[i].state_idx = state_idx;
335  log_debug(LD_CONFIG, "Added state format for %s with index %d",
336  sys->name, state_idx);
337  }
338  }
339  return 0;
340 }
341 
342 #ifdef TOR_UNIT_TESTS
343 /**
344  * Helper: look up the index for <b>sys</b>. Return -1 if the subsystem
345  * is not recognized.
346  **/
347 static int
348 subsys_get_idx(const subsys_fns_t *sys)
349 {
350  for (unsigned i = 0; i < n_tor_subsystems; ++i) {
351  if (sys == tor_subsystems[i])
352  return (int)i;
353  }
354  return -1;
355 }
356 
357 /**
358  * Return the current state-manager's index for any state held by the
359  * subsystem <b>sys</b>. If <b>sys</b> has no options, return -1.
360  *
361  * Using raw indices can be error-prone: only do this from the unit
362  * tests. If you need a way to access another subsystem's configuration,
363  * that subsystem should provide access functions.
364  **/
365 int
366 subsystems_get_options_idx(const subsys_fns_t *sys)
367 {
368  int i = subsys_get_idx(sys);
369  tor_assert(i >= 0);
370  return sys_status[i].options_idx;
371 }
372 
373 /**
374  * Return the current state-manager's index for any state held by the
375  * subsystem <b>sys</b>. If <b>sys</b> has no state, return -1.
376  *
377  * Using raw indices can be error-prone: only do this from the unit
378  * tests. If you need a way to access another subsystem's state
379  * that subsystem should provide access functions.
380  **/
381 int
382 subsystems_get_state_idx(const subsys_fns_t *sys)
383 {
384  int i = subsys_get_idx(sys);
385  tor_assert(i >= 0);
386  return sys_status[i].state_idx;
387 }
388 #endif /* defined(TOR_UNIT_TESTS) */
389 
390 /**
391  * Call all appropriate set_options() methods to tell the various subsystems
392  * about a new set of torrc options. Return 0 on success, -1 on
393  * nonrecoverable failure.
394  **/
395 int
397 {
398  /* XXXX This does not yet handle reversible option assignment; I'll
399  * do that later in this branch. */
400 
401  for (unsigned i = 0; i < n_tor_subsystems; ++i) {
402  const subsys_fns_t *sys = tor_subsystems[i];
403  if (sys_status[i].options_idx >= 0 && sys->set_options) {
404  void *obj = config_mgr_get_obj_mutable(mgr, options,
405  sys_status[i].options_idx);
406  int rv = sys->set_options(obj);
407  if (rv < 0) {
408  log_err(LD_CONFIG, "Error when handling option for %s; "
409  "cannot proceed.", sys->name);
410  return -1;
411  }
412  }
413  }
414  return 0;
415 }
416 
417 /**
418  * Call all appropriate set_state() methods to tell the various subsystems
419  * about an initial DataDir/state file. Return 0 on success, -1 on
420  * nonrecoverable failure.
421  **/
422 int
423 subsystems_set_state(const config_mgr_t *mgr, struct or_state_t *state)
424 {
425  for (unsigned i = 0; i < n_tor_subsystems; ++i) {
426  const subsys_fns_t *sys = tor_subsystems[i];
427  if (sys_status[i].state_idx >= 0 && sys->set_state) {
428  void *obj = config_mgr_get_obj_mutable(mgr, state,
429  sys_status[i].state_idx);
430  int rv = sys->set_state(obj);
431  if (rv < 0) {
432  log_err(LD_CONFIG, "Error when handling state for %s; "
433  "cannot proceed.", sys->name);
434  return -1;
435  }
436  }
437  }
438  return 0;
439 }
440 
441 /**
442  * Call all appropriate flush_state() methods to tell the various subsystems
443  * to update the state objects in <b>state</b>. Return 0 on success,
444  * -1 on failure.
445  **/
446 int
448 {
449  int result = 0;
450  for (unsigned i = 0; i < n_tor_subsystems; ++i) {
451  const subsys_fns_t *sys = tor_subsystems[i];
452  if (sys_status[i].state_idx >= 0 && sys->flush_state) {
453  void *obj = config_mgr_get_obj_mutable(mgr, state,
454  sys_status[i].state_idx);
455  int rv = sys->flush_state(obj);
456  if (rv < 0) {
457  log_warn(LD_CONFIG, "Error when flushing state to state object for %s",
458  sys->name);
459  result = -1;
460  }
461  }
462  }
463  return result;
464 }
#define IDX_NONE
Definition: subsysmgr.c:38
void subsystems_shutdown(void)
Definition: subsysmgr.c:204
int level
Definition: subsys.h:55
int subsystems_flush_state(const config_mgr_t *mgr, struct or_state_t *state)
Definition: subsysmgr.c:447
bool initialized
Definition: subsysmgr.c:45
struct pubsub_connector_t pubsub_connector_t
#define ERROR_ID
Definition: msgtypes.h:34
void(* thread_cleanup)(void)
Definition: subsys.h:118
const char * name
Definition: subsys.h:42
struct pubsub_builder_t pubsub_builder_t
Definition: pubsub_build.h:28
int subsystems_init(void)
Definition: subsysmgr.c:114
#define LD_GENERAL
Definition: log.h:62
void * config_mgr_get_obj_mutable(const config_mgr_t *mgr, void *toplevel, int idx)
Definition: confmgt.c:246
const struct subsys_fns_t * tor_subsystems[]
int subsystems_set_options(const config_mgr_t *mgr, struct or_options_t *options)
Definition: subsysmgr.c:396
#define tor_assert(expr)
Definition: util_bug.h:102
#define N_SYS_STATUS
Definition: subsysmgr.c:53
int subsystems_init_upto(int target_level)
Definition: subsysmgr.c:124
Headers for util_malloc.c.
static void check_and_setup(void)
Definition: subsysmgr.c:78
void subsystems_prefork(void)
Definition: subsysmgr.c:237
void(* shutdown)(void)
Definition: subsys.h:129
bool supported
Definition: subsys.h:48
void(* postfork)(void)
Definition: subsys.h:108
Types used for messages in the dispatcher code.
static subsys_status_t sys_status[N_SYS_STATUS]
Definition: subsysmgr.c:59
int subsystems_add_pubsub_upto(pubsub_builder_t *builder, int target_level)
Definition: subsysmgr.c:160
int(* set_state)(void *)
Definition: subsys.h:177
int subsystems_register_state_formats(config_mgr_t *mgr)
Definition: subsysmgr.c:325
int(* add_pubsub)(struct pubsub_connector_t *)
Definition: subsys.h:80
#define MIN_SUBSYS_LEVEL
Definition: subsys.h:193
void subsystems_thread_cleanup(void)
Definition: subsysmgr.c:279
uint16_t subsys_id_t
Definition: msgtypes.h:22
int(* set_options)(void *)
Definition: subsys.h:159
static void subsys_status_clear(subsys_status_t *status)
Definition: subsysmgr.c:63
void subsystems_shutdown_downto(int target_level)
Definition: subsysmgr.c:213
const struct config_format_t * options_format
Definition: subsys.h:138
const struct config_format_t * state_format
Definition: subsys.h:147
int subsystems_set_state(const config_mgr_t *mgr, struct or_state_t *state)
Definition: subsysmgr.c:423
static bool subsystem_array_validated
Definition: subsysmgr.c:34
int(* initialize)(void)
Definition: subsys.h:70
#define ARRAY_LENGTH(x)
void subsystems_postfork(void)
Definition: subsysmgr.c:258
int subsystems_add_pubsub(pubsub_builder_t *builder)
Definition: subsysmgr.c:195
#define MAX_SUBSYS_LEVEL
Definition: subsys.h:197
void(* prefork)(void)
Definition: subsys.h:94
Headers for torerr.c.
Header for confmgt.c.
pubsub_connector_t * pubsub_connector_for_subsystem(pubsub_builder_t *builder, subsys_id_t subsys)
Definition: pubsub_build.c:89
Header for subsysmgr.c.
Headers for log.c.
Header for dispatch_naming.c.
Header for functions that add relationships to a pubsub builder.
Macros to manage assertions, fatal and non-fatal.
Header used for constructing the OO publish-subscribe facility.
int(* flush_state)(void *)
Definition: subsys.h:187
int subsystems_register_options_formats(config_mgr_t *mgr)
Definition: subsysmgr.c:302
int config_mgr_add_format(config_mgr_t *mgr, const config_format_t *fmt)
Definition: confmgt.c:216
#define pubsub_connector_free(c)
Definition: pubsub_build.h:67
#define LD_CONFIG
Definition: log.h:68