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, and it means the user can at least stop
37 * services even if the halt/reboot commands are unavailable for some reason.
41 using namespace dasynq;
42 using EventLoop_t = event_loop<null_mutex>;
44 EventLoop_t eventLoop = EventLoop_t();
46 static void sigint_reboot_cb(EventLoop_t &eloop) noexcept;
47 static void sigquit_cb(EventLoop_t &eloop) noexcept;
48 static void sigterm_cb(EventLoop_t &eloop) noexcept;
49 static void close_control_socket() noexcept;
50 static void wait_for_user_input() noexcept;
52 static void control_socket_cb(EventLoop_t *loop, int fd);
54 void open_control_socket(bool report_ro_failure = true) noexcept;
55 void setup_external_log() noexcept;
58 class ControlSocketWatcher : public EventLoop_t::fd_watcher_impl<ControlSocketWatcher>
61 rearm fd_event(EventLoop_t &loop, int fd, int flags) noexcept
63 control_socket_cb(&loop, fd);
68 ControlSocketWatcher control_socket_io;
73 static ServiceSet *service_set;
75 static bool am_system_init = false; // true if we are the system init process
77 static bool control_socket_open = false;
78 static bool external_log_open = false;
79 int active_control_conns = 0;
81 // Control socket path. We maintain a string (control_socket_str) in case we need
82 // to allocate storage, but control_socket_path is the authoritative value.
83 static const char *control_socket_path = "/dev/dinitctl";
84 static std::string control_socket_str;
86 static const char *log_socket_path = "/dev/log";
88 static const char *user_home_path = nullptr;
91 // Get user home (and set user_home_path). (The return may become invalid after
92 // changing the evironment (HOME variable) or using the getpwuid() function).
93 const char * get_user_home()
95 if (user_home_path == nullptr) {
96 user_home_path = getenv("HOME");
97 if (user_home_path == nullptr) {
98 struct passwd * pwuid_p = getpwuid(getuid());
99 if (pwuid_p != nullptr) {
100 user_home_path = pwuid_p->pw_dir;
104 return user_home_path;
109 class CallbackSignalHandler : public EventLoop_t::signal_watcher_impl<CallbackSignalHandler>
112 typedef void (*cb_func_t)(EventLoop_t &);
118 CallbackSignalHandler() : cb_func(nullptr) { }
119 CallbackSignalHandler(cb_func_t pcb_func) : cb_func(pcb_func) { }
121 void setCbFunc(cb_func_t cb_func)
123 this->cb_func = cb_func;
126 rearm received(EventLoop_t &eloop, int signo, siginfo_p siginfo)
133 class ControlSocketWatcher : public EventLoop_t::fd_watcher_impl<ControlSocketWatcher>
135 rearm fd_event(EventLoop_t &loop, int fd, int flags)
137 control_socket_cb(&loop, fd);
143 static int dinit_main(int argc, char **argv)
147 am_system_init = (getpid() == 1);
148 const char * service_dir = nullptr;
149 string service_dir_str; // to hold storage for above if necessary
150 bool control_socket_path_set = false;
152 // list of services to start
153 list<const char *> services_to_start;
155 // Arguments, if given, specify a list of services to start.
156 // If we are running as init (PID=1), the kernel gives us any command line
157 // arguments it was given but didn't recognize, including "single" (usually
158 // for "boot to single user mode" aka just start the shell). We can treat
159 // them as service names. In the worst case we can't find any of the named
160 // services, and so we'll start the "boot" service by default.
162 for (int i = 1; i < argc; i++) {
163 if (argv[i][0] == '-') {
165 if (strcmp(argv[i], "--services-dir") == 0 ||
166 strcmp(argv[i], "-d") == 0) {
168 service_dir = argv[i];
171 cerr << "dinit: '--services-dir' (-d) requires an argument" << endl;
175 else if (strcmp(argv[i], "--system") == 0 ||
176 strcmp(argv[i], "-s") == 0) {
177 am_system_init = true;
179 else if (strcmp(argv[i], "--socket-path") == 0 ||
180 strcmp(argv[i], "-p") == 0) {
182 control_socket_path = argv[i];
183 control_socket_path_set = true;
186 cerr << "dinit: '--socket-path' (-p) requires an argument" << endl;
190 else if (strcmp(argv[i], "--help") == 0) {
191 cout << "dinit, an init with dependency management" << endl;
192 cout << " --help display help" << endl;
193 cout << " --services-dir <dir>, -d <dir>" << endl;
194 cout << " set base directory for service description" << endl;
195 cout << " files (-d <dir>)" << endl;
196 cout << " --system, -s run as the system init process" << endl;
197 cout << " --socket-path <path>, -p <path>" << endl;
198 cout << " path to control socket" << endl;
199 cout << " <service-name> start service with name <service-name>" << endl;
204 if (! am_system_init) {
205 cerr << "dinit: Unrecognized option: " << argv[i] << endl;
212 // LILO puts "auto" on the kernel command line for unattended boots; we'll filter it.
213 if (! am_system_init || strcmp(argv[i], "auto") != 0) {
214 services_to_start.push_back(argv[i]);
221 if (am_system_init) {
222 // setup STDIN, STDOUT, STDERR so that we can use them
223 int onefd = open("/dev/console", O_RDONLY, 0);
225 int twofd = open("/dev/console", O_RDWR, 0);
229 if (onefd > 2) close(onefd);
230 if (twofd > 2) close(twofd);
233 /* Set up signal handlers etc */
234 /* SIG_CHILD is ignored by default: good */
235 sigset_t sigwait_set;
236 sigemptyset(&sigwait_set);
237 sigaddset(&sigwait_set, SIGCHLD);
238 sigaddset(&sigwait_set, SIGINT);
239 sigaddset(&sigwait_set, SIGTERM);
240 sigprocmask(SIG_BLOCK, &sigwait_set, NULL);
242 // Terminal access control signals - we block these so that dinit can't be
243 // suspended if it writes to the terminal after some other process has claimed
245 signal(SIGTSTP, SIG_IGN);
246 signal(SIGTTIN, SIG_IGN);
247 signal(SIGTTOU, SIG_IGN);
249 signal(SIGPIPE, SIG_IGN);
251 if (! am_system_init && ! control_socket_path_set) {
252 const char * userhome = get_user_home();
253 if (userhome != nullptr) {
254 control_socket_str = userhome;
255 control_socket_str += "/.dinitctl";
256 control_socket_path = control_socket_str.c_str();
260 /* service directory name */
261 if (service_dir == nullptr && ! am_system_init) {
262 const char * userhome = get_user_home();
263 if (userhome != nullptr) {
264 service_dir_str = get_user_home();
265 service_dir_str += "/dinit.d";
266 service_dir = service_dir_str.c_str();
270 if (service_dir == nullptr) {
271 service_dir = "/etc/dinit.d";
274 if (services_to_start.empty()) {
275 services_to_start.push_back("boot");
278 // Set up signal handlers
279 CallbackSignalHandler sigint_watcher;
280 if (am_system_init) {
281 sigint_watcher.setCbFunc(sigint_reboot_cb);
284 sigint_watcher.setCbFunc(sigterm_cb);
287 CallbackSignalHandler sigquit_watcher;
288 if (am_system_init) {
289 // PID 1: SIGQUIT exec's shutdown
290 sigquit_watcher.setCbFunc(sigquit_cb);
293 // Otherwise: SIGQUIT terminates dinit
294 sigquit_watcher.setCbFunc(sigterm_cb);
297 CallbackSignalHandler sigterm_watcher {sigterm_cb};
299 sigint_watcher.add_watch(eventLoop, SIGINT);
300 sigquit_watcher.add_watch(eventLoop, SIGQUIT);
301 sigterm_watcher.add_watch(eventLoop, SIGTERM);
303 // Try to open control socket (may fail due to readonly filesystem)
304 open_control_socket(false);
307 if (am_system_init) {
308 // Disable non-critical kernel output to console
309 klogctl(6 /* SYSLOG_ACTION_CONSOLE_OFF */, nullptr, 0);
310 // Make ctrl+alt+del combination send SIGINT to PID 1 (this process)
311 reboot(RB_DISABLE_CAD);
315 /* start requested services */
316 service_set = new ServiceSet(service_dir);
318 init_log(service_set);
320 for (auto svc : services_to_start) {
322 service_set->startService(svc);
323 // Note in general if we fail to start a service we don't need any special error handling,
324 // since we either leave other services running or, if it was the only service, then no
325 // services will be running and we will process normally (reboot if system process,
326 // exit if user process).
328 catch (ServiceNotFound &snf) {
329 log(LogLevel::ERROR, snf.serviceName, ": Could not find service description.");
331 catch (ServiceLoadExc &sle) {
332 log(LogLevel::ERROR, sle.serviceName, ": ", sle.excDescription);
334 catch (std::bad_alloc &badalloce) {
335 log(LogLevel::ERROR, "Out of memory when trying to start service: ", svc, ".");
342 // Process events until all services have terminated.
343 while (service_set->count_active_services() != 0) {
347 ShutdownType shutdown_type = service_set->getShutdownType();
349 if (am_system_init) {
350 logMsgBegin(LogLevel::INFO, "No more active services.");
352 if (shutdown_type == ShutdownType::REBOOT) {
353 logMsgEnd(" Will reboot.");
355 else if (shutdown_type == ShutdownType::HALT) {
356 logMsgEnd(" Will halt.");
358 else if (shutdown_type == ShutdownType::POWEROFF) {
359 logMsgEnd(" Will power down.");
362 logMsgEnd(" Re-initiating boot sequence.");
366 while (! is_log_flushed()) {
370 close_control_socket();
372 if (am_system_init) {
373 if (shutdown_type == ShutdownType::CONTINUE) {
374 // It could be that we started in single user mode, and the
375 // user has now exited the shell. We'll try and re-start the
378 service_set->startService("boot");
379 goto event_loop; // yes, the "evil" goto
382 // Now what do we do? try to reboot, but wait for user ack to avoid boot loop.
383 log(LogLevel::ERROR, "Could not start 'boot' service. Will attempt reboot.");
384 wait_for_user_input();
385 shutdown_type = ShutdownType::REBOOT;
389 const char * cmd_arg;
390 if (shutdown_type == ShutdownType::HALT) {
393 else if (shutdown_type == ShutdownType::REBOOT) {
401 // Fork and execute dinit-reboot.
402 execl("/sbin/shutdown", "/sbin/shutdown", "--system", cmd_arg, nullptr);
403 log(LogLevel::ERROR, "Could not execute /sbin/shutdown: ", strerror(errno));
405 // PID 1 must not actually exit, although we should never reach this point:
414 int main(int argc, char **argv)
417 return dinit_main(argc, argv);
419 catch (std::bad_alloc &badalloc) {
420 std::cout << "dinit: Out-of-memory during initialisation" << std::endl;
423 catch (std::system_error &syserr) {
424 std::cout << "dinit: unexpected system error during initialisation: " << syserr.what() << std::endl;
428 std::cout << "dinit: unexpected error during initialisation" << std::endl;
433 // In exception situations we want user confirmation before proceeding (eg on critical boot failure
434 // we wait before rebooting to avoid a reboot loop).
435 static void wait_for_user_input() noexcept
437 std::cout << "Press Enter to continue." << std::endl;
439 read(STDIN_FILENO, buf, 1);
442 // Callback for control socket
443 static void control_socket_cb(EventLoop_t *loop, int sockfd)
445 // TODO limit the number of active connections. Keep a tally, and disable the
446 // control connection listening socket watcher if it gets high, and re-enable
447 // it once it falls below the maximum.
449 // Accept a connection
450 int newfd = dinit_accept4(sockfd, nullptr, nullptr, SOCK_NONBLOCK | SOCK_CLOEXEC);
454 new ControlConn(loop, service_set, newfd); // will delete itself when it's finished
456 catch (std::exception &exc) {
457 log(LogLevel::ERROR, "Accepting control connection: ", exc.what());
463 void open_control_socket(bool report_ro_failure) noexcept
465 if (! control_socket_open) {
466 const char * saddrname = control_socket_path;
467 size_t saddrname_len = strlen(saddrname);
468 uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + saddrname_len + 1;
470 struct sockaddr_un * name = static_cast<sockaddr_un *>(malloc(sockaddr_size));
471 if (name == nullptr) {
472 log(LogLevel::ERROR, "Opening control socket: out of memory");
476 if (am_system_init) {
477 // Unlink any stale control socket file, but only if we are system init, since otherwise
478 // the 'stale' file may not be stale at all:
482 name->sun_family = AF_UNIX;
483 memcpy(name->sun_path, saddrname, saddrname_len + 1);
485 // OpenBSD and Linux both allow combining NONBLOCK/CLOEXEC flags with socket type, however
486 // it's not actually POSIX. (TODO).
487 int sockfd = dinit_socket(AF_UNIX, SOCK_STREAM, 0, SOCK_NONBLOCK | SOCK_CLOEXEC);
489 log(LogLevel::ERROR, "Error creating control socket: ", strerror(errno));
494 if (bind(sockfd, (struct sockaddr *) name, sockaddr_size) == -1) {
495 if (errno != EROFS || report_ro_failure) {
496 log(LogLevel::ERROR, "Error binding control socket: ", strerror(errno));
505 // No connections can be made until we listen, so it is fine to change the permissions now
506 // (and anyway there is no way to atomically create the socket and set permissions):
507 if (chmod(saddrname, S_IRUSR | S_IWUSR) == -1) {
508 log(LogLevel::ERROR, "Error setting control socket permissions: ", strerror(errno));
513 if (listen(sockfd, 10) == -1) {
514 log(LogLevel::ERROR, "Error listening on control socket: ", strerror(errno));
520 control_socket_io.add_watch(eventLoop, sockfd, IN_EVENTS);
521 control_socket_open = true;
523 catch (std::exception &e)
525 log(LogLevel::ERROR, "Could not setup I/O on control socket: ", e.what());
531 static void close_control_socket() noexcept
533 if (control_socket_open) {
534 int fd = control_socket_io.get_watched_fd();
535 control_socket_io.deregister(eventLoop);
538 // Unlink the socket:
539 unlink(control_socket_path);
543 void setup_external_log() noexcept
545 if (! external_log_open) {
547 const char * saddrname = log_socket_path;
548 size_t saddrname_len = strlen(saddrname);
549 uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + saddrname_len + 1;
551 struct sockaddr_un * name = static_cast<sockaddr_un *>(malloc(sockaddr_size));
552 if (name == nullptr) {
553 log(LogLevel::ERROR, "Connecting to log socket: out of memory");
557 name->sun_family = AF_UNIX;
558 memcpy(name->sun_path, saddrname, saddrname_len + 1);
560 int sockfd = dinit_socket(AF_UNIX, SOCK_DGRAM, 0, SOCK_NONBLOCK | SOCK_CLOEXEC);
562 log(LogLevel::ERROR, "Error creating log socket: ", strerror(errno));
567 if (connect(sockfd, (struct sockaddr *) name, sockaddr_size) == 0 || errno == EINPROGRESS) {
568 // TODO for EINPROGRESS, set up a watcher so we can properly wait until
569 // connection is established (or fails) before we pass it to the logging subsystem.
571 setup_main_log(sockfd);
573 catch (std::exception &e) {
574 log(LogLevel::ERROR, "Setting up log failed: ", e.what());
579 // Note if connect fails, we haven't warned at all, because the syslog server might not
588 /* handle SIGINT signal (generated by Linux kernel when ctrl+alt+del pressed) */
589 static void sigint_reboot_cb(EventLoop_t &eloop) noexcept
591 service_set->stop_all_services(ShutdownType::REBOOT);
594 /* handle SIGQUIT (if we are system init) */
595 static void sigquit_cb(EventLoop_t &eloop) noexcept
597 // This performs an immediate shutdown, without service rollback.
598 close_control_socket();
599 execl("/sbin/shutdown", "/sbin/shutdown", "--system", (char *) 0);
600 log(LogLevel::ERROR, "Error executing /sbin/shutdown: ", strerror(errno));
601 sync(); // since a hard poweroff might be required at this point...
604 /* handle SIGTERM/SIGQUIT(non-system-daemon) - stop all services and shut down */
605 static void sigterm_cb(EventLoop_t &eloop) noexcept
607 service_set->stop_all_services();