main.c 28.5 KB
Newer Older
Lennart Poettering's avatar
Lennart Poettering committed
1
2
/*-*- Mode: C; c-basic-offset: 8 -*-*/

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/***
  This file is part of systemd.

  Copyright 2010 Lennart Poettering

  systemd is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  systemd is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/

22
23
#include <dbus/dbus.h>

Lennart Poettering's avatar
Lennart Poettering committed
24
25
26
#include <stdio.h>
#include <errno.h>
#include <string.h>
27
#include <unistd.h>
28
29
#include <sys/types.h>
#include <sys/stat.h>
30
#include <getopt.h>
31
#include <signal.h>
32
#include <sys/wait.h>
Lennart Poettering's avatar
Lennart Poettering committed
33
#include <fcntl.h>
Lennart Poettering's avatar
Lennart Poettering committed
34
35

#include "manager.h"
36
#include "log.h"
37
#include "mount-setup.h"
38
#include "hostname-setup.h"
39
#include "loopback-setup.h"
40
#include "kmod-setup.h"
41
#include "load-fragment.h"
42
#include "fdset.h"
43
#include "special.h"
Lennart Poettering's avatar
Lennart Poettering committed
44

45
46
static enum {
        ACTION_RUN,
Lennart Poettering's avatar
Lennart Poettering committed
47
        ACTION_HELP,
48
        ACTION_TEST,
49
50
        ACTION_DUMP_CONFIGURATION_ITEMS,
        ACTION_DONE
51
52
53
} action = ACTION_RUN;

static char *default_unit = NULL;
54
static ManagerRunningAs running_as = _MANAGER_RUNNING_AS_INVALID;
55

56
static bool dump_core = true;
57
58
static bool crash_shell = false;
static int crash_chvt = -1;
Lennart Poettering's avatar
Lennart Poettering committed
59
static bool confirm_spawn = false;
60
static FILE* serialization = NULL;
Lennart Poettering's avatar
Lennart Poettering committed
61

62
_noreturn_ static void freeze(void) {
63
64
65
66
        for (;;)
                pause();
}

67
68
69
static void nop_handler(int sig) {
}

70
_noreturn_ static void crash(int sig) {
71
72
73
74

        if (!dump_core)
                log_error("Caught <%s>, not dumping core.", strsignal(sig));
        else {
75
                struct sigaction sa;
76
77
                pid_t pid;

78
79
80
81
82
83
                /* We want to wait for the core process, hence let's enable SIGCHLD */
                zero(sa);
                sa.sa_handler = nop_handler;
                sa.sa_flags = SA_NOCLDSTOP|SA_RESTART;
                assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);

84
                if ((pid = fork()) < 0)
85
                        log_error("Caught <%s>, cannot fork for core dump: %s", strsignal(sig), strerror(errno));
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108

                else if (pid == 0) {
                        struct rlimit rl;

                        /* Enable default signal handler for core dump */
                        zero(sa);
                        sa.sa_handler = SIG_DFL;
                        assert_se(sigaction(sig, &sa, NULL) == 0);

                        /* Don't limit the core dump size */
                        zero(rl);
                        rl.rlim_cur = RLIM_INFINITY;
                        rl.rlim_max = RLIM_INFINITY;
                        setrlimit(RLIMIT_CORE, &rl);

                        /* Just to be sure... */
                        assert_se(chdir("/") == 0);

                        /* Raise the signal again */
                        raise(sig);

                        assert_not_reached("We shouldn't be here...");
                        _exit(1);
109
110
111
112
113
114
115
116
117
118
119

                } else {
                        int status, r;

                        /* Order things nicely. */
                        if ((r = waitpid(pid, &status, 0)) < 0)
                                log_error("Caught <%s>, waitpid() failed: %s", strsignal(sig), strerror(errno));
                        else if (!WCOREDUMP(status))
                                log_error("Caught <%s>, core dump failed.", strsignal(sig));
                        else
                                log_error("Caught <%s>, dumped core as pid %llu.", strsignal(sig), (unsigned long long) pid);
120
121
122
                }
        }

123
124
125
        if (crash_chvt)
                chvt(crash_chvt);

