Log system startup.
[oweals/dinit.git] / src / dinit.cc
1 #include <iostream>
2 #include <fstream>
3 #include <list>
4 #include <cstring>
5 #include <csignal>
6 #include <cstddef>
7 #include <cstdlib>
8
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <sys/un.h>
12 #include <sys/socket.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <pwd.h>
16 #ifdef __linux__
17 #include <sys/prctl.h>
18 #include <sys/klog.h>
19 #include <sys/reboot.h>
20 #endif
21 #if defined(__FreeBSD__) || defined(__DragonFly__)
22 #include <sys/procctl.h>
23 #endif
24
25 #include "dinit.h"
26 #include "dasynq.h"
27 #include "service.h"
28 #include "control.h"
29 #include "dinit-log.h"
30 #include "dinit-socket.h"
31
32 /*
33  * When running as the system init process, Dinit processes the following signals:
34  *
35  * SIGTERM - roll back services and then fork/exec /sbin/halt
36  * SIGINT - roll back services and then fork/exec /sbin/reboot
37  * SIGQUIT - exec() /sbin/shutdown without rolling back services
38  *
39  * It's an open question about whether Dinit should roll back services *before*
40  * running halt/reboot, since those commands should prompt rollback of services
41  * anyway. But it seems safe to do so, and it means the user can at least stop
42  * services even if the halt/reboot commands are unavailable for some reason.
43  */
44
45 using eventloop_t = dasynq::event_loop<dasynq::null_mutex>;
46
47 eventloop_t event_loop;
48
49 static void sigint_reboot_cb(eventloop_t &eloop) noexcept;
50 static void sigquit_cb(eventloop_t &eloop) noexcept;
51 static void sigterm_cb(eventloop_t &eloop) noexcept;
52 static void close_control_socket() noexcept;
53 static void wait_for_user_input() noexcept;
54 static void read_env_file(const char *);
55
56 static void control_socket_cb(eventloop_t *loop, int fd);
57
58
59 // Variables
60
61 static dirload_service_set *services;
62
63 static bool am_system_init = false; // true if we are the system init process
64
65 static bool control_socket_open = false;
66 static bool external_log_open = false;
67 int active_control_conns = 0;
68
69 // Control socket path. We maintain a string (control_socket_str) in case we need
70 // to allocate storage, but control_socket_path is the authoritative value.
71 static const char *control_socket_path = "/dev/dinitctl";
72 static std::string control_socket_str;
73
74 static const char *env_file_path = "/etc/dinit/environment";
75
76 static const char *log_socket_path = "/dev/log";
77
78 static const char *user_home_path = nullptr;
79
80
81 // Get user home (and set user_home_path). (The return may become invalid after
82 // changing the evironment (HOME variable) or using the getpwuid() function).
83 const char * get_user_home()
84 {
85     if (user_home_path == nullptr) {
86         user_home_path = getenv("HOME");
87         if (user_home_path == nullptr) {
88             struct passwd * pwuid_p = getpwuid(getuid());
89             if (pwuid_p != nullptr) {
90                 user_home_path = pwuid_p->pw_dir;
91             }
92         }
93     }
94     return user_home_path;
95 }
96
97
98 namespace {
99     class callback_signal_handler : public eventloop_t::signal_watcher_impl<callback_signal_handler>
100     {
101         using rearm = dasynq::rearm;
102
103         public:
104         typedef void (*cb_func_t)(eventloop_t &);
105         
106         private:
107         cb_func_t cb_func;
108         
109         public:
110         callback_signal_handler() : cb_func(nullptr) { }
111         callback_signal_handler(cb_func_t pcb_func) :  cb_func(pcb_func) { }
112         
113         void setCbFunc(cb_func_t cb_func)
114         {
115             this->cb_func = cb_func;
116         }
117         
118         rearm received(eventloop_t &eloop, int signo, siginfo_p siginfo)
119         {
120             cb_func(eloop);
121             return rearm::REARM;
122         }
123     };
124
125     class control_socket_watcher : public eventloop_t::fd_watcher_impl<control_socket_watcher>
126     {
127         using rearm = dasynq::rearm;
128
129         public:
130         rearm fd_event(eventloop_t &loop, int fd, int flags) noexcept
131         {
132             control_socket_cb(&loop, fd);
133             return rearm::REARM;
134         }
135     };
136
137     // Simple timer used to limit the amount of time waiting for the log flush to complete (at shutdown)
138     class log_flush_timer_t : public eventloop_t::timer_impl<log_flush_timer_t>
139     {
140         using rearm = dasynq::rearm;
141
142         bool expired = false;
143
144         public:
145         rearm timer_expiry(eventloop_t &, int expiry_count)
146         {
147             expired = true;
148             return rearm::DISARM;
149         }
150
151         bool has_expired()
152         {
153             return expired;
154         }
155     };
156
157     control_socket_watcher control_socket_io;
158     log_flush_timer_t log_flush_timer;
159 }
160
161 int dinit_main(int argc, char **argv)
162 {
163     using namespace std;
164     
165     am_system_init = (getpid() == 1);
166     const char * service_dir = nullptr;
167     const char * env_file = nullptr;
168     string service_dir_str; // to hold storage for above if necessary
169     bool control_socket_path_set = false;
170     bool env_file_set = false;
171
172     // list of services to start
173     list<const char *> services_to_start;
174     
175     // Arguments, if given, specify a list of services to start.
176     // If we are running as init (PID=1), the Linux kernel gives us any command line arguments it was given
177     // but didn't recognize, including "single" (usually for "boot to single user mode" aka just start the
178     // shell). We can treat them as service names. In the worst case we can't find any of the named
179     // services, and so we'll start the "boot" service by default.
180     if (argc > 1) {
181       for (int i = 1; i < argc; i++) {
182         if (argv[i][0] == '-') {
183             // An option...
184             if (strcmp(argv[i], "--env-file") == 0 || strcmp(argv[i], "-e") == 0) {
185                 if (++i < argc) {
186                     env_file_set = true;
187                     env_file = argv[i];
188                 }
189                 else {
190                     cerr << "dinit: '--env-file' (-e) requires an argument" << endl;
191                 }
192             }
193             else if (strcmp(argv[i], "--services-dir") == 0 || 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 || strcmp(argv[i], "-s") == 0) {
203                 am_system_init = true;
204             }
205             else if (strcmp(argv[i], "--socket-path") == 0 || strcmp(argv[i], "-p") == 0) {
206                 if (++i < argc) {
207                     control_socket_path = argv[i];
208                     control_socket_path_set = true;
209                 }
210                 else {
211                     cerr << "dinit: '--socket-path' (-p) requires an argument" << endl;
212                     return 1;
213                 }
214             }
215             else if (strcmp(argv[i], "--help") == 0) {
216                 cout << "dinit, an init with dependency management" << endl;
217                 cout << " --help                       display help" << endl;
218                 cout << " --env-file <file>, -e <file>" << endl;
219                 cout << "                              environment variable initialisation file" << 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 #ifdef __linux__
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 #else
244             services_to_start.push_back(argv[i]);
245 #endif
246         }
247       }
248     }
249     
250     if (am_system_init) {
251         // setup STDIN, STDOUT, STDERR so that we can use them
252         int onefd = open("/dev/console", O_RDONLY, 0);
253         dup2(onefd, 0);
254         int twofd = open("/dev/console", O_RDWR, 0);
255         dup2(twofd, 1);
256         dup2(twofd, 2);
257         
258         if (onefd > 2) close(onefd);
259         if (twofd > 2) close(twofd);
260
261         if (! env_file_set) {
262             env_file = env_file_path;
263         }
264     }
265
266     /* Set up signal handlers etc */
267     /* SIG_CHILD is ignored by default: good */
268     sigset_t sigwait_set;
269     sigemptyset(&sigwait_set);
270     sigaddset(&sigwait_set, SIGCHLD);
271     sigaddset(&sigwait_set, SIGINT);
272     sigaddset(&sigwait_set, SIGTERM);
273     if (am_system_init) sigaddset(&sigwait_set, SIGQUIT);
274     sigprocmask(SIG_BLOCK, &sigwait_set, NULL);
275
276     // Terminal access control signals - we block these so that dinit can't be
277     // suspended if it writes to the terminal after some other process has claimed
278     // ownership of it.
279     signal(SIGTSTP, SIG_IGN);
280     signal(SIGTTIN, SIG_IGN);
281     signal(SIGTTOU, SIG_IGN);
282     
283     signal(SIGPIPE, SIG_IGN);
284     
285     if (! am_system_init && ! control_socket_path_set) {
286         const char * userhome = get_user_home();
287         if (userhome != nullptr) {
288             control_socket_str = userhome;
289             control_socket_str += "/.dinitctl";
290             control_socket_path = control_socket_str.c_str();
291         }
292     }
293     
294     /* service directory name */
295     if (service_dir == nullptr && ! am_system_init) {
296         const char * userhome = get_user_home();
297         if (userhome != nullptr) {
298             service_dir_str = get_user_home();
299             service_dir_str += "/dinit.d";
300             service_dir = service_dir_str.c_str();
301         }
302     }
303     
304     if (service_dir == nullptr) {
305         service_dir = "/etc/dinit.d";
306     }
307     
308     if (services_to_start.empty()) {
309         services_to_start.push_back("boot");
310     }
311
312     // Set up signal handlers
313     callback_signal_handler sigterm_watcher {sigterm_cb};
314     callback_signal_handler sigint_watcher;
315     callback_signal_handler sigquit_watcher;
316
317     if (am_system_init) {
318         sigint_watcher.setCbFunc(sigint_reboot_cb);
319         sigquit_watcher.setCbFunc(sigquit_cb);
320     }
321     else {
322         sigint_watcher.setCbFunc(sigterm_cb);
323     }
324
325     sigint_watcher.add_watch(event_loop, SIGINT);
326     sigterm_watcher.add_watch(event_loop, SIGTERM);
327     
328     if (am_system_init) {
329         // PID 1: SIGQUIT exec's shutdown
330         sigquit_watcher.add_watch(event_loop, SIGQUIT);
331         // As a user process, we instead just let SIGQUIT perform the default action.
332     }
333
334     // Try to open control socket (may fail due to readonly filesystem)
335     open_control_socket(false);
336     
337 #ifdef __linux__
338     if (am_system_init) {
339         // Disable non-critical kernel output to console
340         klogctl(6 /* SYSLOG_ACTION_CONSOLE_OFF */, nullptr, 0);
341         // Make ctrl+alt+del combination send SIGINT to PID 1 (this process)
342         reboot(RB_DISABLE_CAD);
343     }
344
345     // Mark ourselves as a subreaper. This means that if a process we start double-forks, the
346     // orphaned child will re-parent to us rather than to PID 1 (although that could be us too).
347     prctl(PR_SET_CHILD_SUBREAPER, 1);
348 #elif defined(__FreeBSD__) || defined(__DragonFly__)
349     // Documentation (man page) for this kind of sucks. PROC_REAP_ACQUIRE "acquires the reaper status for
350     // the current process" but does that mean the first two arguments still need valid values to be
351     // supplied? We'll play it safe and explicitly target our own process:
352     procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL);
353 #endif
354     
355     log_flush_timer.add_timer(event_loop, dasynq::clock_type::MONOTONIC);
356
357     /* start requested services */
358     services = new dirload_service_set(service_dir);
359     
360     init_log(services);
361     if (am_system_init) {
362         log(loglevel_t::INFO, false, "starting system");
363     }
364     
365     if (env_file != nullptr) {
366         read_env_file(env_file);
367     }
368
369     for (auto svc : services_to_start) {
370         try {
371             services->start_service(svc);
372             // Note in general if we fail to start a service we don't need any special error handling,
373             // since we either leave other services running or, if it was the only service, then no
374             // services will be running and we will process normally (reboot if system process,
375             // exit if user process).
376         }
377         catch (service_not_found &snf) {
378             log(loglevel_t::ERROR, snf.serviceName, ": Could not find service description.");
379         }
380         catch (service_load_exc &sle) {
381             log(loglevel_t::ERROR, sle.serviceName, ": ", sle.excDescription);
382         }
383         catch (std::bad_alloc &badalloce) {
384             log(loglevel_t::ERROR, "Out of memory when trying to start service: ", svc, ".");
385             break;
386         }
387     }
388     
389     event_loop:
390     
391     // Process events until all services have terminated.
392     while (services->count_active_services() != 0) {
393         event_loop.run();
394     }
395
396     shutdown_type_t shutdown_type = services->get_shutdown_type();
397     
398     if (am_system_init) {
399         log_msg_begin(loglevel_t::INFO, "No more active services.");
400         
401         if (shutdown_type == shutdown_type_t::REBOOT) {
402             log_msg_end(" Will reboot.");
403         }
404         else if (shutdown_type == shutdown_type_t::HALT) {
405             log_msg_end(" Will halt.");
406         }
407         else if (shutdown_type == shutdown_type_t::POWEROFF) {
408             log_msg_end(" Will power down.");
409         }
410         else {
411             log_msg_end(" Re-initiating boot sequence.");
412         }
413     }
414     
415     log_flush_timer.arm_timer_rel(event_loop, timespec{5,0}); // 5 seconds
416     while (! is_log_flushed() && ! log_flush_timer.has_expired()) {
417         event_loop.run();
418     }
419     
420     close_control_socket();
421     
422     if (am_system_init) {
423         if (shutdown_type == shutdown_type_t::CONTINUE) {
424             // It could be that we started in single user mode, and the
425             // user has now exited the shell. We'll try and re-start the
426             // boot process...
427             try {
428                 services->start_service("boot");
429                 goto event_loop; // yes, the "evil" goto
430             }
431             catch (...) {
432                 // Now what do we do? try to reboot, but wait for user ack to avoid boot loop.
433                 log(loglevel_t::ERROR, "Could not start 'boot' service. Will attempt reboot.");
434                 wait_for_user_input();
435                 shutdown_type = shutdown_type_t::REBOOT;
436             }
437         }
438         
439         const char * cmd_arg;
440         if (shutdown_type == shutdown_type_t::HALT) {
441             cmd_arg = "-h";
442         }
443         else if (shutdown_type == shutdown_type_t::REBOOT) {
444             cmd_arg = "-r";
445         }
446         else {
447             // power off.
448             cmd_arg = "-p";
449         }
450         
451         // Fork and execute dinit-reboot.
452         execl("/sbin/shutdown", "/sbin/shutdown", "--system", cmd_arg, nullptr);
453         log(loglevel_t::ERROR, "Could not execute /sbin/shutdown: ", strerror(errno));
454         
455         // PID 1 must not actually exit, although we should never reach this point:
456         while (true) {
457             event_loop.run();
458         }
459     }
460     else if (shutdown_type == shutdown_type_t::REBOOT) {
461         // Non-system-process. If we got SIGINT, let's die due to it:
462         sigset_t sigwait_set;
463         sigemptyset(&sigwait_set);
464         sigaddset(&sigwait_set, SIGINT);
465         raise(SIGINT);
466         sigprocmask(SIG_UNBLOCK, &sigwait_set, NULL);
467     }
468     
469     return 0;
470 }
471
472 static void log_bad_env(int linenum)
473 {
474     log(loglevel_t::ERROR, "invalid environment variable setting in environment file (line ", linenum, ")");
475 }
476
477 // Read and set environment variables from a file.
478 static void read_env_file(const char *env_file_path)
479 {
480     // Note that we can't use the log in this function; it hasn't been initialised yet.
481
482     std::ifstream env_file(env_file_path);
483     if (! env_file) return;
484
485     env_file.exceptions(std::ios::badbit);
486
487     auto &clocale = std::locale::classic();
488     std::string line;
489     int linenum = 0;
490
491     while (std::getline(env_file, line)) {
492         linenum++;
493         auto lpos = line.begin();
494         auto lend = line.end();
495         while (lpos != lend && std::isspace(*lpos, clocale)) {
496             ++lpos;
497         }
498
499         if (lpos != lend) {
500             if (*lpos != '#') {
501                 if (*lpos == '=') {
502                     log_bad_env(linenum);
503                     continue;
504                 }
505                 auto name_begin = lpos++;
506                 // skip until '=' or whitespace:
507                 while (lpos != lend && *lpos != '=' && ! std::isspace(*lpos, clocale)) ++lpos;
508                 auto name_end = lpos;
509                 //  skip whitespace:
510                 while (lpos != lend && std::isspace(*lpos, clocale)) ++lpos;
511                 if (lpos == lend) {
512                     log_bad_env(linenum);
513                     continue;
514                 }
515
516                 ++lpos;
517                 auto val_begin = lpos;
518                 while (lpos != lend && *lpos != '\n') ++lpos;
519                 auto val_end = lpos;
520
521                 std::string name = line.substr(name_begin - line.begin(), name_end - name_begin);
522                 std::string value = line.substr(val_begin - line.begin(), val_end - val_begin);
523                 if (setenv(name.c_str(), value.c_str(), true) == -1) {
524                     throw std::system_error(errno, std::system_category());
525                 }
526             }
527         }
528     }
529 }
530
531 // In exception situations we want user confirmation before proceeding (eg on critical boot failure
532 // we wait before rebooting to avoid a reboot loop).
533 static void wait_for_user_input() noexcept
534 {
535     std::cout << "Press Enter to continue." << std::endl;
536     char buf[1];
537     read(STDIN_FILENO, buf, 1);
538 }
539
540 // Callback for control socket
541 static void control_socket_cb(eventloop_t *loop, int sockfd)
542 {
543     // Considered keeping a limit the number of active connections, however, there doesn't
544     // seem much to be gained from that. Only root can create connections and not being
545     // able to establish a control connection is as much a denial-of-service as is not being
546     // able to start a service due to lack of fd's.
547
548     // Accept a connection
549     int newfd = dinit_accept4(sockfd, nullptr, nullptr, SOCK_NONBLOCK | SOCK_CLOEXEC);
550
551     if (newfd != -1) {
552         try {
553             new control_conn_t(*loop, services, newfd);  // will delete itself when it's finished
554         }
555         catch (std::exception &exc) {
556             log(loglevel_t::ERROR, "Accepting control connection: ", exc.what());
557             close(newfd);
558         }
559     }
560 }
561
562 void open_control_socket(bool report_ro_failure) noexcept
563 {
564     if (! control_socket_open) {
565         const char * saddrname = control_socket_path;
566         size_t saddrname_len = strlen(saddrname);
567         uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + saddrname_len + 1;
568         
569         struct sockaddr_un * name = static_cast<sockaddr_un *>(malloc(sockaddr_size));
570         if (name == nullptr) {
571             log(loglevel_t::ERROR, "Opening control socket: out of memory");
572             return;
573         }
574
575         if (am_system_init) {
576             // Unlink any stale control socket file, but only if we are system init, since otherwise
577             // the 'stale' file may not be stale at all:
578             unlink(saddrname);
579         }
580
581         name->sun_family = AF_UNIX;
582         memcpy(name->sun_path, saddrname, saddrname_len + 1);
583
584         int sockfd = dinit_socket(AF_UNIX, SOCK_STREAM, 0, SOCK_NONBLOCK | SOCK_CLOEXEC);
585         if (sockfd == -1) {
586             log(loglevel_t::ERROR, "Error creating control socket: ", strerror(errno));
587             free(name);
588             return;
589         }
590
591         if (bind(sockfd, (struct sockaddr *) name, sockaddr_size) == -1) {
592             if (errno != EROFS || report_ro_failure) {
593                 log(loglevel_t::ERROR, "Error binding control socket: ", strerror(errno));
594             }
595             close(sockfd);
596             free(name);
597             return;
598         }
599         
600         free(name);
601
602         // No connections can be made until we listen, so it is fine to change the permissions now
603         // (and anyway there is no way to atomically create the socket and set permissions):
604         if (chmod(saddrname, S_IRUSR | S_IWUSR) == -1) {
605             log(loglevel_t::ERROR, "Error setting control socket permissions: ", strerror(errno));
606             close(sockfd);
607             return;
608         }
609
610         if (listen(sockfd, 10) == -1) {
611             log(loglevel_t::ERROR, "Error listening on control socket: ", strerror(errno));
612             close(sockfd);
613             return;
614         }
615
616         try {
617             control_socket_io.add_watch(event_loop, sockfd, dasynq::IN_EVENTS);
618             control_socket_open = true;
619         }
620         catch (std::exception &e)
621         {
622             log(loglevel_t::ERROR, "Could not setup I/O on control socket: ", e.what());
623             close(sockfd);
624         }
625     }
626 }
627
628 static void close_control_socket() noexcept
629 {
630     if (control_socket_open) {
631         int fd = control_socket_io.get_watched_fd();
632         control_socket_io.deregister(event_loop);
633         close(fd);
634         
635         // Unlink the socket:
636         unlink(control_socket_path);
637     }
638 }
639
640 void setup_external_log() noexcept
641 {
642     if (! external_log_open) {
643     
644         const char * saddrname = log_socket_path;
645         size_t saddrname_len = strlen(saddrname);
646         uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + saddrname_len + 1;
647         
648         struct sockaddr_un * name = static_cast<sockaddr_un *>(malloc(sockaddr_size));
649         if (name == nullptr) {
650             log(loglevel_t::ERROR, "Connecting to log socket: out of memory");
651             return;
652         }
653         
654         name->sun_family = AF_UNIX;
655         memcpy(name->sun_path, saddrname, saddrname_len + 1);
656         
657         int sockfd = dinit_socket(AF_UNIX, SOCK_DGRAM, 0, SOCK_NONBLOCK | SOCK_CLOEXEC);
658         if (sockfd == -1) {
659             log(loglevel_t::ERROR, "Error creating log socket: ", strerror(errno));
660             free(name);
661             return;
662         }
663         
664         if (connect(sockfd, (struct sockaddr *) name, sockaddr_size) == 0 || errno == EINPROGRESS) {
665             // For EINPROGRESS, connection is still being established; however, we can select on
666             // the file descriptor so we will be notified when it's ready. In other words we can
667             // basically use it anyway.
668             try {
669                 setup_main_log(sockfd);
670             }
671             catch (std::exception &e) {
672                 log(loglevel_t::ERROR, "Setting up log failed: ", e.what());
673                 close(sockfd);
674             }
675         }
676         else {
677             // Note if connect fails, we haven't warned at all, because the syslog server might not
678             // have started yet.
679             close(sockfd);
680         }
681         
682         free(name);
683     }
684 }
685
686 /* handle SIGINT signal (generated by Linux kernel when ctrl+alt+del pressed) */
687 static void sigint_reboot_cb(eventloop_t &eloop) noexcept
688 {
689     services->stop_all_services(shutdown_type_t::REBOOT);
690 }
691
692 /* handle SIGQUIT (if we are system init) */
693 static void sigquit_cb(eventloop_t &eloop) noexcept
694 {
695     // This performs an immediate shutdown, without service rollback.
696     close_control_socket();
697     execl("/sbin/shutdown", "/sbin/shutdown", "--system", (char *) 0);
698     log(loglevel_t::ERROR, "Error executing /sbin/shutdown: ", strerror(errno));
699     sync(); // since a hard poweroff might be required at this point...
700 }
701
702 /* handle SIGTERM/SIGQUIT(non-system-daemon) - stop all services and shut down */
703 static void sigterm_cb(eventloop_t &eloop) noexcept
704 {
705     services->stop_all_services();
706 }