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