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