126
        if (crash_shell) {
127
128
                struct sigaction sa;
                pid_t pid;
129

130
131
132
                log_info("Executing crash shell in 10s...");
                sleep(10);

133
134
135
136
137
                /* Let the kernel reap children for us */
                zero(sa);
                sa.sa_handler = SIG_IGN;
                sa.sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART;
                assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
138

139
140
141
                if ((pid = fork()) < 0)
                        log_error("Failed to fork off crash shell: %s", strerror(errno));
                else if (pid == 0) {
142
                        int fd, r;
143

144
                        if ((fd = acquire_terminal("/dev/console", false, true, true)) < 0)
145
                                log_error("Failed to acquire terminal: %s", strerror(-fd));
146
                        else if ((r = make_stdio(fd)) < 0)
147
                                log_error("Failed to duplicate terminal fd: %s", strerror(-r));
148

149
150
151
152
153
                        execl("/bin/sh", "/bin/sh", NULL);

                        log_error("execl() failed: %s", strerror(errno));
                        _exit(1);
                }
154

155
                log_info("Successfully spawned crash shall as pid %llu.", (unsigned long long) pid);
156
157
158
        }

        log_info("Freezing execution.");
159
160
161
162
163
164
165
166
167
168
169
        freeze();
}

static void install_crash_handler(void) {
        struct sigaction sa;

        zero(sa);

        sa.sa_handler = crash;
        sa.sa_flags = SA_NODEFER;

Lennart Poettering's avatar
Lennart Poettering committed
170
        sigaction_many(&sa, SIGNALS_CRASH_HANDLER, -1);
171
}
172

173
174
static int make_null_stdio(void) {
        int null_fd, r;
Lennart Poettering's avatar
Lennart Poettering committed
175

176
        if ((null_fd = open("/dev/null", O_RDWR|O_NOCTTY)) < 0) {
Lennart Poettering's avatar
Lennart Poettering committed
177
                log_error("Failed to open /dev/null: %m");
178
                return -errno;
Lennart Poettering's avatar
Lennart Poettering committed
179
180
        }

181
182
        if ((r = make_stdio(null_fd)) < 0)
                log_warning("Failed to dup2() device: %s", strerror(-r));
Lennart Poettering's avatar
Lennart Poettering committed
183

184
185
        return r;
}
Lennart Poettering's avatar
Lennart Poettering committed
186

