]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/main.c
service: properly remember if a sysv is actually enabled
[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"
fa0f4d8a 41#include "modprobe-setup.h"
302e8c4c 42#include "load-fragment.h"
a16e1123 43#include "fdset.h"
514f4ef5 44#include "special.h"
487393e9 45#include "conf-parser.h"
398ef8ba 46#include "bus-errors.h"
ad780f19 47#include "missing.h"
60918275 48
f170852a
LP
49static enum {
50 ACTION_RUN,
e965d56d 51 ACTION_HELP,
e537352b 52 ACTION_TEST,
4288f619
LP
53 ACTION_DUMP_CONFIGURATION_ITEMS,
54 ACTION_DONE
fa0f4d8a 55} arg_action = ACTION_RUN;
f170852a 56
fa0f4d8a 57static char *arg_default_unit = NULL;
0ff4cdd9 58static char *arg_console = NULL;
fa0f4d8a
LP
59static ManagerRunningAs arg_running_as = _MANAGER_RUNNING_AS_INVALID;
60
61static bool arg_dump_core = true;
62static bool arg_crash_shell = false;
63static int arg_crash_chvt = -1;
64static bool arg_confirm_spawn = false;
65static bool arg_nomodules = false;
9e58ff9c 66static bool arg_show_status = true;
4fc935ca 67
a16e1123 68static FILE* serialization = NULL;
80876c20 69
93a46b0b 70_noreturn_ static void freeze(void) {
97c4f35c
LP
71 for (;;)
72 pause();
73}
74
6f5e3f35
LP
75static void nop_handler(int sig) {
76}
77
93a46b0b 78_noreturn_ static void crash(int sig) {
97c4f35c 79
fa0f4d8a 80 if (!arg_dump_core)
582a507f 81 log_error("Caught <%s>, not dumping core.", signal_to_string(sig));
97c4f35c 82 else {
6f5e3f35 83 struct sigaction sa;
97c4f35c
LP
84 pid_t pid;
85
6f5e3f35
LP
86 /* We want to wait for the core process, hence let's enable SIGCHLD */
87 zero(sa);
88 sa.sa_handler = nop_handler;
89 sa.sa_flags = SA_NOCLDSTOP|SA_RESTART;
90 assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
91
97c4f35c 92 if ((pid = fork()) < 0)
582a507f 93 log_error("Caught <%s>, cannot fork for core dump: %s", signal_to_string(sig), strerror(errno));
97c4f35c
LP
94
95 else if (pid == 0) {
97c4f35c
LP
96 struct rlimit rl;
97
98 /* Enable default signal handler for core dump */
99 zero(sa);
100 sa.sa_handler = SIG_DFL;
101 assert_se(sigaction(sig, &sa, NULL) == 0);
102
103 /* Don't limit the core dump size */
104 zero(rl);
105 rl.rlim_cur = RLIM_INFINITY;
106 rl.rlim_max = RLIM_INFINITY;
107 setrlimit(RLIMIT_CORE, &rl);
108
109 /* Just to be sure... */
110 assert_se(chdir("/") == 0);
111
112 /* Raise the signal again */
113 raise(sig);
114
115 assert_not_reached("We shouldn't be here...");
116 _exit(1);
4fc935ca
LP
117
118 } else {
119 int status, r;
120
121 /* Order things nicely. */
122 if ((r = waitpid(pid, &status, 0)) < 0)
582a507f 123 log_error("Caught <%s>, waitpid() failed: %s", signal_to_string(sig), strerror(errno));
4fc935ca 124 else if (!WCOREDUMP(status))
582a507f 125 log_error("Caught <%s>, core dump failed.", signal_to_string(sig));
4fc935ca 126 else
582a507f 127 log_error("Caught <%s>, dumped core as pid %lu.", signal_to_string(sig), (unsigned long) pid);
97c4f35c
LP
128 }
129 }
130
fa0f4d8a
LP
131 if (arg_crash_chvt)
132 chvt(arg_crash_chvt);
601f6a1e 133
fa0f4d8a 134 if (arg_crash_shell) {
6f5e3f35
LP
135 struct sigaction sa;
136 pid_t pid;
8c43883a 137
4fc935ca
LP
138 log_info("Executing crash shell in 10s...");
139 sleep(10);
140
6f5e3f35
LP
141 /* Let the kernel reap children for us */
142 zero(sa);
143 sa.sa_handler = SIG_IGN;
144 sa.sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART;
145 assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
8c43883a 146
6f5e3f35
LP
147 if ((pid = fork()) < 0)
148 log_error("Failed to fork off crash shell: %s", strerror(errno));
149 else if (pid == 0) {
843d2643 150 int fd, r;
ea5652c2 151
21de3988 152 if ((fd = acquire_terminal("/dev/console", false, true, true)) < 0)
ea5652c2 153 log_error("Failed to acquire terminal: %s", strerror(-fd));
5b2a0903 154 else if ((r = make_stdio(fd)) < 0)
843d2643 155 log_error("Failed to duplicate terminal fd: %s", strerror(-r));
ea5652c2 156
6f5e3f35
LP
157 execl("/bin/sh", "/bin/sh", NULL);
158
159 log_error("execl() failed: %s", strerror(errno));
160 _exit(1);
161 }
c99b188e 162
bb00e604 163 log_info("Successfully spawned crash shall as pid %lu.", (unsigned long) pid);
4fc935ca
LP
164 }
165
166 log_info("Freezing execution.");
97c4f35c
LP
167 freeze();
168}
169
170static void install_crash_handler(void) {
171 struct sigaction sa;
172
173 zero(sa);
174
175 sa.sa_handler = crash;
176 sa.sa_flags = SA_NODEFER;
177
1b91d3e8 178 sigaction_many(&sa, SIGNALS_CRASH_HANDLER, -1);
97c4f35c 179}
f170852a 180
843d2643
LP
181static int make_null_stdio(void) {
182 int null_fd, r;
80876c20 183
c8513d54 184 if ((null_fd = open("/dev/null", O_RDWR|O_NOCTTY)) < 0) {
80876c20 185 log_error("Failed to open /dev/null: %m");
843d2643 186 return -errno;
80876c20
LP
187 }
188
843d2643
LP
189 if ((r = make_stdio(null_fd)) < 0)
190 log_warning("Failed to dup2() device: %s", strerror(-r));
80876c20 191
843d2643
LP
192 return r;
193}
80876c20 194
843d2643
LP
195static int console_setup(bool do_reset) {
196 int tty_fd, r;
80876c20 197
843d2643
LP
198 /* If we are init, we connect stdin/stdout/stderr to /dev/null
199 * and make sure we don't have a controlling tty. */
80876c20 200
843d2643
LP
201 release_terminal();
202
203 if (!do_reset)
204 return 0;
80876c20 205
843d2643
LP
206 if ((tty_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0) {
207 log_error("Failed to open /dev/console: %s", strerror(-tty_fd));
208 return -tty_fd;
209 }
80876c20 210
843d2643
LP
211 if ((r = reset_terminal(tty_fd)) < 0)
212 log_error("Failed to reset /dev/console: %s", strerror(-r));
213
214 close_nointr_nofail(tty_fd);
80876c20
LP
215 return r;
216}
217
f170852a
LP
218static int set_default_unit(const char *u) {
219 char *c;
220
221 assert(u);
222
223 if (!(c = strdup(u)))
224 return -ENOMEM;
225
fa0f4d8a
LP
226 free(arg_default_unit);
227 arg_default_unit = c;
f170852a
LP
228 return 0;
229}
230
231static int parse_proc_cmdline_word(const char *word) {
232
233 static const char * const rlmap[] = {
514f4ef5
LP
234 "single", SPECIAL_RESCUE_TARGET,
235 "-s", SPECIAL_RESCUE_TARGET,
236 "s", SPECIAL_RESCUE_TARGET,
237 "S", SPECIAL_RESCUE_TARGET,
238 "1", SPECIAL_RESCUE_TARGET,
f170852a
LP
239 "2", SPECIAL_RUNLEVEL2_TARGET,
240 "3", SPECIAL_RUNLEVEL3_TARGET,
241 "4", SPECIAL_RUNLEVEL4_TARGET,
242 "5", SPECIAL_RUNLEVEL5_TARGET
243 };
9e58ff9c 244 bool ignore_quiet = false;
f170852a 245
2f198e2f
LP
246 if (startswith(word, "systemd.unit="))
247 return set_default_unit(word + 13);
f170852a
LP
248
249 else if (startswith(word, "systemd.log_target=")) {
250
251 if (log_set_target_from_string(word + 19) < 0)
252 log_warning("Failed to parse log target %s. Ignoring.", word + 19);
253
254 } else if (startswith(word, "systemd.log_level=")) {
255
256 if (log_set_max_level_from_string(word + 18) < 0)
257 log_warning("Failed to parse log level %s. Ignoring.", word + 18);
258
bbe63281
LP
259 } else if (startswith(word, "systemd.log_color=")) {
260
261 if (log_show_color_from_string(word + 18) < 0)
262 log_warning("Failed to parse log color setting %s. Ignoring.", word + 18);
263
264 } else if (startswith(word, "systemd.log_location=")) {
265
266 if (log_show_location_from_string(word + 21) < 0)
267 log_warning("Failed to parse log location setting %s. Ignoring.", word + 21);
268
4fc935ca
LP
269 } else if (startswith(word, "systemd.dump_core=")) {
270 int r;
271
272 if ((r = parse_boolean(word + 18)) < 0)
601f6a1e 273 log_warning("Failed to parse dump core switch %s, Ignoring.", word + 18);
4fc935ca 274 else
fa0f4d8a 275 arg_dump_core = r;
4fc935ca
LP
276
277 } else if (startswith(word, "systemd.crash_shell=")) {
278 int r;
279
280 if ((r = parse_boolean(word + 20)) < 0)
601f6a1e 281 log_warning("Failed to parse crash shell switch %s, Ignoring.", word + 20);
4fc935ca 282 else
fa0f4d8a 283 arg_crash_shell = r;
5e7ee61c
LP
284
285 } else if (startswith(word, "systemd.confirm_spawn=")) {
286 int r;
287
288 if ((r = parse_boolean(word + 22)) < 0)
289 log_warning("Failed to parse confirm spawn switch %s, Ignoring.", word + 22);
290 else
fa0f4d8a 291 arg_confirm_spawn = r;
5e7ee61c 292
601f6a1e
LP
293 } else if (startswith(word, "systemd.crash_chvt=")) {
294 int k;
295
296 if (safe_atoi(word + 19, &k) < 0)
297 log_warning("Failed to parse crash chvt switch %s, Ignoring.", word + 19);
298 else
fa0f4d8a 299 arg_crash_chvt = k;
601f6a1e 300
9e58ff9c
LP
301 } else if (startswith(word, "systemd.show_status=")) {
302 int r;
303
304 if ((r = parse_boolean(word + 20)) < 0)
305 log_warning("Failed to parse show status switch %s, Ignoring.", word + 20);
306 else {
307 arg_show_status = r;
308 ignore_quiet = true;
309 }
310
4fc935ca
LP
311 } else if (startswith(word, "systemd.")) {
312
313 log_warning("Unknown kernel switch %s. Ignoring.", word);
314
bbe63281
LP
315 log_info("Supported kernel switches:\n"
316 "systemd.unit=UNIT Default unit to start\n"
317 "systemd.log_target=console|kmsg|syslog| Log target\n"
318 " syslog-org-kmsg|null\n"
319 "systemd.log_level=LEVEL Log level\n"
320 "systemd.log_color=0|1 Highlight important log messages\n"
321 "systemd.log_location=0|1 Include code location in log messages\n"
322 "systemd.dump_core=0|1 Dump core on crash\n"
9e58ff9c 323 "systemd.crash_shell=0|1 Run shell on crash\n"
bbe63281 324 "systemd.crash_chvt=N Change to VT #N on crash\n"
9e58ff9c
LP
325 "systemd.confirm_spawn=0|1 Confirm every process spawn\n"
326 "systemd.show_status=0|1 Show status updates on the console during bootup\n");
4fc935ca 327
fa0f4d8a
LP
328 } else if (streq(word, "nomodules"))
329 arg_nomodules = true;
0ff4cdd9
LP
330 else if (startswith(word, "console=")) {
331 const char *k;
332 size_t l;
333 char *w = NULL;
334
335 k = word + 8;
336 l = strcspn(k, ",");
337
338 if (l < 4 ||
339 !startswith(k, "tty") ||
340 k[3+strspn(k+3, "0123456789")] != 0) {
341
342 if (!(w = strndup(k, l)))
343 return -ENOMEM;
344 }
345
346 free(arg_console);
347 arg_console = w;
348
349 } else if (streq(word, "quiet")) {
9e58ff9c
LP
350 if (!ignore_quiet)
351 arg_show_status = false;
352 } else {
f170852a
LP
353 unsigned i;
354
355 /* SysV compatibility */
f170852a
LP
356 for (i = 0; i < ELEMENTSOF(rlmap); i += 2)
357 if (streq(word, rlmap[i]))
358 return set_default_unit(rlmap[i+1]);
359 }
360
361 return 0;
362}
363
487393e9
LP
364static int config_parse_level(
365 const char *filename,
366 unsigned line,
367 const char *section,
368 const char *lvalue,
369 const char *rvalue,
370 void *data,
371 void *userdata) {
372
373 assert(filename);
374 assert(lvalue);
375 assert(rvalue);
376
377 log_set_max_level_from_string(rvalue);
378 return 0;
379}
380
381static int config_parse_target(
382 const char *filename,
383 unsigned line,
384 const char *section,
385 const char *lvalue,
386 const char *rvalue,
387 void *data,
388 void *userdata) {
389
390 assert(filename);
391 assert(lvalue);
392 assert(rvalue);
393
394 log_set_target_from_string(rvalue);
395 return 0;
396}
397
398static int config_parse_color(
399 const char *filename,
400 unsigned line,
401 const char *section,
402 const char *lvalue,
403 const char *rvalue,
404 void *data,
405 void *userdata) {
406
407 assert(filename);
408 assert(lvalue);
409 assert(rvalue);
410
411 log_show_color_from_string(rvalue);
412 return 0;
413}
414
415static int config_parse_location(
416 const char *filename,
417 unsigned line,
418 const char *section,
419 const char *lvalue,
420 const char *rvalue,
421 void *data,
422 void *userdata) {
423
424 assert(filename);
425 assert(lvalue);
426 assert(rvalue);
427
428 log_show_location_from_string(rvalue);
429 return 0;
430}
431
432static int config_parse_cpu_affinity(
433 const char *filename,
434 unsigned line,
435 const char *section,
436 const char *lvalue,
437 const char *rvalue,
438 void *data,
439 void *userdata) {
440
441 char *w;
442 size_t l;
443 char *state;
444 cpu_set_t *c = NULL;
445 unsigned ncpus = 0;
446
447 assert(filename);
448 assert(lvalue);
449 assert(rvalue);
450
f60f22df 451 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
487393e9
LP
452 char *t;
453 int r;
454 unsigned cpu;
455
456 if (!(t = strndup(w, l)))
457 return -ENOMEM;
458
459 r = safe_atou(t, &cpu);
460 free(t);
461
462 if (!c)
463 if (!(c = cpu_set_malloc(&ncpus)))
464 return -ENOMEM;
465
466 if (r < 0 || cpu >= ncpus) {
467 log_error("[%s:%u] Failed to parse CPU affinity: %s", filename, line, rvalue);
468 CPU_FREE(c);
469 return -EBADMSG;
470 }
471
472 CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c);
473 }
474
475 if (c) {
476 if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0)
477 log_warning("Failed to set CPU affinity: %m");
478
479 CPU_FREE(c);
480 }
481
482 return 0;
483}
484
485static int parse_config_file(void) {
486
487 const ConfigItem items[] = {
488 { "LogLevel", config_parse_level, NULL, "Manager" },
489 { "LogTarget", config_parse_target, NULL, "Manager" },
490 { "LogColor", config_parse_color, NULL, "Manager" },
491 { "LogLocation", config_parse_location, NULL, "Manager" },
492 { "DumpCore", config_parse_bool, &arg_dump_core, "Manager" },
493 { "CrashShell", config_parse_bool, &arg_crash_shell, "Manager" },
494 { "ShowStatus", config_parse_bool, &arg_show_status, "Manager" },
495 { "CrashChVT", config_parse_int, &arg_crash_chvt, "Manager" },
496 { "CPUAffinity", config_parse_cpu_affinity, NULL, "Manager" },
497 { NULL, NULL, NULL, NULL }
498 };
499
500 static const char * const sections[] = {
501 "Manager",
502 NULL
503 };
504
505 FILE *f;
506 const char *fn;
507 int r;
508
509 fn = arg_running_as == MANAGER_SYSTEM ? SYSTEM_CONFIG_FILE : SESSION_CONFIG_FILE;
510
511 if (!(f = fopen(fn, "re"))) {
512 if (errno == ENOENT)
513 return 0;
514
515 log_warning("Failed to open configuration file '%s': %m", fn);
516 return 0;
517 }
518
519 if ((r = config_parse(fn, f, sections, items, false, NULL)) < 0)
520 log_warning("Failed to parse configuration file: %s", strerror(-r));
521
522 fclose(f);
523
524 return 0;
525}
526
f170852a
LP
527static int parse_proc_cmdline(void) {
528 char *line;
529 int r;
530 char *w;
531 size_t l;
532 char *state;
533
534 if ((r = read_one_line_file("/proc/cmdline", &line)) < 0) {
535 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(errno));
536 return 0;
537 }
538
539 FOREACH_WORD_QUOTED(w, l, line, state) {
540 char *word;
541
542 if (!(word = strndup(w, l))) {
543 r = -ENOMEM;
544 goto finish;
545 }
546
547 r = parse_proc_cmdline_word(word);
548 free(word);
549
550 if (r < 0)
551 goto finish;
552 }
553
554 r = 0;
555
556finish:
557 free(line);
558 return r;
559}
560
561static int parse_argv(int argc, char *argv[]) {
562
563 enum {
564 ARG_LOG_LEVEL = 0x100,
565 ARG_LOG_TARGET,
bbe63281
LP
566 ARG_LOG_COLOR,
567 ARG_LOG_LOCATION,
2f198e2f 568 ARG_UNIT,
edb9aaa8
LP
569 ARG_SYSTEM,
570 ARG_SESSION,
e537352b 571 ARG_TEST,
80876c20 572 ARG_DUMP_CONFIGURATION_ITEMS,
9e58ff9c
LP
573 ARG_DUMP_CORE,
574 ARG_CRASH_SHELL,
a16e1123 575 ARG_CONFIRM_SPAWN,
9e58ff9c 576 ARG_SHOW_STATUS,
4288f619
LP
577 ARG_DESERIALIZE,
578 ARG_INTROSPECT
f170852a
LP
579 };
580
581 static const struct option options[] = {
a16e1123
LP
582 { "log-level", required_argument, NULL, ARG_LOG_LEVEL },
583 { "log-target", required_argument, NULL, ARG_LOG_TARGET },
bbe63281
LP
584 { "log-color", optional_argument, NULL, ARG_LOG_COLOR },
585 { "log-location", optional_argument, NULL, ARG_LOG_LOCATION },
2f198e2f 586 { "unit", required_argument, NULL, ARG_UNIT },
edb9aaa8
LP
587 { "system", no_argument, NULL, ARG_SYSTEM },
588 { "session", no_argument, NULL, ARG_SESSION },
a16e1123
LP
589 { "test", no_argument, NULL, ARG_TEST },
590 { "help", no_argument, NULL, 'h' },
591 { "dump-configuration-items", no_argument, NULL, ARG_DUMP_CONFIGURATION_ITEMS },
9e58ff9c
LP
592 { "dump-core", no_argument, NULL, ARG_DUMP_CORE },
593 { "crash-shell", no_argument, NULL, ARG_CRASH_SHELL },
a16e1123 594 { "confirm-spawn", no_argument, NULL, ARG_CONFIRM_SPAWN },
9e58ff9c 595 { "show-status", no_argument, NULL, ARG_SHOW_STATUS },
a16e1123 596 { "deserialize", required_argument, NULL, ARG_DESERIALIZE },
4288f619 597 { "introspect", optional_argument, NULL, ARG_INTROSPECT },
a16e1123 598 { NULL, 0, NULL, 0 }
f170852a
LP
599 };
600
601 int c, r;
602
603 assert(argc >= 1);
604 assert(argv);
605
1d2e23ab 606 while ((c = getopt_long(argc, argv, "hD", options, NULL)) >= 0)
f170852a
LP
607
608 switch (c) {
609
610 case ARG_LOG_LEVEL:
611 if ((r = log_set_max_level_from_string(optarg)) < 0) {
612 log_error("Failed to parse log level %s.", optarg);
613 return r;
614 }
615
616 break;
617
618 case ARG_LOG_TARGET:
619
620 if ((r = log_set_target_from_string(optarg)) < 0) {
621 log_error("Failed to parse log target %s.", optarg);
622 return r;
623 }
624
625 break;
626
bbe63281
LP
627 case ARG_LOG_COLOR:
628
d0b170c8
LP
629 if (optarg) {
630 if ((r = log_show_color_from_string(optarg)) < 0) {
631 log_error("Failed to parse log color setting %s.", optarg);
632 return r;
633 }
634 } else
635 log_show_color(true);
bbe63281
LP
636
637 break;
638
639 case ARG_LOG_LOCATION:
640
d0b170c8
LP
641 if (optarg) {
642 if ((r = log_show_location_from_string(optarg)) < 0) {
643 log_error("Failed to parse log location setting %s.", optarg);
644 return r;
645 }
646 } else
647 log_show_location(true);
bbe63281
LP
648
649 break;
650
2f198e2f 651 case ARG_UNIT:
f170852a
LP
652
653 if ((r = set_default_unit(optarg)) < 0) {
654 log_error("Failed to set default unit %s: %s", optarg, strerror(-r));
655 return r;
656 }
657
658 break;
659
edb9aaa8
LP
660 case ARG_SYSTEM:
661 arg_running_as = MANAGER_SYSTEM;
662 break;
a5dab5ce 663
edb9aaa8
LP
664 case ARG_SESSION:
665 arg_running_as = MANAGER_SESSION;
a5dab5ce 666 break;
a5dab5ce 667
e965d56d 668 case ARG_TEST:
fa0f4d8a 669 arg_action = ACTION_TEST;
e965d56d
LP
670 break;
671
e537352b 672 case ARG_DUMP_CONFIGURATION_ITEMS:
fa0f4d8a 673 arg_action = ACTION_DUMP_CONFIGURATION_ITEMS;
e537352b
LP
674 break;
675
9e58ff9c
LP
676 case ARG_DUMP_CORE:
677 arg_dump_core = true;
678 break;
679
680 case ARG_CRASH_SHELL:
681 arg_crash_shell = true;
682 break;
683
80876c20 684 case ARG_CONFIRM_SPAWN:
fa0f4d8a 685 arg_confirm_spawn = true;
80876c20
LP
686 break;
687
9e58ff9c
LP
688 case ARG_SHOW_STATUS:
689 arg_show_status = true;
690 break;
691
a16e1123
LP
692 case ARG_DESERIALIZE: {
693 int fd;
694 FILE *f;
695
696 if ((r = safe_atoi(optarg, &fd)) < 0 || fd < 0) {
697 log_error("Failed to parse deserialize option %s.", optarg);
698 return r;
699 }
700
701 if (!(f = fdopen(fd, "r"))) {
702 log_error("Failed to open serialization fd: %m");
703 return r;
704 }
705
706 if (serialization)
707 fclose(serialization);
708
709 serialization = f;
710
711 break;
712 }
713
4288f619
LP
714 case ARG_INTROSPECT: {
715 const char * const * i = NULL;
716
717 for (i = bus_interface_table; *i; i += 2)
718 if (!optarg || streq(i[0], optarg)) {
719 fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
720 "<node>\n", stdout);
721 fputs(i[1], stdout);
722 fputs("</node>\n", stdout);
723
724 if (optarg)
725 break;
726 }
727
728 if (!i[0] && optarg)
729 log_error("Unknown interface %s.", optarg);
730
fa0f4d8a 731 arg_action = ACTION_DONE;
4288f619
LP
732 break;
733 }
734
f170852a 735 case 'h':
fa0f4d8a 736 arg_action = ACTION_HELP;
f170852a
LP
737 break;
738
1d2e23ab
LP
739 case 'D':
740 log_set_max_level(LOG_DEBUG);
741 break;
742
f170852a
LP
743 case '?':
744 return -EINVAL;
745
746 default:
747 log_error("Unknown option code %c", c);
748 return -EINVAL;
749 }
750
51f0e189
LP
751 /* PID 1 will get the kernel arguments as parameters, which we
752 * ignore and unconditionally read from
753 * /proc/cmdline. However, we need to ignore those arguments
754 * here. */
fa0f4d8a 755 if (arg_running_as != MANAGER_SYSTEM && optind < argc) {
51f0e189
LP
756 log_error("Excess arguments.");
757 return -EINVAL;
758 }
759
f170852a
LP
760 return 0;
761}
762
763static int help(void) {
764
2e33c433 765 printf("%s [OPTIONS...]\n\n"
bbe63281 766 "Starts up and maintains the system or a session.\n\n"
e537352b 767 " -h --help Show this help\n"
e537352b 768 " --test Determine startup sequence, dump it and exit\n"
80876c20 769 " --dump-configuration-items Dump understood unit configuration items\n"
bbe63281 770 " --introspect[=INTERFACE] Extract D-Bus interface data\n"
9e58ff9c 771 " --unit=UNIT Set default unit\n"
edb9aaa8
LP
772 " --system Run a system instance, even if PID != 1\n"
773 " --session Run a session instance\n"
9e58ff9c
LP
774 " --dump-core Dump core on crash\n"
775 " --crash-shell Run shell on crash\n"
776 " --confirm-spawn Ask for confirmation when spawning processes\n"
777 " --show-status Show status updates on the console during bootup\n"
bbe63281 778 " --log-target=TARGET Set log target (console, syslog, kmsg, syslog-or-kmsg, null)\n"
9e58ff9c 779 " --log-level=LEVEL Set log level (debug, info, notice, warning, err, crit, alert, emerg)\n"
2218198b 780 " --log-color[=0|1] Highlight important log messages\n"
bbe63281 781 " --log-location[=0|1] Include code location in log messages\n",
5b6319dc 782 program_invocation_short_name);
f170852a
LP
783
784 return 0;
785}
786
a16e1123
LP
787static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds) {
788 FILE *f = NULL;
789 FDSet *fds = NULL;
790 int r;
791
792 assert(m);
793 assert(_f);
794 assert(_fds);
795
d8d5ab98 796 if ((r = manager_open_serialization(m, &f)) < 0) {
a16e1123
LP
797 log_error("Failed to create serialization faile: %s", strerror(-r));
798 goto fail;
799 }
800
801 if (!(fds = fdset_new())) {
802 r = -ENOMEM;
803 log_error("Failed to allocate fd set: %s", strerror(-r));
804 goto fail;
805 }
806
807 if ((r = manager_serialize(m, f, fds)) < 0) {
808 log_error("Failed to serialize state: %s", strerror(-r));
809 goto fail;
810 }
811
812 if (fseeko(f, 0, SEEK_SET) < 0) {
813 log_error("Failed to rewind serialization fd: %m");
814 goto fail;
815 }
816
817 if ((r = fd_cloexec(fileno(f), false)) < 0) {
818 log_error("Failed to disable O_CLOEXEC for serialization: %s", strerror(-r));
819 goto fail;
820 }
821
822 if ((r = fdset_cloexec(fds, false)) < 0) {
823 log_error("Failed to disable O_CLOEXEC for serialization fds: %s", strerror(-r));
824 goto fail;
825 }
826
827 *_f = f;
828 *_fds = fds;
829
830 return 0;
831
832fail:
833 fdset_free(fds);
834
835 if (f)
836 fclose(f);
837
838 return r;
839}
840
60918275
LP
841int main(int argc, char *argv[]) {
842 Manager *m = NULL;
87f0e418 843 Unit *target = NULL;
60918275 844 int r, retval = 1;
a16e1123
LP
845 FDSet *fds = NULL;
846 bool reexecute = false;
27b14a22 847
2cb1a60d
LP
848 if (getpid() != 1 && strstr(program_invocation_short_name, "init")) {
849 /* This is compatbility support for SysV, where
850 * calling init as a user is identical to telinit. */
851
852 errno = -ENOENT;
853 execv(SYSTEMCTL_BINARY_PATH, argv);
854 log_error("Failed to exec " SYSTEMCTL_BINARY_PATH ": %m");
855 return 1;
856 }
857
2cc59dbf 858 log_show_color(isatty(STDERR_FILENO) > 0);
bbe63281 859 log_show_location(false);
7c706717 860 log_set_max_level(LOG_INFO);
bbe63281 861
843d2643 862 if (getpid() == 1) {
fa0f4d8a 863 arg_running_as = MANAGER_SYSTEM;
843d2643 864 log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
0ff4cdd9
LP
865
866 if (label_init() < 0)
867 goto finish;
bbe63281 868 } else {
fa0f4d8a 869 arg_running_as = MANAGER_SESSION;
bbe63281
LP
870 log_set_target(LOG_TARGET_CONSOLE);
871 }
a5dab5ce 872
f170852a
LP
873 if (set_default_unit(SPECIAL_DEFAULT_TARGET) < 0)
874 goto finish;
60918275 875
f170852a
LP
876 /* Mount /proc, /sys and friends, so that /proc/cmdline and
877 * /proc/$PID/fd is available. */
ca326f6f 878 if (geteuid() == 0 && !getenv("SYSTEMD_SKIP_API_MOUNTS"))
8efe3c01
LP
879 if (mount_setup() < 0)
880 goto finish;
4ade7963
LP
881
882 /* Reset all signal handlers. */
883 assert_se(reset_all_signal_handlers() == 0);
884
078e4539 885 /* If we are init, we can block sigkill. Yay. */
9a34ec5f 886 ignore_signals(SIGNALS_IGNORE, -1);
078e4539 887
487393e9
LP
888 if (parse_config_file() < 0)
889 goto finish;
890
fa0f4d8a 891 if (arg_running_as == MANAGER_SYSTEM)
a5dab5ce
LP
892 if (parse_proc_cmdline() < 0)
893 goto finish;
f170852a
LP
894
895 log_parse_environment();
896
897 if (parse_argv(argc, argv) < 0)
898 goto finish;
899
fa0f4d8a 900 if (arg_action == ACTION_HELP) {
f170852a
LP
901 retval = help();
902 goto finish;
fa0f4d8a 903 } else if (arg_action == ACTION_DUMP_CONFIGURATION_ITEMS) {
e537352b
LP
904 unit_dump_config_items(stdout);
905 retval = 0;
906 goto finish;
fa0f4d8a 907 } else if (arg_action == ACTION_DONE) {
4288f619
LP
908 retval = 0;
909 goto finish;
f170852a
LP
910 }
911
fa0f4d8a 912 assert_se(arg_action == ACTION_RUN || arg_action == ACTION_TEST);
f170852a 913
a16e1123
LP
914 /* Remember open file descriptors for later deserialization */
915 if (serialization) {
916 if ((r = fdset_new_fill(&fds)) < 0) {
917 log_error("Failed to allocate fd set: %s", strerror(-r));
918 goto finish;
919 }
920
921 assert_se(fdset_remove(fds, fileno(serialization)) >= 0);
922 } else
923 close_all_fds(NULL, 0);
924
09082a94 925 /* Set up PATH unless it is already set */
e537352b
LP
926 setenv("PATH",
927 "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
fa0f4d8a 928 arg_running_as == MANAGER_SYSTEM);
09082a94 929
f170852a
LP
930 /* Move out of the way, so that we won't block unmounts */
931 assert_se(chdir("/") == 0);
932
fa0f4d8a 933 if (arg_running_as == MANAGER_SYSTEM) {
80876c20
LP
934 /* Become a session leader if we aren't one yet. */
935 setsid();
4ade7963 936
80876c20
LP
937 /* Disable the umask logic */
938 umask(0);
939 }
940
843d2643
LP
941 /* Make sure D-Bus doesn't fiddle with the SIGPIPE handlers */
942 dbus_connection_set_change_sigpipe(FALSE);
943
2146621b
LP
944 /* Reset the console, but only if this is really init and we
945 * are freshly booted */
fa0f4d8a 946 if (arg_running_as == MANAGER_SYSTEM && arg_action == ACTION_RUN) {
2146621b 947 console_setup(getpid() == 1 && !serialization);
843d2643
LP
948 make_null_stdio();
949 }
4ade7963 950
18149b9f 951 /* Open the logging devices, if possible and necessary */
843d2643 952 log_open();
4ade7963 953
5373d602
LP
954 /* Make sure we leave a core dump without panicing the
955 * kernel. */
4fc935ca
LP
956 if (getpid() == 1)
957 install_crash_handler();
97c4f35c 958
54165a39 959 log_info(PACKAGE_STRING " running in %s mode.", manager_running_as_to_string(arg_running_as));
a5dab5ce 960
ad780f19
LP
961 if (arg_running_as == MANAGER_SYSTEM) {
962
963 /* Disable nscd, to avoid deadlocks when systemd uses
964 * NSS and the nscd socket is maintained by us. */
e054f833
LP
965 /* if (nss_disable_nscd) { */
966 /* log_debug("Disabling nscd"); */
967 /* nss_disable_nscd(); */
968 /* } else */
969 /* log_debug("Hmm, can't disable nscd."); */
ad780f19
LP
970
971 if (!serialization) {
972 if (arg_show_status)
973 status_welcome();
974 modprobe_setup(arg_nomodules);
975 kmod_setup();
976 hostname_setup();
977 loopback_setup();
978 }
af5bc85d 979 }
302e8c4c 980
9e58ff9c 981 if ((r = manager_new(arg_running_as, &m)) < 0) {
8e274523 982 log_error("Failed to allocate manager object: %s", strerror(-r));
60918275
LP
983 goto finish;
984 }
985
9e58ff9c
LP
986 m->confirm_spawn = arg_confirm_spawn;
987 m->show_status = arg_show_status;
988
a16e1123 989 if ((r = manager_startup(m, serialization, fds)) < 0)
6e2ef85b 990 log_error("Failed to fully start up daemon: %s", strerror(-r));
a16e1123
LP
991
992 if (fds) {
993 /* This will close all file descriptors that were opened, but
994 * not claimed by any unit. */
995
996 fdset_free(fds);
997 fds = NULL;
f50e0a01
LP
998 }
999
a16e1123
LP
1000 if (serialization) {
1001 fclose(serialization);
1002 serialization = NULL;
1003 } else {
398ef8ba
LP
1004 DBusError error;
1005
1006 dbus_error_init(&error);
1007
fa0f4d8a 1008 log_debug("Activating default unit: %s", arg_default_unit);
a16e1123 1009
398ef8ba
LP
1010 if ((r = manager_load_unit(m, arg_default_unit, NULL, &error, &target)) < 0) {
1011 log_error("Failed to load default target: %s", bus_error(&error, r));
1012 dbus_error_free(&error);
27b14a22 1013
a16e1123 1014 log_info("Trying to load rescue target...");
398ef8ba
LP
1015 if ((r = manager_load_unit(m, SPECIAL_RESCUE_TARGET, NULL, &error, &target)) < 0) {
1016 log_error("Failed to load rescue target: %s", bus_error(&error, r));
1017 dbus_error_free(&error);
a16e1123
LP
1018 goto finish;
1019 }
1020 }
37d88da7 1021
fa0f4d8a 1022 if (arg_action == ACTION_TEST) {
40d50879 1023 printf("-> By units:\n");
a16e1123
LP
1024 manager_dump_units(m, stdout, "\t");
1025 }
1026
0ff4cdd9 1027 if ((r = manager_add_job(m, JOB_START, target, JOB_REPLACE, false, &error, NULL)) < 0) {
398ef8ba
LP
1028 log_error("Failed to start default target: %s", bus_error(&error, r));
1029 dbus_error_free(&error);
37d88da7
LP
1030 goto finish;
1031 }
60918275 1032
0ff4cdd9
LP
1033 if (arg_console && arg_running_as == MANAGER_SYSTEM) {
1034 char *name;
1035
1036 if (asprintf(&name, "getty@%s.service", arg_console) < 0)
1037 log_error("Out of memory while generating console getty service name.");
1038 else {
1039 if ((r = manager_add_job_by_name(m, JOB_START, name, JOB_FAIL, false, &error, NULL)) < 0) {
1040 log_error("Failed to start console getty target: %s", bus_error(&error, r));
1041 dbus_error_free(&error);
1042 }
1043
1044 free(name);
1045 }
1046 }
1047
fa0f4d8a 1048 if (arg_action == ACTION_TEST) {
40d50879 1049 printf("-> By jobs:\n");
a16e1123
LP
1050 manager_dump_jobs(m, stdout, "\t");
1051 retval = 0;
1052 goto finish;
1053 }
e965d56d 1054 }
d46de8a1 1055
a16e1123
LP
1056 for (;;) {
1057 if ((r = manager_loop(m)) < 0) {
1058 log_error("Failed to run mainloop: %s", strerror(-r));
1059 goto finish;
1060 }
11dd41ce 1061
a16e1123 1062 switch (m->exit_code) {
e965d56d 1063
a16e1123
LP
1064 case MANAGER_EXIT:
1065 retval = 0;
1066 log_debug("Exit.");
1067 goto finish;
e965d56d 1068
a16e1123 1069 case MANAGER_RELOAD:
e015090f 1070 log_info("Reloading.");
a16e1123
LP
1071 if ((r = manager_reload(m)) < 0)
1072 log_error("Failed to reload: %s", strerror(-r));
1073 break;
cea8e32e 1074
a16e1123 1075 case MANAGER_REEXECUTE:
a16e1123
LP
1076 if (prepare_reexecute(m, &serialization, &fds) < 0)
1077 goto finish;
60918275 1078
a16e1123 1079 reexecute = true;
e015090f 1080 log_notice("Reexecuting.");
a16e1123
LP
1081 goto finish;
1082
1083 default:
1084 assert_not_reached("Unknown exit code.");
1085 }
1086 }
f170852a 1087
60918275
LP
1088finish:
1089 if (m)
1090 manager_free(m);
1091
fa0f4d8a 1092 free(arg_default_unit);
0ff4cdd9 1093 free(arg_console);
b9cd2ec1 1094
ea430986
LP
1095 dbus_shutdown();
1096
a16e1123 1097 if (reexecute) {
edb9aaa8 1098 const char *args[14];
a16e1123
LP
1099 unsigned i = 0;
1100 char sfd[16];
1101
1102 assert(serialization);
1103 assert(fds);
1104
1105 args[i++] = SYSTEMD_BINARY_PATH;
1106
1107 args[i++] = "--log-level";
1108 args[i++] = log_level_to_string(log_get_max_level());
1109
1110 args[i++] = "--log-target";
1111 args[i++] = log_target_to_string(log_get_target());
1112
edb9aaa8
LP
1113 if (arg_running_as == MANAGER_SYSTEM)
1114 args[i++] = "--system";
1115 else
1116 args[i++] = "--session";
1117
1118 if (arg_dump_core)
1119 args[i++] = "--dump-core";
1120
1121 if (arg_crash_shell)
1122 args[i++] = "--crash-shell";
1123
1124 if (arg_confirm_spawn)
1125 args[i++] = "--confirm-spawn";
1126
1127 if (arg_show_status)
1128 args[i++] = "--show-status";
a16e1123
LP
1129
1130 snprintf(sfd, sizeof(sfd), "%i", fileno(serialization));
1131 char_array_0(sfd);
1132
1133 args[i++] = "--deserialize";
1134 args[i++] = sfd;
1135
a16e1123
LP
1136 args[i++] = NULL;
1137
1138 assert(i <= ELEMENTSOF(args));
1139
1140 execv(args[0], (char* const*) args);
1141
1142 log_error("Failed to reexecute: %m");
1143 }
1144
1145 if (serialization)
1146 fclose(serialization);
1147
1148 if (fds)
1149 fdset_free(fds);
1150
c3b3c274
LP
1151 if (getpid() == 1)
1152 freeze();
1153
56cf987f
DW
1154 label_finish();
1155
60918275
LP
1156 return retval;
1157}