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