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