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