Add --log-file (-l) option to specify logging to file.
[oweals/dinit.git] / src / dinit.cc
1 #include <iostream>
2 #include <fstream>
3 #include <list>
4 #include <cstring>
5 #include <csignal>
6 #include <cstddef>
7 #include <cstdlib>
8
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <sys/un.h>
12 #include <sys/socket.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <pwd.h>
16 #ifdef __linux__
17 #include <sys/prctl.h>
18 #include <sys/klog.h>
19 #include <sys/reboot.h>
20 #endif
21 #if defined(__FreeBSD__) || defined(__DragonFly__)
22 #include <sys/procctl.h>
23 #endif
24
25 #include "dinit.h"
26 #include "dasynq.h"
27 #include "service.h"
28 #include "control.h"
29 #include "dinit-log.h"
30 #include "dinit-socket.h"
31
32 /*
33  * When running as the system init process, Dinit processes the following signals:
34  *
35  * SIGTERM - roll back services and then fork/exec /sbin/halt
36  * SIGINT - roll back services and then fork/exec /sbin/reboot
37  * SIGQUIT - exec() /sbin/shutdown without rolling back services
38  *
39  * It's an open question about whether Dinit should roll back services *before*
40  * running halt/reboot, since those commands should prompt rollback of services
41  * anyway. But it seems safe to do so, and it means the user can at least stop
42  * services even if the halt/reboot commands are unavailable for some reason.
43  */
44
45 using eventloop_t = dasynq::event_loop<dasynq::null_mutex>;
46
47 eventloop_t event_loop;
48
49 static void sigint_reboot_cb(eventloop_t &eloop) noexcept;
50 static void sigquit_cb(eventloop_t &eloop) noexcept;
51 static void sigterm_cb(eventloop_t &eloop) noexcept;
52 static void close_control_socket() noexcept;
53 static void wait_for_user_input() noexcept;
54 static void read_env_file(const char *);
55
56 static void control_socket_cb(eventloop_t *loop, int fd);
57
58
59 // Variables
60
61 static dirload_service_set *services;
62
63 static bool am_system_init = false; // true if we are the system init process
64
65 static bool control_socket_open = false;
66 static bool external_log_open = false;
67 int active_control_conns = 0;
68
69 // Control socket path. We maintain a string (control_socket_str) in case we need
70 // to allocate storage, but control_socket_path is the authoritative value.
71 static const char *control_socket_path = "/dev/dinitctl";
72 static std::string control_socket_str;
73
74 static const char *env_file_path = "/etc/dinit/environment";
75
76 static const char *log_path = "/dev/log";
77 static bool log_is_syslog = true; // if false, log is a file
78
79 static const char *user_home_path = nullptr;
80
81
82 // Get user home (and set user_home_path). (The return may become invalid after
83 // changing the evironment (HOME variable) or using the getpwuid() function).
84 const char * get_user_home()
85 {
86     if (user_home_path == nullptr) {
87         user_home_path = getenv("HOME");
88         if (user_home_path == nullptr) {
89             struct passwd * pwuid_p = getpwuid(getuid());
90             if (pwuid_p != nullptr) {
91                 user_home_path = pwuid_p->pw_dir;
92             }
93         }
94     }
95     return user_home_path;
96 }
97
98
99 namespace {
100     class callback_signal_handler : public eventloop_t::signal_watcher_impl<callback_signal_handler>
101     {
102         using rearm = dasynq::rearm;
103
104         public:
105         typedef void (*cb_func_t)(eventloop_t &);
106         
107         private:
108         cb_func_t cb_func;
109         
110         public:
111         callback_signal_handler() : cb_func(nullptr) { }
112         callback_signal_handler(cb_func_t pcb_func) :  cb_func(pcb_func) { }
113         
114         void setCbFunc(cb_func_t cb_func)
115         {
116             this->cb_func = cb_func;
117         }
118         
119         rearm received(eventloop_t &eloop, int signo, siginfo_p siginfo)
120         {
121             cb_func(eloop);
122             return rearm::REARM;
123         }
124     };
125
126     class control_socket_watcher : public eventloop_t::fd_watcher_impl<control_socket_watcher>
127     {
128         using rearm = dasynq::rearm;
129
130         public:
131         rearm fd_event(eventloop_t &loop, int fd, int flags) noexcept
132         {
133             control_socket_cb(&loop, fd);
134             return rearm::REARM;
135         }
136     };
137
138     // Simple timer used to limit the amount of time waiting for the log flush to complete (at shutdown)
139     class log_flush_timer_t : public eventloop_t::timer_impl<log_flush_timer_t>
140     {
141         using rearm = dasynq::rearm;
142
143         bool expired = false;
144
145         public:
146         rearm timer_expiry(eventloop_t &, int expiry_count)
147         {
148             expired = true;
149             return rearm::DISARM;
150         }
151
152         bool has_expired()
153         {
154             return expired;
155         }
156     };
157
158     control_socket_watcher control_socket_io;
159     log_flush_timer_t log_flush_timer;
160 }
161
162 int dinit_main(int argc, char **argv)
163 {
164     using namespace std;
165     
166     am_system_init = (getpid() == 1);
167     const char * service_dir = nullptr;
168     const char * env_file = nullptr;
169     string service_dir_str; // to hold storage for above if necessary
170     bool control_socket_path_set = false;
171     bool env_file_set = false;
172
173     // list of services to start
174     list<const char *> services_to_start;
175     
176     // Arguments, if given, specify a list of services to start.
177     // If we are running as init (PID=1), the Linux kernel gives us any command line arguments it was given
178     // but didn't recognize, including "single" (usually for "boot to single user mode" aka just start the
179     // shell). We can treat them as service names. In the worst case we can't find any of the named
180     // services, and so we'll start the "boot" service by default.
181     if (argc > 1) {
182       for (int i = 1; i < argc; i++) {
183         if (argv[i][0] == '-') {
184             // An option...
185             if (strcmp(argv[i], "--env-file") == 0 || strcmp(argv[i], "-e") == 0) {
186                 if (++i < argc) {
187                     env_file_set = true;
188                     env_file = argv[i];
189                 }
190                 else {
191                     cerr << "dinit: '--env-file' (-e) requires an argument" << endl;
192                 }
193             }
194             else if (strcmp(argv[i], "--services-dir") == 0 || strcmp(argv[i], "-d") == 0) {
195                 if (++i < argc) {
196                     service_dir = argv[i];
197                 }
198                 else {
199                     cerr << "dinit: '--services-dir' (-d) requires an argument" << endl;
200                     return 1;
201                 }
202             }
203             else if (strcmp(argv[i], "--system") == 0 || strcmp(argv[i], "-s") == 0) {
204                 am_system_init = true;
205             }
206             else if (strcmp(argv[i], "--socket-path") == 0 || strcmp(argv[i], "-p") == 0) {
207                 if (++i < argc) {
208                     control_socket_path = argv[i];
209                     control_socket_path_set = true;
210                 }
211                 else {
212                     cerr << "dinit: '--socket-path' (-p) requires an argument" << endl;
213                     return 1;
214                 }
215             }
216             else if (strcmp(argv[i], "--log-file") == 0 || strcmp(argv[i], "-l") == 0) {
217                 if (++i < argc) {
218                     log_path = argv[i];
219                     log_is_syslog = false;
220                 }
221                 else {
222                     cerr << "dinit: '--log-file' (-l) requires an argument" << endl;
223                     return 1;
224                 }
225             }
226             else if (strcmp(argv[i], "--help") == 0) {
227                 cout << "dinit, an init with dependency management" << endl;
228                 cout << " --help                       display help" << endl;
229                 cout << " --env-file <file>, -e <file>" << endl;
230                 cout << "                              environment variable initialisation file" << endl;
231                 cout << " --services-dir <dir>, -d <dir>" << endl;
232                 cout << "                              set base directory for service description" << endl;
233                 cout << "                              files (-d <dir>)" << endl;
234                 cout << " --system, -s                 run as the system init process" << endl;
235                 cout << " --socket-path <path>, -p <path>" << endl;
236                 cout << "                              path to control socket" << endl;
237                 cout << " <service-name>               start service with name <service-name>" << endl;
238                 return 0;
239             }
240             else {
241                 // unrecognized
242                 if (! am_system_init) {
243                     cerr << "dinit: Unrecognized option: " << argv[i] << endl;
244                     return 1;
245                 }
246             }
247         }
248         else {
249 #ifdef __linux__
250             // LILO puts "auto" on the kernel command line for unattended boots; we'll filter it.
251             if (! am_system_init || strcmp(argv[i], "auto") != 0) {
252                 services_to_start.push_back(argv[i]);
253             }
254 #else
255             services_to_start.push_back(argv[i]);
256 #endif
257         }
258       }
259     }
260     
261     if (am_system_init) {
262         // setup STDIN, STDOUT, STDERR so that we can use them
263         int onefd = open("/dev/console", O_RDONLY, 0);
264         dup2(onefd, 0);
265         int twofd = open("/dev/console", O_RDWR, 0);
266         dup2(twofd, 1);
267         dup2(twofd, 2);
268         
269         if (onefd > 2) close(onefd);
270         if (twofd > 2) close(twofd);
271
272         if (! env_file_set) {
273             env_file = env_file_path;
274         }
275     }
276
277     /* Set up signal handlers etc */
278     /* SIG_CHILD is ignored by default: good */
279     sigset_t sigwait_set;
280     sigemptyset(&sigwait_set);
281     sigaddset(&sigwait_set, SIGCHLD);
282     sigaddset(&sigwait_set, SIGINT);
283     sigaddset(&sigwait_set, SIGTERM);
284     if (am_system_init) sigaddset(&sigwait_set, SIGQUIT);
285     sigprocmask(SIG_BLOCK, &sigwait_set, NULL);
286
287     // Terminal access control signals - we block these so that dinit can't be
288     // suspended if it writes to the terminal after some other process has claimed
289     // ownership of it.
290     signal(SIGTSTP, SIG_IGN);
291     signal(SIGTTIN, SIG_IGN);
292     signal(SIGTTOU, SIG_IGN);
293     
294     signal(SIGPIPE, SIG_IGN);
295     
296     if (! am_system_init && ! control_socket_path_set) {
297         const char * userhome = get_user_home();
298         if (userhome != nullptr) {
299             control_socket_str = userhome;
300             control_socket_str += "/.dinitctl";
301             control_socket_path = control_socket_str.c_str();
302         }
303     }
304     
305     /* service directory name */
306     if (service_dir == nullptr && ! am_system_init) {
307         const char * userhome = get_user_home();
308         if (userhome != nullptr) {
309             service_dir_str = get_user_home();
310             service_dir_str += "/dinit.d";
311             service_dir = service_dir_str.c_str();
312         }
313     }
314     
315     if (service_dir == nullptr) {
316         service_dir = "/etc/dinit.d";
317     }
318     
319     if (services_to_start.empty()) {
320         services_to_start.push_back("boot");
321     }
322
323     // Set up signal handlers
324     callback_signal_handler sigterm_watcher {sigterm_cb};
325     callback_signal_handler sigint_watcher;
326     callback_signal_handler sigquit_watcher;
327
328     if (am_system_init) {
329         sigint_watcher.setCbFunc(sigint_reboot_cb);
330         sigquit_watcher.setCbFunc(sigquit_cb);
331     }
332     else {
333         sigint_watcher.setCbFunc(sigterm_cb);
334     }
335
336     sigint_watcher.add_watch(event_loop, SIGINT);
337     sigterm_watcher.add_watch(event_loop, SIGTERM);
338     
339     if (am_system_init) {
340         // PID 1: SIGQUIT exec's shutdown
341         sigquit_watcher.add_watch(event_loop, SIGQUIT);
342         // As a user process, we instead just let SIGQUIT perform the default action.
343     }
344
345     // Try to open control socket (may fail due to readonly filesystem)
346     open_control_socket(false);
347     
348     // Only try to set up the external log now if we aren't the system init. (If we are the
349     // system init, wait until the log service starts).
350     if (! am_system_init) setup_external_log();
351
352 #ifdef __linux__
353     if (am_system_init) {
354         // Disable non-critical kernel output to console
355         klogctl(6 /* SYSLOG_ACTION_CONSOLE_OFF */, nullptr, 0);
356         // Make ctrl+alt+del combination send SIGINT to PID 1 (this process)
357         reboot(RB_DISABLE_CAD);
358     }
359
360     // Mark ourselves as a subreaper. This means that if a process we start double-forks, the
361     // orphaned child will re-parent to us rather than to PID 1 (although that could be us too).
362     prctl(PR_SET_CHILD_SUBREAPER, 1);
363 #elif defined(__FreeBSD__) || defined(__DragonFly__)
364     // Documentation (man page) for this kind of sucks. PROC_REAP_ACQUIRE "acquires the reaper status for
365     // the current process" but does that mean the first two arguments still need valid values to be
366     // supplied? We'll play it safe and explicitly target our own process:
367     procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL);
368 #endif
369     
370     log_flush_timer.add_timer(event_loop, dasynq::clock_type::MONOTONIC);
371
372     /* start requested services */
373     services = new dirload_service_set(service_dir);
374     
375     init_log(services);
376     if (am_system_init) {
377         log(loglevel_t::INFO, false, "starting system");
378     }
379     
380     if (env_file != nullptr) {
381         read_env_file(env_file);
382     }
383
384     for (auto svc : services_to_start) {
385         try {
386             services->start_service(svc);
387             // Note in general if we fail to start a service we don't need any special error handling,
388             // since we either leave other services running or, if it was the only service, then no
389             // services will be running and we will process normally (reboot if system process,
390             // exit if user process).
391         }
392         catch (service_not_found &snf) {
393             log(loglevel_t::ERROR, snf.serviceName, ": Could not find service description.");
394         }
395         catch (service_load_exc &sle) {
396             log(loglevel_t::ERROR, sle.serviceName, ": ", sle.excDescription);
397         }
398         catch (std::bad_alloc &badalloce) {
399             log(loglevel_t::ERROR, "Out of memory when trying to start service: ", svc, ".");
400             break;
401         }
402     }
403     
404     event_loop:
405     
406     // Process events until all services have terminated.
407     while (services->count_active_services() != 0) {
408         event_loop.run();
409     }
410
411     shutdown_type_t shutdown_type = services->get_shutdown_type();
412     
413     if (am_system_init) {
414         log_msg_begin(loglevel_t::INFO, "No more active services.");
415         
416         if (shutdown_type == shutdown_type_t::REBOOT) {
417             log_msg_end(" Will reboot.");
418         }
419         else if (shutdown_type == shutdown_type_t::HALT) {
420             log_msg_end(" Will halt.");
421         }
422         else if (shutdown_type == shutdown_type_t::POWEROFF) {
423             log_msg_end(" Will power down.");
424         }
425         else {
426             log_msg_end(" Re-initiating boot sequence.");
427         }
428     }
429     
430     log_flush_timer.arm_timer_rel(event_loop, timespec{5,0}); // 5 seconds
431     while (! is_log_flushed() && ! log_flush_timer.has_expired()) {
432         event_loop.run();
433     }
434     
435     close_control_socket();
436     
437     if (am_system_init) {
438         if (shutdown_type == shutdown_type_t::CONTINUE) {
439             // It could be that we started in single user mode, and the
440             // user has now exited the shell. We'll try and re-start the
441             // boot process...
442             try {
443                 services->start_service("boot");
444                 goto event_loop; // yes, the "evil" goto
445             }
446             catch (...) {
447                 // Now what do we do? try to reboot, but wait for user ack to avoid boot loop.
448                 log(loglevel_t::ERROR, "Could not start 'boot' service. Will attempt reboot.");
449                 wait_for_user_input();
450                 shutdown_type = shutdown_type_t::REBOOT;
451             }
452         }
453         
454         const char * cmd_arg;
455         if (shutdown_type == shutdown_type_t::HALT) {
456             cmd_arg = "-h";
457         }
458         else if (shutdown_type == shutdown_type_t::REBOOT) {
459             cmd_arg = "-r";
460         }
461         else {
462             // power off.
463             cmd_arg = "-p";
464         }
465         
466         // Fork and execute dinit-reboot.
467         execl("/sbin/shutdown", "/sbin/shutdown", "--system", cmd_arg, nullptr);
468         log(loglevel_t::ERROR, "Could not execute /sbin/shutdown: ", strerror(errno));
469         
470         // PID 1 must not actually exit, although we should never reach this point:
471         while (true) {
472             event_loop.run();
473         }
474     }
475     else if (shutdown_type == shutdown_type_t::REBOOT) {
476         // Non-system-process. If we got SIGINT, let's die due to it:
477         sigset_t sigwait_set;
478         sigemptyset(&sigwait_set);
479         sigaddset(&sigwait_set, SIGINT);
480         raise(SIGINT);
481         sigprocmask(SIG_UNBLOCK, &sigwait_set, NULL);
482     }
483     
484     return 0;
485 }
486
487 static void log_bad_env(int linenum)
488 {
489     log(loglevel_t::ERROR, "invalid environment variable setting in environment file (line ", linenum, ")");
490 }
491
492 // Read and set environment variables from a file.
493 static void read_env_file(const char *env_file_path)
494 {
495     // Note that we can't use the log in this function; it hasn't been initialised yet.
496
497     std::ifstream env_file(env_file_path);
498     if (! env_file) return;
499
500     env_file.exceptions(std::ios::badbit);
501
502     auto &clocale = std::locale::classic();
503     std::string line;
504     int linenum = 0;
505
506     while (std::getline(env_file, line)) {
507         linenum++;
508         auto lpos = line.begin();
509         auto lend = line.end();
510         while (lpos != lend && std::isspace(*lpos, clocale)) {
511             ++lpos;
512         }
513
514         if (lpos != lend) {
515             if (*lpos != '#') {
516                 if (*lpos == '=') {
517                     log_bad_env(linenum);
518                     continue;
519                 }
520                 auto name_begin = lpos++;
521                 // skip until '=' or whitespace:
522                 while (lpos != lend && *lpos != '=' && ! std::isspace(*lpos, clocale)) ++lpos;
523                 auto name_end = lpos;
524                 //  skip whitespace:
525                 while (lpos != lend && std::isspace(*lpos, clocale)) ++lpos;
526                 if (lpos == lend) {
527                     log_bad_env(linenum);
528                     continue;
529                 }
530
531                 ++lpos;
532                 auto val_begin = lpos;
533                 while (lpos != lend && *lpos != '\n') ++lpos;
534                 auto val_end = lpos;
535
536                 std::string name = line.substr(name_begin - line.begin(), name_end - name_begin);
537                 std::string value = line.substr(val_begin - line.begin(), val_end - val_begin);
538                 if (setenv(name.c_str(), value.c_str(), true) == -1) {
539                     throw std::system_error(errno, std::system_category());
540                 }
541             }
542         }
543     }
544 }
545
546 // In exception situations we want user confirmation before proceeding (eg on critical boot failure
547 // we wait before rebooting to avoid a reboot loop).
548 static void wait_for_user_input() noexcept
549 {
550     std::cout << "Press Enter to continue." << std::endl;
551     char buf[1];
552     read(STDIN_FILENO, buf, 1);
553 }
554
555 // Callback for control socket
556 static void control_socket_cb(eventloop_t *loop, int sockfd)
557 {
558     // Considered keeping a limit the number of active connections, however, there doesn't
559     // seem much to be gained from that. Only root can create connections and not being
560     // able to establish a control connection is as much a denial-of-service as is not being
561     // able to start a service due to lack of fd's.
562
563     // Accept a connection
564     int newfd = dinit_accept4(sockfd, nullptr, nullptr, SOCK_NONBLOCK | SOCK_CLOEXEC);
565
566     if (newfd != -1) {
567         try {
568             new control_conn_t(*loop, services, newfd);  // will delete itself when it's finished
569         }
570         catch (std::exception &exc) {
571             log(loglevel_t::ERROR, "Accepting control connection: ", exc.what());
572             close(newfd);
573         }
574     }
575 }
576
577 void open_control_socket(bool report_ro_failure) noexcept
578 {
579     if (! control_socket_open) {
580         const char * saddrname = control_socket_path;
581         size_t saddrname_len = strlen(saddrname);
582         uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + saddrname_len + 1;
583         
584         struct sockaddr_un * name = static_cast<sockaddr_un *>(malloc(sockaddr_size));
585         if (name == nullptr) {
586             log(loglevel_t::ERROR, "Opening control socket: out of memory");
587             return;
588         }
589
590         if (am_system_init) {
591             // Unlink any stale control socket file, but only if we are system init, since otherwise
592             // the 'stale' file may not be stale at all:
593             unlink(saddrname);
594         }
595
596         name->sun_family = AF_UNIX;
597         memcpy(name->sun_path, saddrname, saddrname_len + 1);
598
599         int sockfd = dinit_socket(AF_UNIX, SOCK_STREAM, 0, SOCK_NONBLOCK | SOCK_CLOEXEC);
600         if (sockfd == -1) {
601             log(loglevel_t::ERROR, "Error creating control socket: ", strerror(errno));
602             free(name);
603             return;
604         }
605
606         if (bind(sockfd, (struct sockaddr *) name, sockaddr_size) == -1) {
607             if (errno != EROFS || report_ro_failure) {
608                 log(loglevel_t::ERROR, "Error binding control socket: ", strerror(errno));
609             }
610             close(sockfd);
611             free(name);
612             return;
613         }
614         
615         free(name);
616
617         // No connections can be made until we listen, so it is fine to change the permissions now
618         // (and anyway there is no way to atomically create the socket and set permissions):
619         if (chmod(saddrname, S_IRUSR | S_IWUSR) == -1) {
620             log(loglevel_t::ERROR, "Error setting control socket permissions: ", strerror(errno));
621             close(sockfd);
622             return;
623         }
624
625         if (listen(sockfd, 10) == -1) {
626             log(loglevel_t::ERROR, "Error listening on control socket: ", strerror(errno));
627             close(sockfd);
628             return;
629         }
630
631         try {
632             control_socket_io.add_watch(event_loop, sockfd, dasynq::IN_EVENTS);
633             control_socket_open = true;
634         }
635         catch (std::exception &e)
636         {
637             log(loglevel_t::ERROR, "Could not setup I/O on control socket: ", e.what());
638             close(sockfd);
639         }
640     }
641 }
642
643 static void close_control_socket() noexcept
644 {
645     if (control_socket_open) {
646         int fd = control_socket_io.get_watched_fd();
647         control_socket_io.deregister(event_loop);
648         close(fd);
649         
650         // Unlink the socket:
651         unlink(control_socket_path);
652     }
653 }
654
655 void setup_external_log() noexcept
656 {
657     if (! external_log_open) {
658         if (log_is_syslog) {
659             const char * saddrname = log_path;
660             size_t saddrname_len = strlen(saddrname);
661             uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + saddrname_len + 1;
662
663             struct sockaddr_un * name = static_cast<sockaddr_un *>(malloc(sockaddr_size));
664             if (name == nullptr) {
665                 log(loglevel_t::ERROR, "Connecting to log socket: out of memory");
666                 return;
667             }
668
669             name->sun_family = AF_UNIX;
670             memcpy(name->sun_path, saddrname, saddrname_len + 1);
671
672             int sockfd = dinit_socket(AF_UNIX, SOCK_DGRAM, 0, SOCK_NONBLOCK | SOCK_CLOEXEC);
673             if (sockfd == -1) {
674                 log(loglevel_t::ERROR, "Error creating log socket: ", strerror(errno));
675                 free(name);
676                 return;
677             }
678
679             if (connect(sockfd, (struct sockaddr *) name, sockaddr_size) == 0 || errno == EINPROGRESS) {
680                 // For EINPROGRESS, connection is still being established; however, we can select on
681                 // the file descriptor so we will be notified when it's ready. In other words we can
682                 // basically use it anyway.
683                 try {
684                     setup_main_log(sockfd, true);
685                 }
686                 catch (std::exception &e) {
687                     log(loglevel_t::ERROR, "Setting up log failed: ", e.what());
688                     close(sockfd);
689                 }
690             }
691             else {
692                 // Note if connect fails, we haven't warned at all, because the syslog server might not
693                 // have started yet.
694                 close(sockfd);
695             }
696
697             free(name);
698         }
699         else {
700             // log to file:
701             int log_fd = open(log_path, O_WRONLY | O_CREAT | O_APPEND | O_NONBLOCK | O_CLOEXEC, 0644);
702             if (log_fd >= 0) {
703                 try {
704                     setup_main_log(log_fd, false);
705                 }
706                 catch (std::exception &e) {
707                     log(loglevel_t::ERROR, "Setting up log failed: ", e.what());
708                     close(log_fd);
709                 }
710             }
711             else {
712                 // log failure to log? It makes more sense than first appears, because we also log to console:
713                 log(loglevel_t::ERROR, "Setting up log failed: ", strerror(errno));
714             }
715         }
716     }
717 }
718
719 /* handle SIGINT signal (generated by Linux kernel when ctrl+alt+del pressed) */
720 static void sigint_reboot_cb(eventloop_t &eloop) noexcept
721 {
722     services->stop_all_services(shutdown_type_t::REBOOT);
723 }
724
725 /* handle SIGQUIT (if we are system init) */
726 static void sigquit_cb(eventloop_t &eloop) noexcept
727 {
728     // This performs an immediate shutdown, without service rollback.
729     close_control_socket();
730     execl("/sbin/shutdown", "/sbin/shutdown", "--system", (char *) 0);
731     log(loglevel_t::ERROR, "Error executing /sbin/shutdown: ", strerror(errno));
732     sync(); // since a hard poweroff might be required at this point...
733 }
734
735 /* handle SIGTERM/SIGQUIT(non-system-daemon) - stop all services and shut down */
736 static void sigterm_cb(eventloop_t &eloop) noexcept
737 {
738     services->stop_all_services();
739 }