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