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 : }
|