187
188
static int console_setup(bool do_reset) {
        int tty_fd, r;
Lennart Poettering's avatar
Lennart Poettering committed
189

190
191
        /* If we are init, we connect stdin/stdout/stderr to /dev/null
         * and make sure we don't have a controlling tty. */
Lennart Poettering's avatar
Lennart Poettering committed
192

193
194
195
196
        release_terminal();

        if (!do_reset)
                return 0;
Lennart Poettering's avatar
Lennart Poettering committed
197

198
199
200
201
        if ((tty_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0) {
                log_error("Failed to open /dev/console: %s", strerror(-tty_fd));
                return -tty_fd;
        }
Lennart Poettering's avatar
Lennart Poettering committed
202

203
204
205
206
        if ((r = reset_terminal(tty_fd)) < 0)
                log_error("Failed to reset /dev/console: %s", strerror(-r));

        close_nointr_nofail(tty_fd);
Lennart Poettering's avatar
Lennart Poettering committed
207
208
209
        return r;
}

210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
static int set_default_unit(const char *u) {
        char *c;

        assert(u);

        if (!(c = strdup(u)))
                return -ENOMEM;

        free(default_unit);
        default_unit = c;
        return 0;
}

static int parse_proc_cmdline_word(const char *word) {

        static const char * const rlmap[] = {
226
227
228
229
230
                "single", SPECIAL_RESCUE_TARGET,
                "-s",     SPECIAL_RESCUE_TARGET,
                "s",      SPECIAL_RESCUE_TARGET,
                "S",      SPECIAL_RESCUE_TARGET,
                "1",      SPECIAL_RESCUE_TARGET,
231
232
233
234
235
236
                "2",      SPECIAL_RUNLEVEL2_TARGET,
                "3",      SPECIAL_RUNLEVEL3_TARGET,
                "4",      SPECIAL_RUNLEVEL4_TARGET,
                "5",      SPECIAL_RUNLEVEL5_TARGET
        };

237
238
        if (startswith(word, "systemd.unit="))
                return set_default_unit(word + 13);
239
240
241
242
243
244
245
246
247
248
249

        else if (startswith(word, "systemd.log_target=")) {

                if (log_set_target_from_string(word + 19) < 0)
                        log_warning("Failed to parse log target %s. Ignoring.", word + 19);

        } else if (startswith(word, "systemd.log_level=")) {

                if (log_set_max_level_from_string(word + 18) < 0)
                        log_warning("Failed to parse log level %s. Ignoring.", word + 18);

250
251
252
253
254
255
256
257
258
259
        } else if (startswith(word, "systemd.log_color=")) {

                if (log_show_color_from_string(word + 18) < 0)
                        log_warning("Failed to parse log color setting %s. Ignoring.", word + 18);

        } else if (startswith(word, "systemd.log_location=")) {

                if (log_show_location_from_string(word + 21) < 0)
                        log_warning("Failed to parse log location setting %s. Ignoring.", word + 21);

260
261
262
263
        } else if (startswith(word, "systemd.dump_core=")) {
                int r;

                if ((r = parse_boolean(word + 18)) < 0)
264
                        log_warning("Failed to parse dump core switch %s, Ignoring.", word + 18);
265
266
267
268
269
270
271
                else
                        dump_core = r;

        } else if (startswith(word, "systemd.crash_shell=")) {
                int r;

                if ((r = parse_boolean(word + 20)) < 0)
272
                        log_warning("Failed to parse crash shell switch %s, Ignoring.", word + 20);
273
274
275
                else
                        crash_shell = r;

276
277
278
279
280
281
282
283
284

        } else if (startswith(word, "systemd.confirm_spawn=")) {
                int r;

                if ((r = parse_boolean(word + 22)) < 0)
                        log_warning("Failed to parse confirm spawn switch %s, Ignoring.", word + 22);
                else
                        confirm_spawn = r;

285
286
287
288
289
290
291
292
        } else if (startswith(word, "systemd.crash_chvt=")) {
                int k;

                if (safe_atoi(word + 19, &k) < 0)
                        log_warning("Failed to parse crash chvt switch %s, Ignoring.", word + 19);
                else
                        crash_chvt = k;

293
294
295
296
        } else if (startswith(word, "systemd.")) {

                log_warning("Unknown kernel switch %s. Ignoring.", word);

297
298
299
300
301
302
303
304
305
306
307
                log_info("Supported kernel switches:\n"
                         "systemd.unit=UNIT                        Default unit to start\n"
                         "systemd.log_target=console|kmsg|syslog|  Log target\n"
                         "                   syslog-org-kmsg|null\n"
                         "systemd.log_level=LEVEL                  Log level\n"
                         "systemd.log_color=0|1                    Highlight important log messages\n"
                         "systemd.log_location=0|1                 Include code location in log messages\n"
                         "systemd.dump_core=0|1                    Dump core on crash\n"
                         "systemd.crash_shell=0|1                  On crash run shell\n"
                         "systemd.crash_chvt=N                     Change to VT #N on crash\n"
                         "systemd.confirm_spawn=0|1                Confirm every process spawn");
308

309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
        } else {
                unsigned i;

                /* SysV compatibility */
                for (i = 0; i < ELEMENTSOF(rlmap); i += 2)
                        if (streq(word, rlmap[i]))
                                return set_default_unit(rlmap[i+1]);
        }

        return 0;
}

static int parse_proc_cmdline(void) {
        char *line;
        int r;
        char *w;
        size_t l;
        char *state;

        if ((r = read_one_line_file("/proc/cmdline", &line)) < 0) {
                log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(errno));
                return 0;
        }

        FOREACH_WORD_QUOTED(w, l, line, state) {
                char *word;

                if (!(word = strndup(w, l))) {
                        r = -ENOMEM;
                        goto finish;
                }

                r = parse_proc_cmdline_word(word);
                free(word);

                if (r < 0)
                        goto finish;
        }

        r = 0;

finish:
        free(line);
        return r;
}

