]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/main.c
log: add null log target
[thirdparty/systemd.git] / src / main.c
CommitLineData
60918275
LP
1/*-*- Mode: C; c-basic-offset: 8 -*-*/
2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
ea430986
LP
22#include <dbus/dbus.h>
23
60918275
LP
24#include <stdio.h>
25#include <errno.h>
26#include <string.h>
16354eff 27#include <unistd.h>
4ade7963
LP
28#include <sys/types.h>
29#include <sys/stat.h>
f170852a 30#include <getopt.h>
97c4f35c 31#include <signal.h>
4fc935ca 32#include <sys/wait.h>
80876c20 33#include <fcntl.h>
60918275
LP
34
35#include "manager.h"
16354eff 36#include "log.h"
4ade7963 37#include "mount-setup.h"
302e8c4c 38#include "hostname-setup.h"
af5bc85d 39#include "loopback-setup.h"
11c3a4ee 40#include "kmod-setup.h"
302e8c4c 41#include "load-fragment.h"
a16e1123 42#include "fdset.h"
60918275 43
f170852a
LP
44static enum {
45 ACTION_RUN,
e965d56d 46 ACTION_HELP,
e537352b 47 ACTION_TEST,
4288f619
LP
48 ACTION_DUMP_CONFIGURATION_ITEMS,
49 ACTION_DONE
f170852a
LP
50} action = ACTION_RUN;
51
52static char *default_unit = NULL;
a5dab5ce 53static ManagerRunningAs running_as = _MANAGER_RUNNING_AS_INVALID;
4fc935ca 54
97c4f35c 55static bool dump_core = true;
601f6a1e
LP
56static bool crash_shell = false;
57static int crash_chvt = -1;
80876c20 58static bool confirm_spawn = false;
a16e1123 59static FILE* serialization = NULL;
80876c20 60
93a46b0b 61_noreturn_ static void freeze(void) {
97c4f35c
LP
62 for (;;)
63 pause();
64}
65
6f5e3f35
LP
66static void nop_handler(int sig) {
67}
68
93a46b0b 69_noreturn_ static void crash(int sig) {
97c4f35c
LP
70
71 if (!dump_core)
72 log_error("Caught <%s>, not dumping core.", strsignal(sig));
73 else {
6f5e3f35 74 struct sigaction sa;
97c4f35c
LP
75 pid_t pid;
76
6f5e3f35
LP
77 /* We want to wait for the core process, hence let's enable SIGCHLD */
78 zero(sa);
79 sa.sa_handler = nop_handler;
80 sa.sa_flags = SA_NOCLDSTOP|SA_RESTART;
81 assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
82
97c4f35c 83 if ((pid = fork()) < 0)
4fc935ca 84 log_error("Caught <%s>, cannot fork for core dump: %s", strsignal(sig), strerror(errno));
97c4f35c
LP
85
86 else if (pid == 0) {
97c4f35c
LP
87 struct rlimit rl;
88
89 /* Enable default signal handler for core dump */
90 zero(sa);
91 sa.sa_handler = SIG_DFL;
92 assert_se(sigaction(sig, &sa, NULL) == 0);
93
94 /* Don't limit the core dump size */
95 zero(rl);
96 rl.rlim_cur = RLIM_INFINITY;
97 rl.rlim_max = RLIM_INFINITY;
98 setrlimit(RLIMIT_CORE, &rl);
99
100 /* Just to be sure... */
101 assert_se(chdir("/") == 0);
102
103 /* Raise the signal again */
104 raise(sig);
105
106 assert_not_reached("We shouldn't be here...");
107 _exit(1);
4fc935ca
LP
108
109 } else {
110 int status, r;
111
112 /* Order things nicely. */
113 if ((r = waitpid(pid, &status, 0)) < 0)
114 log_error("Caught <%s>, waitpid() failed: %s", strsignal(sig), strerror(errno));
115 else if (!WCOREDUMP(status))
116 log_error("Caught <%s>, core dump failed.", strsignal(sig));
117 else
118 log_error("Caught <%s>, dumped core as pid %llu.", strsignal(sig), (unsigned long long) pid);
97c4f35c
LP
119 }
120 }
121
601f6a1e
LP
122 if (crash_chvt)
123 chvt(crash_chvt);
124
4fc935ca 125 if (crash_shell) {
6f5e3f35
LP
126 struct sigaction sa;
127 pid_t pid;
8c43883a 128
4fc935ca
LP
129 log_info("Executing crash shell in 10s...");
130 sleep(10);
131
6f5e3f35
LP
132 /* Let the kernel reap children for us */
133 zero(sa);
134 sa.sa_handler = SIG_IGN;
135 sa.sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART;
136 assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
8c43883a 137
6f5e3f35
LP
138 if ((pid = fork()) < 0)
139 log_error("Failed to fork off crash shell: %s", strerror(errno));
140 else if (pid == 0) {
843d2643 141 int fd, r;
ea5652c2 142
21de3988 143 if ((fd = acquire_terminal("/dev/console", false, true, true)) < 0)
ea5652c2 144 log_error("Failed to acquire terminal: %s", strerror(-fd));
5b2a0903 145 else if ((r = make_stdio(fd)) < 0)
843d2643 146 log_error("Failed to duplicate terminal fd: %s", strerror(-r));
ea5652c2 147
6f5e3f35
LP
148 execl("/bin/sh", "/bin/sh", NULL);
149
150 log_error("execl() failed: %s", strerror(errno));
151 _exit(1);
152 }
c99b188e 153
6f5e3f35 154 log_info("Successfully spawned crash shall as pid %llu.", (unsigned long long) pid);
4fc935ca
LP
155 }
156
157 log_info("Freezing execution.");
97c4f35c
LP
158 freeze();
159}
160
161static void install_crash_handler(void) {
162 struct sigaction sa;
163
164 zero(sa);
165
166 sa.sa_handler = crash;
167 sa.sa_flags = SA_NODEFER;
168
1b91d3e8 169 sigaction_many(&sa, SIGNALS_CRASH_HANDLER, -1);
97c4f35c 170}
f170852a 171
843d2643
LP
172static int make_null_stdio(void) {
173 int null_fd, r;
80876c20 174
c8513d54 175 if ((null_fd = open("/dev/null", O_RDWR|O_NOCTTY)) < 0) {
80876c20 176 log_error("Failed to open /dev/null: %m");
843d2643 177 return -errno;
80876c20
LP
178 }
179
843d2643
LP
180 if ((r = make_stdio(null_fd)) < 0)
181 log_warning("Failed to dup2() device: %s", strerror(-r));
80876c20 182
843d2643
LP
183 return r;
184}
80876c20 185
843d2643
LP
186static int console_setup(bool do_reset) {
187 int tty_fd, r;
80876c20 188
843d2643
LP
189 /* If we are init, we connect stdin/stdout/stderr to /dev/null
190 * and make sure we don't have a controlling tty. */
80876c20 191
843d2643
LP
192 release_terminal();
193
194 if (!do_reset)
195 return 0;
80876c20 196
843d2643
LP
197 if ((tty_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0) {
198 log_error("Failed to open /dev/console: %s", strerror(-tty_fd));
199 return -tty_fd;
200 }
80876c20 201
843d2643
LP
202 if ((r = reset_terminal(tty_fd)) < 0)
203 log_error("Failed to reset /dev/console: %s", strerror(-r));
204
205 close_nointr_nofail(tty_fd);
80876c20
LP
206 return r;
207}
208
f170852a
LP
209static int set_default_unit(const char *u) {
210 char *c;
211
212 assert(u);
213
214 if (!(c = strdup(u)))
215 return -ENOMEM;
216
217 free(default_unit);
218 default_unit = c;
219 return 0;
220}
221
222static int parse_proc_cmdline_word(const char *word) {
223
224 static const char * const rlmap[] = {
225 "single", SPECIAL_RUNLEVEL1_TARGET,
226 "-s", SPECIAL_RUNLEVEL1_TARGET,
227 "s", SPECIAL_RUNLEVEL1_TARGET,
228 "S", SPECIAL_RUNLEVEL1_TARGET,
229 "1", SPECIAL_RUNLEVEL1_TARGET,
230 "2", SPECIAL_RUNLEVEL2_TARGET,
231 "3", SPECIAL_RUNLEVEL3_TARGET,
232 "4", SPECIAL_RUNLEVEL4_TARGET,
233 "5", SPECIAL_RUNLEVEL5_TARGET
234 };
235
236 if (startswith(word, "systemd.default="))
82771ba1 237 return set_default_unit(word + 16);
f170852a
LP
238
239 else if (startswith(word, "systemd.log_target=")) {
240
241 if (log_set_target_from_string(word + 19) < 0)
242 log_warning("Failed to parse log target %s. Ignoring.", word + 19);
243
244 } else if (startswith(word, "systemd.log_level=")) {
245
246 if (log_set_max_level_from_string(word + 18) < 0)
247 log_warning("Failed to parse log level %s. Ignoring.", word + 18);
248
4fc935ca
LP
249 } else if (startswith(word, "systemd.dump_core=")) {
250 int r;
251
252 if ((r = parse_boolean(word + 18)) < 0)
601f6a1e 253 log_warning("Failed to parse dump core switch %s, Ignoring.", word + 18);
4fc935ca
LP
254 else
255 dump_core = r;
256
257 } else if (startswith(word, "systemd.crash_shell=")) {
258 int r;
259
260 if ((r = parse_boolean(word + 20)) < 0)
601f6a1e 261 log_warning("Failed to parse crash shell switch %s, Ignoring.", word + 20);
4fc935ca
LP
262 else
263 crash_shell = r;
264
5e7ee61c
LP
265
266 } else if (startswith(word, "systemd.confirm_spawn=")) {
267 int r;
268
269 if ((r = parse_boolean(word + 22)) < 0)
270 log_warning("Failed to parse confirm spawn switch %s, Ignoring.", word + 22);
271 else
272 confirm_spawn = r;
273
601f6a1e
LP
274 } else if (startswith(word, "systemd.crash_chvt=")) {
275 int k;
276
277 if (safe_atoi(word + 19, &k) < 0)
278 log_warning("Failed to parse crash chvt switch %s, Ignoring.", word + 19);
279 else
280 crash_chvt = k;
281
4fc935ca
LP
282 } else if (startswith(word, "systemd.")) {
283
284 log_warning("Unknown kernel switch %s. Ignoring.", word);
285
286 log_info("Supported kernel switches:");
287 log_info("systemd.default=UNIT Default unit to start");
288 log_info("systemd.log_target=console|kmsg|syslog Log target");
289 log_info("systemd.log_level=LEVEL Log level");
290 log_info("systemd.dump_core=0|1 Dump core on crash");
291 log_info("systemd.crash_shell=0|1 On crash run shell");
601f6a1e 292 log_info("systemd.crash_chvt=N Change to VT #N on crash");
5e7ee61c 293 log_info("systemd.confirm_spawn=0|1 Confirm every process spawn");
4fc935ca 294
f170852a
LP
295 } else {
296 unsigned i;
297
298 /* SysV compatibility */
f170852a
LP
299 for (i = 0; i < ELEMENTSOF(rlmap); i += 2)
300 if (streq(word, rlmap[i]))
301 return set_default_unit(rlmap[i+1]);
302 }
303
304 return 0;
305}
306
307static int parse_proc_cmdline(void) {
308 char *line;
309 int r;
310 char *w;
311 size_t l;
312 char *state;
313
314 if ((r = read_one_line_file("/proc/cmdline", &line)) < 0) {
315 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(errno));
316 return 0;
317 }
318
319 FOREACH_WORD_QUOTED(w, l, line, state) {
320 char *word;
321
322 if (!(word = strndup(w, l))) {
323 r = -ENOMEM;
324 goto finish;
325 }
326
327 r = parse_proc_cmdline_word(word);
328 free(word);
329
330 if (r < 0)
331 goto finish;
332 }
333
334 r = 0;
335
336finish:
337 free(line);
338 return r;
339}
340
341static int parse_argv(int argc, char *argv[]) {
342
343 enum {
344 ARG_LOG_LEVEL = 0x100,
345 ARG_LOG_TARGET,
a5dab5ce 346 ARG_DEFAULT,
e965d56d 347 ARG_RUNNING_AS,
e537352b 348 ARG_TEST,
80876c20 349 ARG_DUMP_CONFIGURATION_ITEMS,
a16e1123 350 ARG_CONFIRM_SPAWN,
4288f619
LP
351 ARG_DESERIALIZE,
352 ARG_INTROSPECT
f170852a
LP
353 };
354
355 static const struct option options[] = {
a16e1123
LP
356 { "log-level", required_argument, NULL, ARG_LOG_LEVEL },
357 { "log-target", required_argument, NULL, ARG_LOG_TARGET },
358 { "default", required_argument, NULL, ARG_DEFAULT },
359 { "running-as", required_argument, NULL, ARG_RUNNING_AS },
360 { "test", no_argument, NULL, ARG_TEST },
361 { "help", no_argument, NULL, 'h' },
362 { "dump-configuration-items", no_argument, NULL, ARG_DUMP_CONFIGURATION_ITEMS },
363 { "confirm-spawn", no_argument, NULL, ARG_CONFIRM_SPAWN },
364 { "deserialize", required_argument, NULL, ARG_DESERIALIZE },
4288f619 365 { "introspect", optional_argument, NULL, ARG_INTROSPECT },
a16e1123 366 { NULL, 0, NULL, 0 }
f170852a
LP
367 };
368
369 int c, r;
370
371 assert(argc >= 1);
372 assert(argv);
373
374 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
375
376 switch (c) {
377
378 case ARG_LOG_LEVEL:
379 if ((r = log_set_max_level_from_string(optarg)) < 0) {
380 log_error("Failed to parse log level %s.", optarg);
381 return r;
382 }
383
384 break;
385
386 case ARG_LOG_TARGET:
387
388 if ((r = log_set_target_from_string(optarg)) < 0) {
389 log_error("Failed to parse log target %s.", optarg);
390 return r;
391 }
392
393 break;
394
395 case ARG_DEFAULT:
396
397 if ((r = set_default_unit(optarg)) < 0) {
398 log_error("Failed to set default unit %s: %s", optarg, strerror(-r));
399 return r;
400 }
401
402 break;
403
a5dab5ce
LP
404 case ARG_RUNNING_AS: {
405 ManagerRunningAs as;
406
407 if ((as = manager_running_as_from_string(optarg)) < 0) {
408 log_error("Failed to parse running as value %s", optarg);
409 return -EINVAL;
410 }
411
412 running_as = as;
413 break;
414 }
415
e965d56d
LP
416 case ARG_TEST:
417 action = ACTION_TEST;
418 break;
419
e537352b
LP
420 case ARG_DUMP_CONFIGURATION_ITEMS:
421 action = ACTION_DUMP_CONFIGURATION_ITEMS;
422 break;
423
80876c20
LP
424 case ARG_CONFIRM_SPAWN:
425 confirm_spawn = true;
426 break;
427
a16e1123
LP
428 case ARG_DESERIALIZE: {
429 int fd;
430 FILE *f;
431
432 if ((r = safe_atoi(optarg, &fd)) < 0 || fd < 0) {
433 log_error("Failed to parse deserialize option %s.", optarg);
434 return r;
435 }
436
437 if (!(f = fdopen(fd, "r"))) {
438 log_error("Failed to open serialization fd: %m");
439 return r;
440 }
441
442 if (serialization)
443 fclose(serialization);
444
445 serialization = f;
446
447 break;
448 }
449
4288f619
LP
450 case ARG_INTROSPECT: {
451 const char * const * i = NULL;
452
453 for (i = bus_interface_table; *i; i += 2)
454 if (!optarg || streq(i[0], optarg)) {
455 fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
456 "<node>\n", stdout);
457 fputs(i[1], stdout);
458 fputs("</node>\n", stdout);
459
460 if (optarg)
461 break;
462 }
463
464 if (!i[0] && optarg)
465 log_error("Unknown interface %s.", optarg);
466
467 action = ACTION_DONE;
468 break;
469 }
470
f170852a
LP
471 case 'h':
472 action = ACTION_HELP;
473 break;
474
475 case '?':
476 return -EINVAL;
477
478 default:
479 log_error("Unknown option code %c", c);
480 return -EINVAL;
481 }
482
51f0e189
LP
483 /* PID 1 will get the kernel arguments as parameters, which we
484 * ignore and unconditionally read from
485 * /proc/cmdline. However, we need to ignore those arguments
486 * here. */
487 if (running_as != MANAGER_INIT && optind < argc) {
488 log_error("Excess arguments.");
489 return -EINVAL;
490 }
491
f170852a
LP
492 return 0;
493}
494
495static int help(void) {
496
497 printf("%s [options]\n\n"
e537352b
LP
498 " -h --help Show this help\n"
499 " --default=UNIT Set default unit\n"
500 " --log-level=LEVEL Set log level\n"
843d2643 501 " --log-target=TARGET Set log target (console, syslog, kmsg, syslog-or-kmsg)\n"
e537352b
LP
502 " --running-as=AS Set running as (init, system, session)\n"
503 " --test Determine startup sequence, dump it and exit\n"
80876c20 504 " --dump-configuration-items Dump understood unit configuration items\n"
4288f619
LP
505 " --confirm-spawn Ask for confirmation when spawning processes\n"
506 " --introspect[=INTERFACE] Extract D-Bus interface data\n",
f170852a
LP
507 __progname);
508
509 return 0;
510}
511
a16e1123
LP
512static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds) {
513 FILE *f = NULL;
514 FDSet *fds = NULL;
515 int r;
516
517 assert(m);
518 assert(_f);
519 assert(_fds);
520
521 if ((r = manager_open_serialization(&f)) < 0) {
522 log_error("Failed to create serialization faile: %s", strerror(-r));
523 goto fail;
524 }
525
526 if (!(fds = fdset_new())) {
527 r = -ENOMEM;
528 log_error("Failed to allocate fd set: %s", strerror(-r));
529 goto fail;
530 }
531
532 if ((r = manager_serialize(m, f, fds)) < 0) {
533 log_error("Failed to serialize state: %s", strerror(-r));
534 goto fail;
535 }
536
537 if (fseeko(f, 0, SEEK_SET) < 0) {
538 log_error("Failed to rewind serialization fd: %m");
539 goto fail;
540 }
541
542 if ((r = fd_cloexec(fileno(f), false)) < 0) {
543 log_error("Failed to disable O_CLOEXEC for serialization: %s", strerror(-r));
544 goto fail;
545 }
546
547 if ((r = fdset_cloexec(fds, false)) < 0) {
548 log_error("Failed to disable O_CLOEXEC for serialization fds: %s", strerror(-r));
549 goto fail;
550 }
551
552 *_f = f;
553 *_fds = fds;
554
555 return 0;
556
557fail:
558 fdset_free(fds);
559
560 if (f)
561 fclose(f);
562
563 return r;
564}
565
60918275
LP
566int main(int argc, char *argv[]) {
567 Manager *m = NULL;
87f0e418 568 Unit *target = NULL;
60918275
LP
569 Job *job = NULL;
570 int r, retval = 1;
a16e1123
LP
571 FDSet *fds = NULL;
572 bool reexecute = false;
27b14a22 573
843d2643 574 if (getpid() == 1) {
a5dab5ce 575 running_as = MANAGER_INIT;
843d2643
LP
576 log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
577 } else
a5dab5ce
LP
578 running_as = MANAGER_SESSION;
579
f170852a
LP
580 if (set_default_unit(SPECIAL_DEFAULT_TARGET) < 0)
581 goto finish;
60918275 582
f170852a
LP
583 /* Mount /proc, /sys and friends, so that /proc/cmdline and
584 * /proc/$PID/fd is available. */
8efe3c01
LP
585 if (geteuid() == 0)
586 if (mount_setup() < 0)
587 goto finish;
4ade7963
LP
588
589 /* Reset all signal handlers. */
590 assert_se(reset_all_signal_handlers() == 0);
591
078e4539 592 /* If we are init, we can block sigkill. Yay. */
9a34ec5f 593 ignore_signals(SIGNALS_IGNORE, -1);
078e4539 594
a5dab5ce
LP
595 if (running_as != MANAGER_SESSION)
596 if (parse_proc_cmdline() < 0)
597 goto finish;
f170852a
LP
598
599 log_parse_environment();
600
601 if (parse_argv(argc, argv) < 0)
602 goto finish;
603
604 if (action == ACTION_HELP) {
605 retval = help();
606 goto finish;
e537352b
LP
607 } else if (action == ACTION_DUMP_CONFIGURATION_ITEMS) {
608 unit_dump_config_items(stdout);
609 retval = 0;
610 goto finish;
4288f619
LP
611 } else if (action == ACTION_DONE) {
612 retval = 0;
613 goto finish;
f170852a
LP
614 }
615
e965d56d 616 assert_se(action == ACTION_RUN || action == ACTION_TEST);
f170852a 617
a16e1123
LP
618 /* Remember open file descriptors for later deserialization */
619 if (serialization) {
620 if ((r = fdset_new_fill(&fds)) < 0) {
621 log_error("Failed to allocate fd set: %s", strerror(-r));
622 goto finish;
623 }
624
625 assert_se(fdset_remove(fds, fileno(serialization)) >= 0);
626 } else
627 close_all_fds(NULL, 0);
628
09082a94 629 /* Set up PATH unless it is already set */
e537352b
LP
630 setenv("PATH",
631 "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
632 running_as == MANAGER_INIT);
09082a94 633
f170852a
LP
634 /* Move out of the way, so that we won't block unmounts */
635 assert_se(chdir("/") == 0);
636
80876c20
LP
637 if (running_as != MANAGER_SESSION) {
638 /* Become a session leader if we aren't one yet. */
639 setsid();
4ade7963 640
80876c20
LP
641 /* Disable the umask logic */
642 umask(0);
643 }
644
843d2643
LP
645 /* Make sure D-Bus doesn't fiddle with the SIGPIPE handlers */
646 dbus_connection_set_change_sigpipe(FALSE);
647
2146621b
LP
648 /* Reset the console, but only if this is really init and we
649 * are freshly booted */
843d2643 650 if (running_as != MANAGER_SESSION && action == ACTION_RUN) {
2146621b 651 console_setup(getpid() == 1 && !serialization);
843d2643
LP
652 make_null_stdio();
653 }
4ade7963 654
18149b9f 655 /* Open the logging devices, if possible and necessary */
843d2643 656 log_open();
4ade7963 657
5373d602
LP
658 /* Make sure we leave a core dump without panicing the
659 * kernel. */
4fc935ca
LP
660 if (getpid() == 1)
661 install_crash_handler();
97c4f35c 662
a5dab5ce
LP
663 log_debug("systemd running in %s mode.", manager_running_as_to_string(running_as));
664
af5bc85d 665 if (running_as == MANAGER_INIT) {
11c3a4ee 666 kmod_setup();
e537352b 667 hostname_setup();
af5bc85d
LP
668 loopback_setup();
669 }
302e8c4c 670
80876c20 671 if ((r = manager_new(running_as, confirm_spawn, &m)) < 0) {
8e274523 672 log_error("Failed to allocate manager object: %s", strerror(-r));
60918275
LP
673 goto finish;
674 }
675
a16e1123 676 if ((r = manager_startup(m, serialization, fds)) < 0)
6e2ef85b 677 log_error("Failed to fully start up daemon: %s", strerror(-r));
a16e1123
LP
678
679 if (fds) {
680 /* This will close all file descriptors that were opened, but
681 * not claimed by any unit. */
682
683 fdset_free(fds);
684 fds = NULL;
f50e0a01
LP
685 }
686
a16e1123
LP
687 if (serialization) {
688 fclose(serialization);
689 serialization = NULL;
690 } else {
691 log_debug("Activating default unit: %s", default_unit);
692
693 if ((r = manager_load_unit(m, default_unit, NULL, &target)) < 0) {
694 log_error("Failed to load default target: %s", strerror(-r));
27b14a22 695
a16e1123
LP
696 log_info("Trying to load rescue target...");
697 if ((r = manager_load_unit(m, SPECIAL_RESCUE_TARGET, NULL, &target)) < 0) {
698 log_error("Failed to load rescue target: %s", strerror(-r));
699 goto finish;
700 }
701 }
37d88da7 702
a16e1123 703 if (action == ACTION_TEST) {
40d50879 704 printf("-> By units:\n");
a16e1123
LP
705 manager_dump_units(m, stdout, "\t");
706 }
707
708 if ((r = manager_add_job(m, JOB_START, target, JOB_REPLACE, false, &job)) < 0) {
709 log_error("Failed to start default target: %s", strerror(-r));
37d88da7
LP
710 goto finish;
711 }
60918275 712
a16e1123 713 if (action == ACTION_TEST) {
40d50879 714 printf("-> By jobs:\n");
a16e1123
LP
715 manager_dump_jobs(m, stdout, "\t");
716 retval = 0;
717 goto finish;
718 }
e965d56d 719 }
d46de8a1 720
a16e1123
LP
721 for (;;) {
722 if ((r = manager_loop(m)) < 0) {
723 log_error("Failed to run mainloop: %s", strerror(-r));
724 goto finish;
725 }
11dd41ce 726
a16e1123 727 switch (m->exit_code) {
e965d56d 728
a16e1123
LP
729 case MANAGER_EXIT:
730 retval = 0;
731 log_debug("Exit.");
732 goto finish;
e965d56d 733
a16e1123
LP
734 case MANAGER_RELOAD:
735 if ((r = manager_reload(m)) < 0)
736 log_error("Failed to reload: %s", strerror(-r));
737 break;
cea8e32e 738
a16e1123 739 case MANAGER_REEXECUTE:
a16e1123
LP
740 if (prepare_reexecute(m, &serialization, &fds) < 0)
741 goto finish;
60918275 742
a16e1123
LP
743 reexecute = true;
744 log_debug("Reexecuting.");
745 goto finish;
746
747 default:
748 assert_not_reached("Unknown exit code.");
749 }
750 }
f170852a 751
60918275
LP
752finish:
753 if (m)
754 manager_free(m);
755
f170852a 756 free(default_unit);
b9cd2ec1 757
ea430986
LP
758 dbus_shutdown();
759
a16e1123
LP
760 if (reexecute) {
761 const char *args[11];
762 unsigned i = 0;
763 char sfd[16];
764
765 assert(serialization);
766 assert(fds);
767
768 args[i++] = SYSTEMD_BINARY_PATH;
769
770 args[i++] = "--log-level";
771 args[i++] = log_level_to_string(log_get_max_level());
772
773 args[i++] = "--log-target";
774 args[i++] = log_target_to_string(log_get_target());
775
776 args[i++] = "--running-as";
777 args[i++] = manager_running_as_to_string(running_as);
778
779 snprintf(sfd, sizeof(sfd), "%i", fileno(serialization));
780 char_array_0(sfd);
781
782 args[i++] = "--deserialize";
783 args[i++] = sfd;
784
785 if (confirm_spawn)
786 args[i++] = "--confirm-spawn";
787
788 args[i++] = NULL;
789
790 assert(i <= ELEMENTSOF(args));
791
792 execv(args[0], (char* const*) args);
793
794 log_error("Failed to reexecute: %m");
795 }
796
797 if (serialization)
798 fclose(serialization);
799
800 if (fds)
801 fdset_free(fds);
802
c3b3c274
LP
803 if (getpid() == 1)
804 freeze();
805
60918275
LP
806 return retval;
807}