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