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