static int parse_argv(int argc, char *argv[]) {

        enum {
                ARG_LOG_LEVEL = 0x100,
                ARG_LOG_TARGET,
360
361
                ARG_LOG_COLOR,
                ARG_LOG_LOCATION,
362
                ARG_UNIT,
Lennart Poettering's avatar
Lennart Poettering committed
363
                ARG_RUNNING_AS,
364
                ARG_TEST,
Lennart Poettering's avatar
Lennart Poettering committed
365
                ARG_DUMP_CONFIGURATION_ITEMS,
366
                ARG_CONFIRM_SPAWN,
367
368
                ARG_DESERIALIZE,
                ARG_INTROSPECT
369
370
371
        };

        static const struct option options[] = {
372
373
                { "log-level",                required_argument, NULL, ARG_LOG_LEVEL                },
                { "log-target",               required_argument, NULL, ARG_LOG_TARGET               },
374
375
                { "log-color",                optional_argument, NULL, ARG_LOG_COLOR                },
                { "log-location",             optional_argument, NULL, ARG_LOG_LOCATION             },
376
                { "unit",                     required_argument, NULL, ARG_UNIT                     },
377
378
379
380
381
382
                { "running-as",               required_argument, NULL, ARG_RUNNING_AS               },
                { "test",                     no_argument,       NULL, ARG_TEST                     },
                { "help",                     no_argument,       NULL, 'h'                          },
                { "dump-configuration-items", no_argument,       NULL, ARG_DUMP_CONFIGURATION_ITEMS },
                { "confirm-spawn",            no_argument,       NULL, ARG_CONFIRM_SPAWN            },
                { "deserialize",              required_argument, NULL, ARG_DESERIALIZE              },
383
                { "introspect",               optional_argument, NULL, ARG_INTROSPECT               },
384
                { NULL,                       0,                 NULL, 0                            }
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
        };

        int c, r;

        assert(argc >= 1);
        assert(argv);

        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)

                switch (c) {

                case ARG_LOG_LEVEL:
                        if ((r = log_set_max_level_from_string(optarg)) < 0) {
                                log_error("Failed to parse log level %s.", optarg);
                                return r;
                        }

                        break;

                case ARG_LOG_TARGET:

                        if ((r = log_set_target_from_string(optarg)) < 0) {
                                log_error("Failed to parse log target %s.", optarg);
                                return r;
                        }

                        break;

413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
                case ARG_LOG_COLOR:

                        if ((r = log_show_color_from_string(optarg)) < 0) {
                                log_error("Failed to parse log color setting %s.", optarg);
                                return r;
                        }

                        break;

                case ARG_LOG_LOCATION:

                        if ((r = log_show_location_from_string(optarg)) < 0) {
                                log_error("Failed to parse log location setting %s.", optarg);
                                return r;
                        }

                        break;

431
                case ARG_UNIT:
432
433
434
435
436
437
438
439

                        if ((r = set_default_unit(optarg)) < 0) {
                                log_error("Failed to set default unit %s: %s", optarg, strerror(-r));
                                return r;
                        }

                        break;

440
441
442
443
444
445
446
447
448
449
450
451
                case ARG_RUNNING_AS: {
                        ManagerRunningAs as;

                        if ((as = manager_running_as_from_string(optarg)) < 0) {
                                log_error("Failed to parse running as value %s", optarg);
                                return -EINVAL;
                        }

                        running_as = as;
                        break;
                }

Lennart Poettering's avatar
Lennart Poettering committed
452
453
454
455
                case ARG_TEST:
                        action = ACTION_TEST;
                        break;

456
457
458
459
                case ARG_DUMP_CONFIGURATION_ITEMS:
                        action = ACTION_DUMP_CONFIGURATION_ITEMS;
                        break;

Lennart Poettering's avatar
Lennart Poettering committed
460
461
462
463
                case ARG_CONFIRM_SPAWN:
                        confirm_spawn = true;
                        break;

464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
                case ARG_DESERIALIZE: {
                        int fd;
                        FILE *f;

                        if ((r = safe_atoi(optarg, &fd)) < 0 || fd < 0) {
                                log_error("Failed to parse deserialize option %s.", optarg);
                                return r;
                        }

                        if (!(f = fdopen(fd, "r"))) {
                                log_error("Failed to open serialization fd: %m");
                                return r;
                        }

                        if (serialization)
                                fclose(serialization);

                        serialization = f;

                        break;
                }

486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
                case ARG_INTROSPECT: {
                        const char * const * i = NULL;

                        for (i = bus_interface_table; *i; i += 2)
                                if (!optarg || streq(i[0], optarg)) {
                                        fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
                                              "<node>\n", stdout);
                                        fputs(i[1], stdout);
                                        fputs("</node>\n", stdout);

                                        if (optarg)
                                                break;
                                }

                        if (!i[0] && optarg)
                                log_error("Unknown interface %s.", optarg);

                        action = ACTION_DONE;
                        break;
                }

