11 #include <sys/socket.h>
19 #include "dinit-log.h"
23 #include <sys/reboot.h>
27 * When running as the system init process, Dinit processes the following signals:
29 * SIGTERM - roll back services and then fork/exec /sbin/halt
30 * SIGINT - roll back services and then fork/exec /sbin/reboot
31 * SIGQUIT - exec() /sbin/shutdown without rolling back services
33 * It's an open question about whether dinit should roll back services *before*
34 * running halt/reboot, since those commands should prompt rollback of services
35 * anyway. But it seems safe to do so.
39 using namespace dasynq;
40 using EventLoop_t = event_loop<null_mutex>;
42 EventLoop_t eventLoop = EventLoop_t();
44 static void sigint_reboot_cb(EventLoop_t *eloop) noexcept;
45 static void sigquit_cb(EventLoop_t *eloop) noexcept;
46 static void sigterm_cb(EventLoop_t *eloop) noexcept;
47 static void close_control_socket() noexcept;
49 static void control_socket_cb(EventLoop_t *loop, int fd);
51 void open_control_socket(bool report_ro_failure = true) noexcept;
52 void setup_external_log() noexcept;
55 class ControlSocketWatcher : public EventLoop_t::fd_watcher_impl<ControlSocketWatcher>
58 rearm fd_event(EventLoop_t &loop, int fd, int flags) noexcept
60 control_socket_cb(&loop, fd);
65 ControlSocketWatcher control_socket_io;
70 static ServiceSet *service_set;
72 static bool am_system_init = false; // true if we are the system init process
74 static bool control_socket_open = false;
75 static bool external_log_open = false;
76 int active_control_conns = 0;
78 // Control socket path. We maintain a string (control_socket_str) in case we need
79 // to allocate storage, but control_socket_path is the authoritative value.
80 static const char *control_socket_path = "/dev/dinitctl";
81 static std::string control_socket_str;
83 static const char *log_socket_path = "/dev/log";
85 static const char *user_home_path = nullptr;
88 // Get user home (and set user_home_path). (The return may become invalid after
89 // changing the evironment (HOME variable) or using the getpwuid() function).
90 const char * get_user_home()
92 if (user_home_path == nullptr) {
93 user_home_path = getenv("HOME");
94 if (user_home_path == nullptr) {
95 struct passwd * pwuid_p = getpwuid(getuid());
96 if (pwuid_p != nullptr) {
97 user_home_path = pwuid_p->pw_dir;
101 return user_home_path;
106 class CallbackSignalHandler : public EventLoop_t::signal_watcher_impl<CallbackSignalHandler>
109 typedef void (*cb_func_t)(EventLoop_t *);
115 CallbackSignalHandler() : cb_func(nullptr) { }
116 CallbackSignalHandler(cb_func_t pcb_func) : cb_func(pcb_func) { }
118 void setCbFunc(cb_func_t cb_func)
120 this->cb_func = cb_func;
123 rearm received(EventLoop_t &eloop, int signo, siginfo_p siginfo)
125 service_set->stop_all_services(ShutdownType::REBOOT);
130 class ControlSocketWatcher : public EventLoop_t::fd_watcher_impl<ControlSocketWatcher>
132 rearm fd_event(EventLoop_t &loop, int fd, int flags)
134 control_socket_cb(&loop, fd);
140 int main(int argc, char **argv)
144 am_system_init = (getpid() == 1);
145 const char * service_dir = nullptr;
146 string service_dir_str; // to hold storage for above if necessary
147 bool control_socket_path_set = false;
149 // list of services to start
150 list<const char *> services_to_start;
152 // Arguments, if given, specify a list of services to start.
153 // If we are running as init (PID=1), the kernel gives us any command line
154 // arguments it was given but didn't recognize, including "single" (usually
155 // for "boot to single user mode" aka just start the shell). We can treat
156 // them as service names. In the worst case we can't find any of the named
157 // services, and so we'll start the "boot" service by default.
159 for (int i = 1; i < argc; i++) {
160 if (argv[i][0] == '-') {
162 if (strcmp(argv[i], "--services-dir") == 0 ||
163 strcmp(argv[i], "-d") == 0) {
165 service_dir = argv[i];
168 cerr << "dinit: '--services-dir' (-d) requires an argument" << endl;
172 else if (strcmp(argv[i], "--system") == 0 ||
173 strcmp(argv[i], "-s") == 0) {
174 am_system_init = true;
176 else if (strcmp(argv[i], "--socket-path") == 0 ||
177 strcmp(argv[i], "-p") == 0) {
179 control_socket_path = argv[i];
180 control_socket_path_set = true;
183 cerr << "dinit: '--socket-path' (-p) requires an argument" << endl;
187 else if (strcmp(argv[i], "--help") == 0) {
188 cout << "dinit, an init with dependency management" << endl;
189 cout << " --help display help" << endl;
190 cout << " --services-dir <dir>, -d <dir>" << endl;
191 cout << " set base directory for service description" << endl;
192 cout << " files (-d <dir>)" << endl;
193 cout << " --system, -s run as the system init process" << endl;
194 cout << " --socket-path <path>, -p <path>" << endl;
195 cout << " path to control socket" << endl;
196 cout << " <service-name> start service with name <service-name>" << endl;
201 if (! am_system_init) {
202 cerr << "dinit: Unrecognized option: " << argv[i] << endl;
208 // LILO puts "auto" on the kernel command line for unattended boots; we'll filter it.
209 if (! am_system_init || strcmp(argv[i], "auto") != 0) {
210 services_to_start.push_back(argv[i]);
216 if (am_system_init) {
217 // setup STDIN, STDOUT, STDERR so that we can use them
218 int onefd = open("/dev/console", O_RDONLY, 0);
220 int twofd = open("/dev/console", O_RDWR, 0);
224 if (onefd > 2) close(onefd);
225 if (twofd > 2) close(twofd);
228 /* Set up signal handlers etc */
229 /* SIG_CHILD is ignored by default: good */
230 sigset_t sigwait_set;
231 sigemptyset(&sigwait_set);
232 sigaddset(&sigwait_set, SIGCHLD);
233 sigaddset(&sigwait_set, SIGINT);
234 sigaddset(&sigwait_set, SIGTERM);
235 sigprocmask(SIG_BLOCK, &sigwait_set, NULL);
237 // Terminal access control signals - we block these so that dinit can't be
238 // suspended if it writes to the terminal after some other process has claimed
240 signal(SIGTSTP, SIG_IGN);
241 signal(SIGTTIN, SIG_IGN);
242 signal(SIGTTOU, SIG_IGN);
244 signal(SIGPIPE, SIG_IGN);
246 if (! am_system_init && ! control_socket_path_set) {
247 const char * userhome = get_user_home();
248 if (userhome != nullptr) {
249 control_socket_str = userhome;
250 control_socket_str += "/.dinitctl";
251 control_socket_path = control_socket_str.c_str();
255 /* service directory name */
256 if (service_dir == nullptr && ! am_system_init) {
257 const char * userhome = get_user_home();
258 if (userhome != nullptr) {
259 service_dir_str = get_user_home();
260 service_dir_str += "/dinit.d";
261 service_dir = service_dir_str.c_str();
265 if (service_dir == nullptr) {
266 service_dir = "/etc/dinit.d";
269 if (services_to_start.empty()) {
270 services_to_start.push_back("boot");
273 // Set up signal handlers
274 CallbackSignalHandler sigint_watcher;
275 if (am_system_init) {
276 sigint_watcher.setCbFunc(sigint_reboot_cb);
279 sigint_watcher.setCbFunc(sigterm_cb);
282 CallbackSignalHandler sigquit_watcher;
283 if (am_system_init) {
284 // PID 1: SIGQUIT exec's shutdown
285 sigquit_watcher.setCbFunc(sigquit_cb);
288 // Otherwise: SIGQUIT terminates dinit
289 sigquit_watcher.setCbFunc(sigterm_cb);
292 CallbackSignalHandler sigterm_watcher {sigterm_cb};
294 sigint_watcher.add_watch(eventLoop, SIGINT);
295 sigquit_watcher.add_watch(eventLoop, SIGQUIT);
296 sigterm_watcher.add_watch(eventLoop, SIGTERM);
298 // Try to open control socket (may fail due to readonly filesystem)
299 open_control_socket(false);
302 if (am_system_init) {
303 // Disable non-critical kernel output to console
304 klogctl(6 /* SYSLOG_ACTION_CONSOLE_OFF */, nullptr, 0);
305 // Make ctrl+alt+del combination send SIGINT to PID 1 (this process)
306 reboot(RB_DISABLE_CAD);
310 /* start requested services */
311 service_set = new ServiceSet(service_dir);
313 init_log(service_set);
315 for (list<const char *>::iterator i = services_to_start.begin();
316 i != services_to_start.end();
319 service_set->startService(*i);
321 catch (ServiceNotFound &snf) {
322 log(LogLevel::ERROR, snf.serviceName, ": Could not find service description.");
324 catch (ServiceLoadExc &sle) {
325 log(LogLevel::ERROR, sle.serviceName, ": ", sle.excDescription);
327 catch (std::bad_alloc &badalloce) {
328 log(LogLevel::ERROR, "Out of memory when trying to start service: ", *i, ".");
334 // Process events until all services have terminated.
335 while (service_set->count_active_services() != 0) {
339 ShutdownType shutdown_type = service_set->getShutdownType();
341 if (am_system_init) {
342 logMsgBegin(LogLevel::INFO, "No more active services.");
344 if (shutdown_type == ShutdownType::REBOOT) {
345 logMsgEnd(" Will reboot.");
347 else if (shutdown_type == ShutdownType::HALT) {
348 logMsgEnd(" Will halt.");
350 else if (shutdown_type == ShutdownType::POWEROFF) {
351 logMsgEnd(" Will power down.");
354 logMsgEnd(" Re-initiating boot sequence.");
358 while (! is_log_flushed()) {
362 close_control_socket();
364 if (am_system_init) {
365 if (shutdown_type == ShutdownType::CONTINUE) {
366 // It could be that we started in single user mode, and the
367 // user has now exited the shell. We'll try and re-start the
370 service_set->startService("boot");
371 goto event_loop; // yes, the "evil" goto
374 // Now WTF do we do? try to reboot
375 log(LogLevel::ERROR, "Could not start 'boot' service; rebooting.");
376 shutdown_type = ShutdownType::REBOOT;
380 const char * cmd_arg;
381 if (shutdown_type == ShutdownType::HALT) {
384 else if (shutdown_type == ShutdownType::REBOOT) {
392 // Fork and execute dinit-reboot.
393 execl("/sbin/shutdown", "/sbin/shutdown", "--system", cmd_arg, nullptr);
394 log(LogLevel::ERROR, "Could not execute /sbin/shutdown: ", strerror(errno));
396 // PID 1 must not actually exit, although we should never reach this point:
405 // Callback for control socket
406 static void control_socket_cb(EventLoop_t *loop, int sockfd)
408 // TODO limit the number of active connections. Keep a tally, and disable the
409 // control connection listening socket watcher if it gets high, and re-enable
410 // it once it falls below the maximum.
412 // Accept a connection
413 int newfd = accept4(sockfd, nullptr, nullptr, SOCK_NONBLOCK | SOCK_CLOEXEC);
417 new ControlConn(loop, service_set, newfd); // will delete itself when it's finished
419 catch (std::exception &exc) {
420 log(LogLevel::ERROR, "Accepting control connection: ", exc.what());
426 void open_control_socket(bool report_ro_failure) noexcept
428 if (! control_socket_open) {
429 const char * saddrname = control_socket_path;
430 size_t saddrname_len = strlen(saddrname);
431 uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + saddrname_len + 1;
433 struct sockaddr_un * name = static_cast<sockaddr_un *>(malloc(sockaddr_size));
434 if (name == nullptr) {
435 log(LogLevel::ERROR, "Opening control socket: out of memory");
439 if (am_system_init) {
440 // Unlink any stale control socket file, but only if we are system init, since otherwise
441 // the 'stale' file may not be stale at all:
445 name->sun_family = AF_UNIX;
446 memcpy(name->sun_path, saddrname, saddrname_len + 1);
448 // OpenBSD and Linux both allow combining NONBLOCK/CLOEXEC flags with socket type, however
449 // it's not actually POSIX. (TODO).
450 int sockfd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
452 log(LogLevel::ERROR, "Error creating control socket: ", strerror(errno));
457 if (bind(sockfd, (struct sockaddr *) name, sockaddr_size) == -1) {
458 if (errno != EROFS || report_ro_failure) {
459 log(LogLevel::ERROR, "Error binding control socket: ", strerror(errno));
468 // No connections can be made until we listen, so it is fine to change the permissions now
469 // (and anyway there is no way to atomically create the socket and set permissions):
470 if (chmod(saddrname, S_IRUSR | S_IWUSR) == -1) {
471 log(LogLevel::ERROR, "Error setting control socket permissions: ", strerror(errno));
476 if (listen(sockfd, 10) == -1) {
477 log(LogLevel::ERROR, "Error listening on control socket: ", strerror(errno));
483 control_socket_io.add_watch(eventLoop, sockfd, IN_EVENTS);
484 control_socket_open = true;
486 catch (std::exception &e)
488 log(LogLevel::ERROR, "Could not setup I/O on control socket: ", e.what());
494 static void close_control_socket() noexcept
496 if (control_socket_open) {
497 int fd = control_socket_io.get_watched_fd();
498 control_socket_io.deregister(eventLoop);
501 // Unlink the socket:
502 unlink(control_socket_path);
506 void setup_external_log() noexcept
508 if (! external_log_open) {
510 const char * saddrname = log_socket_path;
511 size_t saddrname_len = strlen(saddrname);
512 uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + saddrname_len + 1;
514 struct sockaddr_un * name = static_cast<sockaddr_un *>(malloc(sockaddr_size));
515 if (name == nullptr) {
516 log(LogLevel::ERROR, "Connecting to log socket: out of memory");
520 name->sun_family = AF_UNIX;
521 memcpy(name->sun_path, saddrname, saddrname_len + 1);
523 int sockfd = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
525 log(LogLevel::ERROR, "Error creating log socket: ", strerror(errno));
530 if (connect(sockfd, (struct sockaddr *) name, sockaddr_size) == 0 || errno == EINPROGRESS) {
531 // TODO for EINPROGRESS, set up a watcher so we can properly wait until
532 // connection is established (or fails) before we pass it to the logging subsystem.
534 setup_main_log(sockfd);
536 catch (std::exception &e) {
537 log(LogLevel::ERROR, "Setting up log failed: ", e.what());
542 // Note if connect fails, we haven't warned at all, because the syslog server might not
551 /* handle SIGINT signal (generated by kernel when ctrl+alt+del pressed) */
552 static void sigint_reboot_cb(EventLoop_t *eloop) noexcept
554 service_set->stop_all_services(ShutdownType::REBOOT);
557 /* handle SIGQUIT (if we are system init) */
558 static void sigquit_cb(EventLoop_t *eloop) noexcept
560 // This performs an immediate shutdown, without service rollback.
561 close_control_socket();
562 execl("/sbin/shutdown", "/sbin/shutdown", "--system", (char *) 0);
563 log(LogLevel::ERROR, "Error executing /sbin/shutdown: ", strerror(errno));
566 /* handle SIGTERM/SIGQUIT(non-system-daemon) - stop all services and shut down */
567 static void sigterm_cb(EventLoop_t *eloop) noexcept
569 service_set->stop_all_services();