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