Tor 0.4.9.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"
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 **/
34static 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 **/
43typedef 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. */
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. */
62static 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 **/
77static 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 **/
113int
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 **/
123int
124subsystems_init_upto(int target_level)
125{
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 **/
159int
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 **/
194int
196{
198}
199
200/**
201 * Shut down all the subsystems.
202 **/
203void
205{
207}
208
209/**
210 * Shut down all the subsystems whose level is above <b>target_level</b>.
211 **/
212void
214{
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 **/
236void
238{
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 **/
257void
259{
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 **/
278void
280{
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 **/
300void
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 **/
315int
317{
318 tor_assert(mgr);
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 **/
338int
340{
341 tor_assert(mgr);
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 **/
361static int
362subsys_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 **/
379int
380subsystems_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 **/
395int
396subsystems_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 **/
409int
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 **/
436int
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 **/
460int
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:103