11 #include <sys/socket.h>
19 #include "dinit-log.h"
20 #include "dinit-socket.h"
24 #include <sys/reboot.h>
28 * When running as the system init process, Dinit processes the following signals:
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
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.
40 using namespace dasynq;
41 using EventLoop_t = event_loop<null_mutex>;
43 EventLoop_t eventLoop = EventLoop_t();
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;
50 static void control_socket_cb(EventLoop_t *loop, int fd);
52 void open_control_socket(bool report_ro_failure = true) noexcept;
53 void setup_external_log() noexcept;
56 class ControlSocketWatcher : public EventLoop_t::fd_watcher_impl<ControlSocketWatcher>
59 rearm fd_event(EventLoop_t &loop, int fd, int flags) noexcept
61 control_socket_cb(&loop, fd);
66 ControlSocketWatcher control_socket_io;
71 static ServiceSet *service_set;
73 static bool am_system_init = false; // true if we are the system init process
75 static bool control_socket_open = false;
76 static bool external_log_open = false;
77 int active_control_conns = 0;
79 // Control socket path. We maintain a string (control_socket_str) in case we need
80 // to allocate storage, but control_socket_path is the authoritative value.
81 static const char *control_socket_path = "/dev/dinitctl";
82 static std::string control_socket_str;
84 static const char *log_socket_path = "/dev/log";
86 static const char *user_home_path = nullptr;
89 // Get user home (and set user_home_path). (The return may become invalid after
90 // changing the evironment (HOME variable) or using the getpwuid() function).
91 const char * get_user_home()
93 if (user_home_path == nullptr) {
94 user_home_path = getenv("HOME");
95 if (user_home_path == nullptr) {
96 struct passwd * pwuid_p = getpwuid(getuid());
97 if (pwuid_p != nullptr) {
98 user_home_path = pwuid_p->pw_dir;
102 return user_home_path;
107 class CallbackSignalHandler : public EventLoop_t::signal_watcher_impl<CallbackSignalHandler>
110 typedef void (*cb_func_t)(EventLoop_t &);
116 CallbackSignalHandler() : cb_func(nullptr) { }
117 CallbackSignalHandler(cb_func_t pcb_func) : cb_func(pcb_func) { }
119 void setCbFunc(cb_func_t cb_func)
121 this->cb_func = cb_func;
124 rearm received(EventLoop_t &eloop, int signo, siginfo_p siginfo)
131 class ControlSocketWatcher : public EventLoop_t::fd_watcher_impl<ControlSocketWatcher>
133 rearm fd_event(EventLoop_t &loop, int fd, int flags)
135 control_socket_cb(&loop, fd);
141 static int dinit_main(int argc, char **argv)
145 am_system_init = (getpid() == 1);
146 const char * service_dir = nullptr;
147 string service_dir_str; // to hold storage for above if necessary
148 bool control_socket_path_set = false;
150 // list of services to start
151 list<const char *> services_to_start;
153 // Arguments, if given, specify a list of services to start.
154 // If we are running as init (PID=1), the kernel gives us any command line
155 // arguments it was given but didn't recognize, including "single" (usually
156 // for "boot to single user mode" aka just start the shell). We can treat
157 // them as service names. In the worst case we can't find any of the named
158 // services, and so we'll start the "boot" service by default.
160 for (int i = 1; i < argc; i++) {
161 if (argv[i][0] == '-') {
163 if (strcmp(argv[i], "--services-dir") == 0 ||
164 strcmp(argv[i], "-d") == 0) {
166 service_dir = argv[i];
169 cerr << "dinit: '--services-dir' (-d) requires an argument" << endl;
173 else if (strcmp(argv[i], "--system") == 0 ||
174 strcmp(argv[i], "-s") == 0) {
175 am_system_init = true;
177 else if (strcmp(argv[i], "--socket-path") == 0 ||
178 strcmp(argv[i], "-p") == 0) {
180 control_socket_path = argv[i];
181 control_socket_path_set = true;
184 cerr << "dinit: '--socket-path' (-p) requires an argument" << endl;
188 else if (strcmp(argv[i], "--help") == 0) {
189 cout << "dinit, an init with dependency management" << endl;
190 cout << " --help display help" << endl;
191 cout << " --services-dir <dir>, -d <dir>" << endl;
192 cout << " set base directory for service description" << endl;
193 cout << " files (-d <dir>)" << endl;
194 cout << " --system, -s run as the system init process" << endl;
195 cout << " --socket-path <path>, -p <path>" << endl;
196 cout << " path to control socket" << endl;
197 cout << " <service-name> start service with name <service-name>" << endl;
202 if (! am_system_init) {
203 cerr << "dinit: Unrecognized option: " << argv[i] << endl;
210 // LILO puts "auto" on the kernel command line for unattended boots; we'll filter it.
211 if (! am_system_init || strcmp(argv[i], "auto") != 0) {
212 services_to_start.push_back(argv[i]);
219 if (am_system_init) {
220 // setup STDIN, STDOUT, STDERR so that we can use them
221 int onefd = open("/dev/console", O_RDONLY, 0);
223 int twofd = open("/dev/console", O_RDWR, 0);
227 if (onefd > 2) close(onefd);
228 if (twofd > 2) close(twofd);
231 /* Set up signal handlers etc */
232 /* SIG_CHILD is ignored by default: good */
233 sigset_t sigwait_set;
234 sigemptyset(&sigwait_set);
235 sigaddset(&sigwait_set, SIGCHLD);
236 sigaddset(&sigwait_set, SIGINT);
237 sigaddset(&sigwait_set, SIGTERM);
238 sigprocmask(SIG_BLOCK, &sigwait_set, NULL);
240 // Terminal access control signals - we block these so that dinit can't be
241 // suspended if it writes to the terminal after some other process has claimed
243 signal(SIGTSTP, SIG_IGN);
244 signal(SIGTTIN, SIG_IGN);
245 signal(SIGTTOU, SIG_IGN);
247 signal(SIGPIPE, SIG_IGN);
249 if (! am_system_init && ! control_socket_path_set) {
250 const char * userhome = get_user_home();
251 if (userhome != nullptr) {
252 control_socket_str = userhome;
253 control_socket_str += "/.dinitctl";
254 control_socket_path = control_socket_str.c_str();
258 /* service directory name */
259 if (service_dir == nullptr && ! am_system_init) {
260 const char * userhome = get_user_home();
261 if (userhome != nullptr) {
262 service_dir_str = get_user_home();
263 service_dir_str += "/dinit.d";
264 service_dir = service_dir_str.c_str();
268 if (service_dir == nullptr) {
269 service_dir = "/etc/dinit.d";
272 if (services_to_start.empty()) {
273 services_to_start.push_back("boot");
276 // Set up signal handlers
277 CallbackSignalHandler sigint_watcher;
278 if (am_system_init) {
279 sigint_watcher.setCbFunc(sigint_reboot_cb);
282 sigint_watcher.setCbFunc(sigterm_cb);
285 CallbackSignalHandler sigquit_watcher;
286 if (am_system_init) {
287 // PID 1: SIGQUIT exec's shutdown
288 sigquit_watcher.setCbFunc(sigquit_cb);
291 // Otherwise: SIGQUIT terminates dinit
292 sigquit_watcher.setCbFunc(sigterm_cb);
295 CallbackSignalHandler sigterm_watcher {sigterm_cb};
297 sigint_watcher.add_watch(eventLoop, SIGINT);
298 sigquit_watcher.add_watch(eventLoop, SIGQUIT);
299 sigterm_watcher.add_watch(eventLoop, SIGTERM);
301 // Try to open control socket (may fail due to readonly filesystem)
302 open_control_socket(false);
305 if (am_system_init) {
306 // Disable non-critical kernel output to console
307 klogctl(6 /* SYSLOG_ACTION_CONSOLE_OFF */, nullptr, 0);
308 // Make ctrl+alt+del combination send SIGINT to PID 1 (this process)
309 reboot(RB_DISABLE_CAD);
313 /* start requested services */
314 service_set = new ServiceSet(service_dir);
316 init_log(service_set);
318 for (auto svc : services_to_start) {
320 service_set->startService(svc);
321 // Note in general if we fail to start a service we don't need any special error handling,
322 // since we either leave other services running or, if it was the only service, then no
323 // services will be running and we will process normally (reboot if system process,
324 // exit if user process).
326 catch (ServiceNotFound &snf) {
327 log(LogLevel::ERROR, snf.serviceName, ": Could not find service description.");
329 catch (ServiceLoadExc &sle) {
330 log(LogLevel::ERROR, sle.serviceName, ": ", sle.excDescription);
332 catch (std::bad_alloc &badalloce) {
333 log(LogLevel::ERROR, "Out of memory when trying to start service: ", svc, ".");
340 // Process events until all services have terminated.
341 while (service_set->count_active_services() != 0) {
345 ShutdownType shutdown_type = service_set->getShutdownType();
347 if (am_system_init) {
348 logMsgBegin(LogLevel::INFO, "No more active services.");
350 if (shutdown_type == ShutdownType::REBOOT) {
351 logMsgEnd(" Will reboot.");
353 else if (shutdown_type == ShutdownType::HALT) {
354 logMsgEnd(" Will halt.");
356 else if (shutdown_type == ShutdownType::POWEROFF) {
357 logMsgEnd(" Will power down.");
360 logMsgEnd(" Re-initiating boot sequence.");
364 while (! is_log_flushed()) {
368 close_control_socket();
370 if (am_system_init) {
371 if (shutdown_type == ShutdownType::CONTINUE) {
372 // It could be that we started in single user mode, and the
373 // user has now exited the shell. We'll try and re-start the
376 service_set->startService("boot");
377 goto event_loop; // yes, the "evil" goto
380 // Now WTF do we do? try to reboot
381 log(LogLevel::ERROR, "Could not start 'boot' service; rebooting.");
382 shutdown_type = ShutdownType::REBOOT;
386 const char * cmd_arg;
387 if (shutdown_type == ShutdownType::HALT) {
390 else if (shutdown_type == ShutdownType::REBOOT) {
398 // Fork and execute dinit-reboot.
399 execl("/sbin/shutdown", "/sbin/shutdown", "--system", cmd_arg, nullptr);
400 log(LogLevel::ERROR, "Could not execute /sbin/shutdown: ", strerror(errno));
402 // PID 1 must not actually exit, although we should never reach this point:
411 int main(int argc, char **argv)
414 return dinit_main(argc, argv);
416 catch (std::bad_alloc &badalloc) {
417 std::cout << "dinit: Out-of-memory during initialisation" << std::endl;
420 catch (std::system_error &syserr) {
421 std::cout << "dinit: unexpected system error during initialisation: " << syserr.what() << std::endl;
425 std::cout << "dinit: unexpected error during initialisation" << std::endl;
430 // Callback for control socket
431 static void control_socket_cb(EventLoop_t *loop, int sockfd)
433 // TODO limit the number of active connections. Keep a tally, and disable the
434 // control connection listening socket watcher if it gets high, and re-enable
435 // it once it falls below the maximum.
437 // Accept a connection
438 int newfd = dinit_accept4(sockfd, nullptr, nullptr, SOCK_NONBLOCK | SOCK_CLOEXEC);
442 new ControlConn(loop, service_set, newfd); // will delete itself when it's finished
444 catch (std::exception &exc) {
445 log(LogLevel::ERROR, "Accepting control connection: ", exc.what());
451 void open_control_socket(bool report_ro_failure) noexcept
453 if (! control_socket_open) {
454 const char * saddrname = control_socket_path;
455 size_t saddrname_len = strlen(saddrname);
456 uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + saddrname_len + 1;
458 struct sockaddr_un * name = static_cast<sockaddr_un *>(malloc(sockaddr_size));
459 if (name == nullptr) {
460 log(LogLevel::ERROR, "Opening control socket: out of memory");
464 if (am_system_init) {
465 // Unlink any stale control socket file, but only if we are system init, since otherwise
466 // the 'stale' file may not be stale at all:
470 name->sun_family = AF_UNIX;
471 memcpy(name->sun_path, saddrname, saddrname_len + 1);
473 // OpenBSD and Linux both allow combining NONBLOCK/CLOEXEC flags with socket type, however
474 // it's not actually POSIX. (TODO).
475 int sockfd = dinit_socket(AF_UNIX, SOCK_STREAM, 0, SOCK_NONBLOCK | SOCK_CLOEXEC);
477 log(LogLevel::ERROR, "Error creating control socket: ", strerror(errno));
482 if (bind(sockfd, (struct sockaddr *) name, sockaddr_size) == -1) {
483 if (errno != EROFS || report_ro_failure) {
484 log(LogLevel::ERROR, "Error binding control socket: ", strerror(errno));
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));
501 if (listen(sockfd, 10) == -1) {
502 log(LogLevel::ERROR, "Error listening on control socket: ", strerror(errno));
508 control_socket_io.add_watch(eventLoop, sockfd, IN_EVENTS);
509 control_socket_open = true;
511 catch (std::exception &e)
513 log(LogLevel::ERROR, "Could not setup I/O on control socket: ", e.what());
519 static void close_control_socket() noexcept
521 if (control_socket_open) {
522 int fd = control_socket_io.get_watched_fd();
523 control_socket_io.deregister(eventLoop);
526 // Unlink the socket:
527 unlink(control_socket_path);
531 void setup_external_log() noexcept
533 if (! external_log_open) {
535 const char * saddrname = log_socket_path;
536 size_t saddrname_len = strlen(saddrname);
537 uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + saddrname_len + 1;
539 struct sockaddr_un * name = static_cast<sockaddr_un *>(malloc(sockaddr_size));
540 if (name == nullptr) {
541 log(LogLevel::ERROR, "Connecting to log socket: out of memory");
545 name->sun_family = AF_UNIX;
546 memcpy(name->sun_path, saddrname, saddrname_len + 1);
548 int sockfd = dinit_socket(AF_UNIX, SOCK_DGRAM, 0, SOCK_NONBLOCK | SOCK_CLOEXEC);
550 log(LogLevel::ERROR, "Error creating log socket: ", strerror(errno));
555 if (connect(sockfd, (struct sockaddr *) name, sockaddr_size) == 0 || errno == EINPROGRESS) {
556 // TODO for EINPROGRESS, set up a watcher so we can properly wait until
557 // connection is established (or fails) before we pass it to the logging subsystem.
559 setup_main_log(sockfd);
561 catch (std::exception &e) {
562 log(LogLevel::ERROR, "Setting up log failed: ", e.what());
567 // Note if connect fails, we haven't warned at all, because the syslog server might not
576 /* handle SIGINT signal (generated by kernel when ctrl+alt+del pressed) */
577 static void sigint_reboot_cb(EventLoop_t &eloop) noexcept
579 service_set->stop_all_services(ShutdownType::REBOOT);
582 /* handle SIGQUIT (if we are system init) */
583 static void sigquit_cb(EventLoop_t &eloop) noexcept
585 // This performs an immediate shutdown, without service rollback.
586 close_control_socket();
587 execl("/sbin/shutdown", "/sbin/shutdown", "--system", (char *) 0);
588 log(LogLevel::ERROR, "Error executing /sbin/shutdown: ", strerror(errno));
591 /* handle SIGTERM/SIGQUIT(non-system-daemon) - stop all services and shut down */
592 static void sigterm_cb(EventLoop_t &eloop) noexcept
594 service_set->stop_all_services();