Rip out libev, replace with dasynq (new library written for the purpose).
[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 "dasync.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 dasync;
64 using EventLoop_t = EventLoop<NullMutex>;
65
66 EventLoop_t eventLoop = EventLoop_t();
67
68 // TODO remove:
69 //static void sigint_reboot_cb(struct ev_loop *loop, ev_signal *w, int revents);
70 //static void sigquit_cb(struct ev_loop *loop, ev_signal *w, int revents);
71 //static void sigterm_cb(struct ev_loop *loop, ev_signal *w, int revents);
72 static void sigint_reboot_cb(EventLoop_t *eloop) noexcept;
73 static void sigquit_cb(EventLoop_t *eloop) noexcept;
74 static void sigterm_cb(EventLoop_t *eloop) noexcept;
75 void open_control_socket(EventLoop_t *loop) noexcept;
76 void close_control_socket(EventLoop_t *loop) noexcept;
77
78 static void control_socket_cb(EventLoop_t *loop, int fd);
79
80 class ControlSocketWatcher : public PosixFdWatcher<NullMutex>
81 {
82     Rearm gotEvent(EventLoop_t * loop, int fd, int flags)
83     {
84         control_socket_cb(loop, fd);
85         return Rearm::REARM;
86     }
87     
88     public:
89     // TODO the fd is already stored, must we really store it again...
90     int fd;
91     
92     void registerWith(EventLoop_t * loop, int fd, int flags)
93     {
94         this->fd = fd;
95         PosixFdWatcher<NullMutex>::registerWith(loop, fd, flags);
96     }
97 };
98
99 ControlSocketWatcher control_socket_io;
100
101
102 // Variables
103
104 static ServiceSet *service_set;
105
106 static bool am_system_init = false; // true if we are the system init process
107
108 static bool control_socket_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 *user_home_path = nullptr;
117
118
119 // Get user home (and set user_home_path). (The return may become invalid after
120 // changing the evironment (HOME variable) or using the getpwuid() function).
121 const char * get_user_home()
122 {
123     if (user_home_path == nullptr) {
124         user_home_path = getenv("HOME");
125         if (user_home_path == nullptr) {
126             struct passwd * pwuid_p = getpwuid(getuid());
127             if (pwuid_p != nullptr) {
128                 user_home_path = pwuid_p->pw_dir;
129             }
130         }
131     }
132     return user_home_path;
133 }
134
135
136 namespace {
137     class CallbackSignalHandler : public PosixSignalWatcher<NullMutex>
138     {
139         public:
140         typedef void (*cb_func_t)(EventLoop_t *);
141         
142         private:
143         cb_func_t cb_func;
144         
145         public:
146         CallbackSignalHandler() : cb_func(nullptr) { }
147         CallbackSignalHandler(cb_func_t pcb_func) :  cb_func(pcb_func) { }
148         
149         void setCbFunc(cb_func_t cb_func)
150         {
151             this->cb_func = cb_func;
152         }
153         
154         Rearm gotSignal(EventLoop_t * eloop, int signo, SigInfo_p siginfo) override
155         {
156             service_set->stop_all_services(ShutdownType::REBOOT);
157             return Rearm::REARM;
158         }
159     };
160
161     class ControlSocketWatcher : public PosixFdWatcher<NullMutex>
162     {
163         Rearm gotEvent(EventLoop_t * loop, int fd, int flags)
164         {
165             control_socket_cb(loop, fd);
166             return Rearm::REARM;
167         }
168     };
169 }
170
171 int main(int argc, char **argv)
172 {
173     using namespace std;
174     
175     am_system_init = (getpid() == 1);
176     const char * service_dir = nullptr;
177     string service_dir_str; // to hold storage for above if necessary
178     bool control_socket_path_set = false;
179
180     // list of services to start
181     list<const char *> services_to_start;
182     
183     // Arguments, if given, specify a list of services to start.
184     // If we are running as init (PID=1), the kernel gives us any command line
185     // arguments it was given but didn't recognize, including "single" (usually
186     // for "boot to single user mode" aka just start the shell). We can treat
187     // them as service names. In the worst case we can't find any of the named
188     // services, and so we'll start the "boot" service by default.
189     if (argc > 1) {
190       for (int i = 1; i < argc; i++) {
191         if (argv[i][0] == '-') {
192             // An option...
193             if (strcmp(argv[i], "--services-dir") == 0 ||
194                     strcmp(argv[i], "-d") == 0) {
195                 if (++i < argc) {
196                     service_dir = argv[i];
197                 }
198                 else {
199                     cerr << "dinit: '--services-dir' (-d) requires an argument" << endl;
200                     return 1;
201                 }
202             }
203             else if (strcmp(argv[i], "--system") == 0 ||
204                     strcmp(argv[i], "-s") == 0) {
205                 am_system_init = true;
206             }
207             else if (strcmp(argv[i], "--socket-path") == 0 ||
208                     strcmp(argv[i], "-p") == 0) {
209                 if (++i < argc) {
210                     control_socket_path = argv[i];
211                     control_socket_path_set = true;
212                 }
213                 else {
214                     cerr << "dinit: '--socket-path' (-p) requires an argument" << endl;
215                     return 1;
216                 }
217             }
218             else if (strcmp(argv[i], "--help") == 0) {
219                 cout << "dinit, an init with dependency management" << endl;
220                 cout << " --help                       display help" << endl;
221                 cout << " --services-dir <dir>, -d <dir>" << endl;
222                 cout << "                              set base directory for service description" << endl;
223                 cout << "                              files (-d <dir>)" << endl;
224                 cout << " --system, -s                 run as the system init process" << endl;
225                 cout << " --socket-path <path>, -p <path>" << endl;
226                 cout << "                              path to control socket" << endl;
227                 cout << " <service-name>               start service with name <service-name>" << endl;
228                 return 0;
229             }
230             else {
231                 // unrecognized
232                 if (! am_system_init) {
233                     cerr << "dinit: Unrecognized option: " << argv[i] << endl;
234                     return 1;
235                 }
236             }
237         }
238         else {
239             // LILO puts "auto" on the kernel command line for unattended boots; we'll filter it.
240             if (! am_system_init || strcmp(argv[i], "auto") != 0) {
241                 services_to_start.push_back(argv[i]);
242             }
243         }
244       }
245     }
246     
247     if (am_system_init) {
248         // setup STDIN, STDOUT, STDERR so that we can use them
249         int onefd = open("/dev/console", O_RDONLY, 0);
250         dup2(onefd, 0);
251         int twofd = open("/dev/console", O_RDWR, 0);
252         dup2(twofd, 1);
253         dup2(twofd, 2);
254         
255         if (onefd > 2) close(onefd);
256         if (twofd > 2) close(twofd);
257     }
258     
259     /* Set up signal handlers etc */
260     /* SIG_CHILD is ignored by default: good */
261     sigset_t sigwait_set;
262     sigemptyset(&sigwait_set);
263     sigaddset(&sigwait_set, SIGCHLD);
264     sigaddset(&sigwait_set, SIGINT);
265     sigaddset(&sigwait_set, SIGTERM);
266     sigprocmask(SIG_BLOCK, &sigwait_set, NULL);
267     
268     // Terminal access control signals - we block these so that dinit can't be
269     // suspended if it writes to the terminal after some other process has claimed
270     // ownership of it.
271     signal(SIGTSTP, SIG_IGN);
272     signal(SIGTTIN, SIG_IGN);
273     signal(SIGTTOU, SIG_IGN);
274     
275     if (! am_system_init && ! control_socket_path_set) {
276         const char * userhome = get_user_home();
277         if (userhome != nullptr) {
278             control_socket_str = userhome;
279             control_socket_str += "/.dinitctl";
280             control_socket_path = control_socket_str.c_str();
281         }
282     }
283     
284     /* service directory name */
285     if (service_dir == nullptr && ! am_system_init) {
286         const char * userhome = get_user_home();
287         if (userhome != nullptr) {
288             service_dir_str = get_user_home();
289             service_dir_str += "/dinit.d";
290             service_dir = service_dir_str.c_str();
291         }
292     }
293     
294     if (service_dir == nullptr) {
295         service_dir = "/etc/dinit.d";
296     }
297     
298     if (services_to_start.empty()) {
299         services_to_start.push_back("boot");
300     }
301
302     // Set up signal handlers
303     //ev_signal sigint_ev_signal;
304     CallbackSignalHandler sigint_watcher;
305     if (am_system_init) {
306       //ev_signal_init(&sigint_ev_signal, sigint_reboot_cb, SIGINT);
307       sigint_watcher.setCbFunc(sigint_reboot_cb);
308     }
309     else {
310       //ev_signal_init(&sigint_ev_signal, sigterm_cb, SIGINT);
311       sigint_watcher.setCbFunc(sigterm_cb);
312     }
313     
314     //ev_signal sigquit_ev_signal;
315     CallbackSignalHandler sigquit_watcher;
316     if (am_system_init) {
317         // PID 1: SIGQUIT exec's shutdown
318         //ev_signal_init(&sigquit_ev_signal, sigquit_cb, SIGQUIT);
319         sigquit_watcher.setCbFunc(sigquit_cb);
320     }
321     else {
322         // Otherwise: SIGQUIT terminates dinit
323         //ev_signal_init(&sigquit_ev_signal, sigterm_cb, SIGQUIT);
324         sigquit_watcher.setCbFunc(sigterm_cb);
325     }
326     
327     //ev_signal sigterm_ev_signal;
328     //ev_signal_init(&sigterm_ev_signal, sigterm_cb, SIGTERM);
329     auto sigterm_watcher = CallbackSignalHandler(sigterm_cb);
330     
331     /* Set up libev */
332     //struct ev_loop *loop = ev_default_loop(EVFLAG_AUTO /* | EVFLAG_SIGNALFD */);
333     //ev_signal_start(loop, &sigint_ev_signal);
334     //ev_signal_start(loop, &sigquit_ev_signal);
335     //ev_signal_start(loop, &sigterm_ev_signal);
336     sigint_watcher.registerWatch(&eventLoop, SIGINT);
337     sigquit_watcher.registerWatch(&eventLoop, SIGQUIT);
338     sigterm_watcher.registerWatch(&eventLoop, SIGTERM);
339
340     // Try to open control socket (may fail due to readonly filesystem)
341     open_control_socket(&eventLoop);
342     
343 #ifdef __linux__
344     if (am_system_init) {
345         // Disable non-critical kernel output to console
346         klogctl(6 /* SYSLOG_ACTION_CONSOLE_OFF */, nullptr, 0);
347         // Make ctrl+alt+del combination send SIGINT to PID 1 (this process)
348         reboot(RB_DISABLE_CAD);
349     }
350 #endif
351     
352     /* start requested services */
353     service_set = new ServiceSet(service_dir);
354     
355     init_log(service_set);
356     
357     for (list<const char *>::iterator i = services_to_start.begin();
358             i != services_to_start.end();
359             ++i) {
360         try {
361             service_set->startService(*i);
362         }
363         catch (ServiceNotFound &snf) {
364             log(LogLevel::ERROR, snf.serviceName, ": Could not find service description.");
365         }
366         catch (ServiceLoadExc &sle) {
367             log(LogLevel::ERROR, sle.serviceName, ": ", sle.excDescription);
368         }
369         catch (std::bad_alloc &badalloce) {
370             log(LogLevel::ERROR, "Out of memory when trying to start service: ", *i, ".");
371         }
372     }
373     
374     event_loop:
375     
376     // Process events until all services have terminated.
377     while (service_set->count_active_services() != 0) {
378         // ev_loop(loop, EVLOOP_ONESHOT);
379         eventLoop.run();
380     }
381
382     ShutdownType shutdown_type = service_set->getShutdownType();
383     
384     if (am_system_init) {
385         logMsgBegin(LogLevel::INFO, "No more active services.");
386         
387         if (shutdown_type == ShutdownType::REBOOT) {
388             logMsgEnd(" Will reboot.");
389         }
390         else if (shutdown_type == ShutdownType::HALT) {
391             logMsgEnd(" Will halt.");
392         }
393         else if (shutdown_type == ShutdownType::POWEROFF) {
394             logMsgEnd(" Will power down.");
395         }
396         else {
397             logMsgEnd(" Re-initiating boot sequence.");
398         }
399     }
400     
401     close_control_socket(&eventLoop);
402     
403     if (am_system_init) {
404         if (shutdown_type == ShutdownType::CONTINUE) {
405             // It could be that we started in single user mode, and the
406             // user has now exited the shell. We'll try and re-start the
407             // boot process...
408             try {
409                 service_set->startService("boot");
410                 goto event_loop; // yes, the "evil" goto
411             }
412             catch (...) {
413                 // Now WTF do we do? try to reboot
414                 log(LogLevel::ERROR, "Could not start 'boot' service; rebooting.");
415                 shutdown_type = ShutdownType::REBOOT;
416             }
417         }
418         
419         const char * cmd_arg;
420         if (shutdown_type == ShutdownType::HALT) {
421             cmd_arg = "-h";
422         }
423         else if (shutdown_type == ShutdownType::REBOOT) {
424             cmd_arg = "-r";
425         }
426         else {
427             // power off.
428             cmd_arg = "-p";
429         }
430         
431         // Fork and execute dinit-reboot.
432         execl("/sbin/shutdown", "/sbin/shutdown", "--system", cmd_arg, nullptr);
433         log(LogLevel::ERROR, "Could not execute /sbin/shutdown: ", strerror(errno));
434         
435         // PID 1 must not actually exit, although we should never reach this point:
436         while (true) {
437             // ev_loop(loop, EVLOOP_ONESHOT);
438             eventLoop.run();
439         }
440     }
441     
442     return 0;
443 }
444
445 // Callback for control socket
446 static void control_socket_cb(EventLoop_t *loop, int sockfd)
447 {
448     // TODO limit the number of active connections. Keep a tally, and disable the
449     // control connection listening socket watcher if it gets high, and re-enable
450     // it once it falls below the maximum.
451
452     // Accept a connection
453     int newfd = accept4(sockfd, nullptr, nullptr, SOCK_NONBLOCK | SOCK_CLOEXEC);
454
455     if (newfd != -1) {
456         try {
457             new ControlConn(loop, service_set, newfd);  // will delete itself when it's finished
458         }
459         catch (std::bad_alloc &bad_alloc_exc) {
460             log(LogLevel::ERROR, "Accepting control connection: Out of memory");
461             close(newfd);
462         }
463     }
464 }
465
466 void open_control_socket(EventLoop_t *loop) noexcept
467 {
468     if (! control_socket_open) {
469         const char * saddrname = control_socket_path;
470         uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + strlen(saddrname) + 1;
471         
472         struct sockaddr_un * name = static_cast<sockaddr_un *>(malloc(sockaddr_size));
473         if (name == nullptr) {
474             log(LogLevel::ERROR, "Opening control socket: out of memory");
475             return;
476         }
477
478         if (am_system_init) {
479             // Unlink any stale control socket file, but only if we are system init, since otherwise
480             // the 'stale' file may not be stale at all:
481             unlink(saddrname);
482         }
483
484         name->sun_family = AF_UNIX;
485         strcpy(name->sun_path, saddrname);
486
487         // OpenBSD and Linux both allow combining NONBLOCK/CLOEXEC flags with socket type, however
488         // it's not actually POSIX. (TODO).
489         int sockfd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
490         if (sockfd == -1) {
491             log(LogLevel::ERROR, "Error creating control socket: ", strerror(errno));
492             free(name);
493             return;
494         }
495
496         if (bind(sockfd, (struct sockaddr *) name, sockaddr_size) == -1) {
497             log(LogLevel::ERROR, "Error binding control socket: ", strerror(errno));
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         control_socket_open = true;
520         //ev_io_init(&control_socket_io, control_socket_cb, sockfd, EV_READ);
521         //ev_io_start(loop, &control_socket_io);
522         control_socket_io.registerWith(&eventLoop, sockfd, in_events);
523     }
524 }
525
526 void close_control_socket(EventLoop_t *loop) noexcept
527 {
528     if (control_socket_open) {
529         int fd = control_socket_io.fd;
530         //ev_io_stop(loop, &control_socket_io);
531         control_socket_io.deregisterWatch(&eventLoop);
532         close(fd);
533         
534         // Unlink the socket:
535         unlink(control_socket_path);
536     }
537 }
538
539 /* handle SIGINT signal (generated by kernel when ctrl+alt+del pressed) */
540 static void sigint_reboot_cb(EventLoop_t *eloop) noexcept
541 {
542     service_set->stop_all_services(ShutdownType::REBOOT);
543 }
544
545 /* handle SIGQUIT (if we are system init) */
546 static void sigquit_cb(EventLoop_t *eloop) noexcept
547 {
548     // This allows remounting the filesystem read-only if the dinit binary has been
549     // unlinked. In that case the kernel holds the binary open, so that it can't be
550     // properly removed.
551     close_control_socket(eloop);
552     execl("/sbin/shutdown", "/sbin/shutdown", (char *) 0);
553     log(LogLevel::ERROR, "Error executing /sbin/shutdown: ", strerror(errno));
554 }
555
556 /* handle SIGTERM/SIGQUIT - stop all services (not used for system daemon) */
557 static void sigterm_cb(EventLoop_t *eloop) noexcept
558 {
559     service_set->stop_all_services();
560 }