507
508
509
510
511
512
513
514
515
516
517
518
                case 'h':
                        action = ACTION_HELP;
                        break;

                case '?':
                        return -EINVAL;

                default:
                        log_error("Unknown option code %c", c);
                        return -EINVAL;
                }

519
520
521
522
523
524
525
526
527
        /* PID 1 will get the kernel arguments as parameters, which we
         * ignore and unconditionally read from
         * /proc/cmdline. However, we need to ignore those arguments
         * here. */
        if (running_as != MANAGER_INIT && optind < argc) {
                log_error("Excess arguments.");
                return -EINVAL;
        }

528
529
530
531
532
533
        return 0;
}

static int help(void) {

        printf("%s [options]\n\n"
534
               "Starts up and maintains the system or a session.\n\n"
535
               "  -h --help                      Show this help\n"
536
               "     --unit=UNIT                 Set default unit\n"
537
538
               "     --running-as=AS             Set running as (init, system, session)\n"
               "     --test                      Determine startup sequence, dump it and exit\n"
Lennart Poettering's avatar
Lennart Poettering committed
539
               "     --dump-configuration-items  Dump understood unit configuration items\n"
540
               "     --confirm-spawn             Ask for confirmation when spawning processes\n"
541
542
543
544
545
               "     --introspect[=INTERFACE]    Extract D-Bus interface data\n"
               "     --log-level=LEVEL           Set log level\n"
               "     --log-target=TARGET         Set log target (console, syslog, kmsg, syslog-or-kmsg, null)\n"
               "     --log-color[=0|1]           Highlight import log messages\n"
               "     --log-location[=0|1]        Include code location in log messages\n",
546
               program_invocation_short_name);
547
548
549
550

        return 0;
}

551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds) {
        FILE *f = NULL;
        FDSet *fds = NULL;
        int r;

        assert(m);
        assert(_f);
        assert(_fds);

        if ((r = manager_open_serialization(&f)) < 0) {
                log_error("Failed to create serialization faile: %s", strerror(-r));
                goto fail;
        }

        if (!(fds = fdset_new())) {
                r = -ENOMEM;
                log_error("Failed to allocate fd set: %s", strerror(-r));
                goto fail;
        }

        if ((r = manager_serialize(m, f, fds)) < 0) {
                log_error("Failed to serialize state: %s", strerror(-r));
                goto fail;
        }

        if (fseeko(f, 0, SEEK_SET) < 0) {
                log_error("Failed to rewind serialization fd: %m");
                goto fail;
        }

        if ((r = fd_cloexec(fileno(f), false)) < 0) {
                log_error("Failed to disable O_CLOEXEC for serialization: %s", strerror(-r));
                goto fail;
        }

        if ((r = fdset_cloexec(fds, false)) < 0) {
                log_error("Failed to disable O_CLOEXEC for serialization fds: %s", strerror(-r));
                goto fail;
        }

        *_f = f;
        *_fds = fds;

        return 0;

fail:
        fdset_free(fds);

        if (f)
                fclose(f);

        return r;
}

