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