Lennart Poettering's avatar
Lennart Poettering committed
605
606
int main(int argc, char *argv[]) {
        Manager *m = NULL;
Lennart Poettering's avatar
Lennart Poettering committed
607
        Unit *target = NULL;
Lennart Poettering's avatar
Lennart Poettering committed
608
609
        Job *job = NULL;
        int r, retval = 1;
610
611
        FDSet *fds = NULL;
        bool reexecute = false;
612

613
614
615
616
617
618
619
620
621
622
        if (getpid() != 1 && strstr(program_invocation_short_name, "init")) {
                /* This is compatbility support for SysV, where
                 * calling init as a user is identical to telinit. */

                errno = -ENOENT;
                execv(SYSTEMCTL_BINARY_PATH, argv);
                log_error("Failed to exec " SYSTEMCTL_BINARY_PATH ": %m");
                return 1;
        }

623
624
625
626
        log_show_color(true);
        log_show_location(false);
        log_set_max_level(LOG_DEBUG);

627
        if (getpid() == 1) {
628
                running_as = MANAGER_INIT;
629
                log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
630
        } else {
631
                running_as = MANAGER_SESSION;
632
633
                log_set_target(LOG_TARGET_CONSOLE);
        }
634

635
636
        if (set_default_unit(SPECIAL_DEFAULT_TARGET) < 0)
                goto finish;
Lennart Poettering's avatar
Lennart Poettering committed
637

638
639
        /* Mount /proc, /sys and friends, so that /proc/cmdline and
         * /proc/$PID/fd is available. */
640
641
642
        if (geteuid() == 0)
                if (mount_setup() < 0)
                        goto finish;
643
644
645
646

        /* Reset all signal handlers. */
        assert_se(reset_all_signal_handlers() == 0);

647
        /* If we are init, we can block sigkill. Yay. */
648
        ignore_signals(SIGNALS_IGNORE, -1);
649

650
651
652
        if (running_as != MANAGER_SESSION)
                if (parse_proc_cmdline() < 0)
                        goto finish;
653
654
655
656
657
658
659
660
661

        log_parse_environment();

        if (parse_argv(argc, argv) < 0)
                goto finish;

        if (action == ACTION_HELP) {
                retval = help();
                goto finish;
662
663
664
665
        } else if (action == ACTION_DUMP_CONFIGURATION_ITEMS) {
                unit_dump_config_items(stdout);
                retval = 0;
                goto finish;
666
667
668
        } else if (action == ACTION_DONE) {
                retval = 0;
                goto finish;
669
670
        }

Lennart Poettering's avatar
Lennart Poettering committed
671
        assert_se(action == ACTION_RUN || action == ACTION_TEST);
672

673
674
675
676
677
678
679
680
681
682
683
        /* Remember open file descriptors for later deserialization */
        if (serialization) {
                if ((r = fdset_new_fill(&fds)) < 0) {
                        log_error("Failed to allocate fd set: %s", strerror(-r));
                        goto finish;
                }

                assert_se(fdset_remove(fds, fileno(serialization)) >= 0);
        } else
                close_all_fds(NULL, 0);

684
        /* Set up PATH unless it is already set */
685
686
687
        setenv("PATH",
               "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
               running_as == MANAGER_INIT);
688

689
690
691
        /* Move out of the way, so that we won't block unmounts */
        assert_se(chdir("/")  == 0);

Lennart Poettering's avatar
Lennart Poettering committed
692
693
694
        if (running_as != MANAGER_SESSION) {
                /* Become a session leader if we aren't one yet. */
                setsid();
695

Lennart Poettering's avatar
Lennart Poettering committed
696
697
698
699
                /* Disable the umask logic */
                umask(0);
        }

700
701
702
        /* Make sure D-Bus doesn't fiddle with the SIGPIPE handlers */
        dbus_connection_set_change_sigpipe(FALSE);

703
704
        /* Reset the console, but only if this is really init and we
         * are freshly booted */
705
        if (running_as != MANAGER_SESSION && action == ACTION_RUN) {
706
                console_setup(getpid() == 1 && !serialization);
707
708
                make_null_stdio();
        }
709

710
        /* Open the logging devices, if possible and necessary */
711
        log_open();
712

713
714
        /* Make sure we leave a core dump without panicing the
         * kernel. */
715
716
        if (getpid() == 1)
                install_crash_handler();
717

718
719
        log_debug("systemd running in %s mode.", manager_running_as_to_string(running_as));

720
        if (running_as == MANAGER_INIT) {
721
                kmod_setup();
722
                hostname_setup();
723
724
                loopback_setup();
        }
725

Lennart Poettering's avatar
Lennart Poettering committed
726
        if ((r = manager_new(running_as, confirm_spawn, &m)) < 0) {
727
                log_error("Failed to allocate manager object: %s", strerror(-r));
Lennart Poettering's avatar
Lennart Poettering committed
728
729
730
                goto finish;
        }

731
        if ((r = manager_startup(m, serialization, fds)) < 0)
732
                log_error("Failed to fully start up daemon: %s", strerror(-r));
733
734
735
736
737
738
739

        if (fds) {
                /* This will close all file descriptors that were opened, but
                 * not claimed by any unit. */

                fdset_free(fds);
                fds = NULL;
Lennart Poettering's avatar
Lennart Poettering committed
740
741
        }

742
743
744
745
746
747
748
749
        if (serialization) {
                fclose(serialization);
                serialization = NULL;
        } else {
                log_debug("Activating default unit: %s", default_unit);

                if ((r = manager_load_unit(m, default_unit, NULL, &target)) < 0) {
                        log_error("Failed to load default target: %s", strerror(-r));
750

751
752
753
754
755
756
                        log_info("Trying to load rescue target...");
                        if ((r = manager_load_unit(m, SPECIAL_RESCUE_TARGET, NULL, &target)) < 0) {
                                log_error("Failed to load rescue target: %s", strerror(-r));
                                goto finish;
                        }
                }
757

758
                if (action == ACTION_TEST) {
759
                        printf("-> By units:\n");
760
761
762
763
764
                        manager_dump_units(m, stdout, "\t");
                }

                if ((r = manager_add_job(m, JOB_START, target, JOB_REPLACE, false, &job)) < 0) {
                        log_error("Failed to start default target: %s", strerror(-r));
765
766
                        goto finish;
                }
Lennart Poettering's avatar
Lennart Poettering committed
767

768
                if (action == ACTION_TEST) {
769
                        printf("-> By jobs:\n");
770
771
772
773
                        manager_dump_jobs(m, stdout, "\t");
                        retval = 0;
                        goto finish;
                }
Lennart Poettering's avatar
Lennart Poettering committed
774
        }
775

776
777
778
779
780
        for (;;) {
                if ((r = manager_loop(m)) < 0) {
                        log_error("Failed to run mainloop: %s", strerror(-r));
                        goto finish;
                }
781

782
                switch (m->exit_code) {
Lennart Poettering's avatar
Lennart Poettering committed
783

784
785
786
787
                case MANAGER_EXIT:
                        retval = 0;
                        log_debug("Exit.");
                        goto finish;
Lennart Poettering's avatar
Lennart Poettering committed
788

789
790
791
792
                case MANAGER_RELOAD:
                        if ((r = manager_reload(m)) < 0)
                                log_error("Failed to reload: %s", strerror(-r));
                        break;
Lennart Poettering's avatar
Lennart Poettering committed
793

794
795
796
                case MANAGER_REEXECUTE:
                        if (prepare_reexecute(m, &serialization, &fds) < 0)
                                goto finish;
Lennart Poettering's avatar
Lennart Poettering committed
797

798
799
800
801
802
803
804
805
                        reexecute = true;
                        log_debug("Reexecuting.");
                        goto finish;

                default:
                        assert_not_reached("Unknown exit code.");
                }
        }
806

Lennart Poettering's avatar
Lennart Poettering committed
807
808
809
810
finish:
        if (m)
                manager_free(m);

811
        free(default_unit);
Lennart Poettering's avatar
Lennart Poettering committed
812

813
814
        dbus_shutdown();

815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
        if (reexecute) {
                const char *args[11];
                unsigned i = 0;
                char sfd[16];

                assert(serialization);
                assert(fds);

                args[i++] = SYSTEMD_BINARY_PATH;

                args[i++] = "--log-level";
                args[i++] = log_level_to_string(log_get_max_level());

                args[i++] = "--log-target";
                args[i++] = log_target_to_string(log_get_target());

                args[i++] = "--running-as";
                args[i++] = manager_running_as_to_string(running_as);

                snprintf(sfd, sizeof(sfd), "%i", fileno(serialization));
                char_array_0(sfd);

                args[i++] = "--deserialize";
                args[i++] = sfd;

                if (confirm_spawn)
                        args[i++] = "--confirm-spawn";

                args[i++] = NULL;

                assert(i <= ELEMENTSOF(args));

                execv(args[0], (char* const*) args);

                log_error("Failed to reexecute: %m");
        }

        if (serialization)
                fclose(serialization);

        if (fds)
                fdset_free(fds);

858
859
860
        if (getpid() == 1)
                freeze();

Lennart Poettering's avatar
Lennart Poettering committed
861
862
        return retval;
}