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 = EventLoop<NullMutex>;
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::FdWatcher
57 Rearm fdEvent(EventLoop_t &loop, int fd, int flags) override
59 control_socket_cb(&loop, fd);
64 // TODO the fd is already stored, must we really store it again...
67 void addWatch(EventLoop_t &loop, int fd, int flags)
70 EventLoop_t::FdWatcher::addWatch(loop, fd, flags);
74 ControlSocketWatcher control_socket_io;
79 static ServiceSet *service_set;
81 static bool am_system_init = false; // true if we are the system init process
83 static bool control_socket_open = false;
84 static bool external_log_open = false;
85 int active_control_conns = 0;
87 // Control socket path. We maintain a string (control_socket_str) in case we need
88 // to allocate storage, but control_socket_path is the authoritative value.
89 static const char *control_socket_path = "/dev/dinitctl";
90 static std::string control_socket_str;
92 static const char *log_socket_path = "/dev/log";
94 static const char *user_home_path = nullptr;
97 // Get user home (and set user_home_path). (The return may become invalid after
98 // changing the evironment (HOME variable) or using the getpwuid() function).
99 const char * get_user_home()
101 if (user_home_path == nullptr) {
102 user_home_path = getenv("HOME");
103 if (user_home_path == nullptr) {
104 struct passwd * pwuid_p = getpwuid(getuid());
105 if (pwuid_p != nullptr) {
106 user_home_path = pwuid_p->pw_dir;
110 return user_home_path;
115 class CallbackSignalHandler : public EventLoop_t::SignalWatcher
118 typedef void (*cb_func_t)(EventLoop_t *);
124 CallbackSignalHandler() : cb_func(nullptr) { }
125 CallbackSignalHandler(cb_func_t pcb_func) : cb_func(pcb_func) { }
127 void setCbFunc(cb_func_t cb_func)
129 this->cb_func = cb_func;
132 Rearm received(EventLoop_t &eloop, int signo, SigInfo_p siginfo) override
134 service_set->stop_all_services(ShutdownType::REBOOT);
139 class ControlSocketWatcher : public EventLoop_t::FdWatcher
141 Rearm fdEvent(EventLoop_t &loop, int fd, int flags)
143 control_socket_cb(&loop, fd);
149 int main(int argc, char **argv)
153 am_system_init = (getpid() == 1);
154 const char * service_dir = nullptr;
155 string service_dir_str; // to hold storage for above if necessary
156 bool control_socket_path_set = false;
158 // list of services to start
159 list<const char *> services_to_start;
161 // Arguments, if given, specify a list of services to start.
162 // If we are running as init (PID=1), the kernel gives us any command line
163 // arguments it was given but didn't recognize, including "single" (usually
164 // for "boot to single user mode" aka just start the shell). We can treat
165 // them as service names. In the worst case we can't find any of the named
166 // services, and so we'll start the "boot" service by default.
168 for (int i = 1; i < argc; i++) {
169 if (argv[i][0] == '-') {
171 if (strcmp(argv[i], "--services-dir") == 0 ||
172 strcmp(argv[i], "-d") == 0) {
174 service_dir = argv[i];
177 cerr << "dinit: '--services-dir' (-d) requires an argument" << endl;
181 else if (strcmp(argv[i], "--system") == 0 ||
182 strcmp(argv[i], "-s") == 0) {
183 am_system_init = true;
185 else if (strcmp(argv[i], "--socket-path") == 0 ||
186 strcmp(argv[i], "-p") == 0) {
188 control_socket_path = argv[i];
189 control_socket_path_set = true;
192 cerr << "dinit: '--socket-path' (-p) requires an argument" << endl;
196 else if (strcmp(argv[i], "--help") == 0) {
197 cout << "dinit, an init with dependency management" << endl;
198 cout << " --help display help" << endl;
199 cout << " --services-dir <dir>, -d <dir>" << endl;
200 cout << " set base directory for service description" << endl;
201 cout << " files (-d <dir>)" << endl;
202 cout << " --system, -s run as the system init process" << endl;
203 cout << " --socket-path <path>, -p <path>" << endl;
204 cout << " path to control socket" << endl;
205 cout << " <service-name> start service with name <service-name>" << endl;
210 if (! am_system_init) {
211 cerr << "dinit: Unrecognized option: " << argv[i] << endl;
217 // LILO puts "auto" on the kernel command line for unattended boots; we'll filter it.
218 if (! am_system_init || strcmp(argv[i], "auto") != 0) {
219 services_to_start.push_back(argv[i]);
225 if (am_system_init) {
226 // setup STDIN, STDOUT, STDERR so that we can use them
227 int onefd = open("/dev/console", O_RDONLY, 0);
229 int twofd = open("/dev/console", O_RDWR, 0);
233 if (onefd > 2) close(onefd);
234 if (twofd > 2) close(twofd);
237 /* Set up signal handlers etc */
238 /* SIG_CHILD is ignored by default: good */
239 sigset_t sigwait_set;
240 sigemptyset(&sigwait_set);
241 sigaddset(&sigwait_set, SIGCHLD);
242 sigaddset(&sigwait_set, SIGINT);
243 sigaddset(&sigwait_set, SIGTERM);
244 sigprocmask(SIG_BLOCK, &sigwait_set, NULL);
246 // Terminal access control signals - we block these so that dinit can't be
247 // suspended if it writes to the terminal after some other process has claimed
249 signal(SIGTSTP, SIG_IGN);
250 signal(SIGTTIN, SIG_IGN);
251 signal(SIGTTOU, SIG_IGN);
253 if (! am_system_init && ! control_socket_path_set) {
254 const char * userhome = get_user_home();
255 if (userhome != nullptr) {
256 control_socket_str = userhome;
257 control_socket_str += "/.dinitctl";
258 control_socket_path = control_socket_str.c_str();
262 /* service directory name */
263 if (service_dir == nullptr && ! am_system_init) {
264 const char * userhome = get_user_home();
265 if (userhome != nullptr) {
266 service_dir_str = get_user_home();
267 service_dir_str += "/dinit.d";
268 service_dir = service_dir_str.c_str();
272 if (service_dir == nullptr) {
273 service_dir = "/etc/dinit.d";
276 if (services_to_start.empty()) {
277 services_to_start.push_back("boot");
280 // Set up signal handlers
281 CallbackSignalHandler sigint_watcher;
282 if (am_system_init) {
283 sigint_watcher.setCbFunc(sigint_reboot_cb);
286 sigint_watcher.setCbFunc(sigterm_cb);
289 CallbackSignalHandler sigquit_watcher;
290 if (am_system_init) {
291 // PID 1: SIGQUIT exec's shutdown
292 sigquit_watcher.setCbFunc(sigquit_cb);
295 // Otherwise: SIGQUIT terminates dinit
296 sigquit_watcher.setCbFunc(sigterm_cb);
299 auto sigterm_watcher = CallbackSignalHandler(sigterm_cb);
301 sigint_watcher.addWatch(eventLoop, SIGINT);
302 sigquit_watcher.addWatch(eventLoop, SIGQUIT);
303 sigterm_watcher.addWatch(eventLoop, SIGTERM);
305 // Try to open control socket (may fail due to readonly filesystem)
306 open_control_socket(false);
309 if (am_system_init) {
310 // Disable non-critical kernel output to console
311 klogctl(6 /* SYSLOG_ACTION_CONSOLE_OFF */, nullptr, 0);
312 // Make ctrl+alt+del combination send SIGINT to PID 1 (this process)
313 reboot(RB_DISABLE_CAD);
317 /* start requested services */
318 service_set = new ServiceSet(service_dir);
320 init_log(service_set);
322 for (list<const char *>::iterator i = services_to_start.begin();
323 i != services_to_start.end();
326 service_set->startService(*i);
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: ", *i, ".");
341 // Process events until all services have terminated.
342 while (service_set->count_active_services() != 0) {
346 ShutdownType shutdown_type = service_set->getShutdownType();
348 if (am_system_init) {
349 logMsgBegin(LogLevel::INFO, "No more active services.");
351 if (shutdown_type == ShutdownType::REBOOT) {
352 logMsgEnd(" Will reboot.");
354 else if (shutdown_type == ShutdownType::HALT) {
355 logMsgEnd(" Will halt.");
357 else if (shutdown_type == ShutdownType::POWEROFF) {
358 logMsgEnd(" Will power down.");
361 logMsgEnd(" Re-initiating boot sequence.");
365 while (! is_log_flushed()) {
369 close_control_socket();
371 if (am_system_init) {
372 if (shutdown_type == ShutdownType::CONTINUE) {
373 // It could be that we started in single user mode, and the
374 // user has now exited the shell. We'll try and re-start the
377 service_set->startService("boot");
378 goto event_loop; // yes, the "evil" goto
381 // Now WTF do we do? try to reboot
382 log(LogLevel::ERROR, "Could not start 'boot' service; rebooting.");
383 shutdown_type = ShutdownType::REBOOT;
387 const char * cmd_arg;
388 if (shutdown_type == ShutdownType::HALT) {
391 else if (shutdown_type == ShutdownType::REBOOT) {
399 // Fork and execute dinit-reboot.
400 execl("/sbin/shutdown", "/sbin/shutdown", "--system", cmd_arg, nullptr);
401 log(LogLevel::ERROR, "Could not execute /sbin/shutdown: ", strerror(errno));
403 // PID 1 must not actually exit, although we should never reach this point:
412 // Callback for control socket
413 static void control_socket_cb(EventLoop_t *loop, int sockfd)
415 // TODO limit the number of active connections. Keep a tally, and disable the
416 // control connection listening socket watcher if it gets high, and re-enable
417 // it once it falls below the maximum.
419 // Accept a connection
420 int newfd = accept4(sockfd, nullptr, nullptr, SOCK_NONBLOCK | SOCK_CLOEXEC);
424 new ControlConn(loop, service_set, newfd); // will delete itself when it's finished
426 catch (std::exception &exc) {
427 log(LogLevel::ERROR, "Accepting control connection: ", exc.what());
433 void open_control_socket(bool report_ro_failure) noexcept
435 if (! control_socket_open) {
436 const char * saddrname = control_socket_path;
437 uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + strlen(saddrname) + 1;
439 struct sockaddr_un * name = static_cast<sockaddr_un *>(malloc(sockaddr_size));
440 if (name == nullptr) {
441 log(LogLevel::ERROR, "Opening control socket: out of memory");
445 if (am_system_init) {
446 // Unlink any stale control socket file, but only if we are system init, since otherwise
447 // the 'stale' file may not be stale at all:
451 name->sun_family = AF_UNIX;
452 strcpy(name->sun_path, saddrname);
454 // OpenBSD and Linux both allow combining NONBLOCK/CLOEXEC flags with socket type, however
455 // it's not actually POSIX. (TODO).
456 int sockfd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
458 log(LogLevel::ERROR, "Error creating control socket: ", strerror(errno));
463 if (bind(sockfd, (struct sockaddr *) name, sockaddr_size) == -1) {
464 if (errno != EROFS || report_ro_failure) {
465 log(LogLevel::ERROR, "Error binding control socket: ", strerror(errno));
474 // No connections can be made until we listen, so it is fine to change the permissions now
475 // (and anyway there is no way to atomically create the socket and set permissions):
476 if (chmod(saddrname, S_IRUSR | S_IWUSR) == -1) {
477 log(LogLevel::ERROR, "Error setting control socket permissions: ", strerror(errno));
482 if (listen(sockfd, 10) == -1) {
483 log(LogLevel::ERROR, "Error listening on control socket: ", strerror(errno));
489 control_socket_io.addWatch(eventLoop, sockfd, IN_EVENTS);
490 control_socket_open = true;
492 catch (std::exception &e)
494 log(LogLevel::ERROR, "Could not setup I/O on control socket: ", e.what());
500 static void close_control_socket() noexcept
502 if (control_socket_open) {
503 int fd = control_socket_io.fd;
504 control_socket_io.deregister(eventLoop);
507 // Unlink the socket:
508 unlink(control_socket_path);
512 void setup_external_log() noexcept
514 if (! external_log_open) {
516 const char * saddrname = log_socket_path;
517 uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + strlen(saddrname) + 1;
519 struct sockaddr_un * name = static_cast<sockaddr_un *>(malloc(sockaddr_size));
520 if (name == nullptr) {
521 log(LogLevel::ERROR, "Connecting to log socket: out of memory");
525 name->sun_family = AF_UNIX;
526 strcpy(name->sun_path, saddrname);
528 int sockfd = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
530 log(LogLevel::ERROR, "Error creating log socket: ", strerror(errno));
535 if (connect(sockfd, (struct sockaddr *) name, sockaddr_size) == 0 || errno == EINPROGRESS) {
536 // TODO for EINPROGRESS, set up a watcher so we can properly wait until
537 // connection is established (or fails) before we pass it to the logging subsystem.
539 setup_main_log(sockfd);
541 catch (std::exception &e) {
542 log(LogLevel::ERROR, "Setting up log failed: ", e.what());
547 // Note if connect fails, we haven't warned at all, because the syslog server might not
556 /* handle SIGINT signal (generated by kernel when ctrl+alt+del pressed) */
557 static void sigint_reboot_cb(EventLoop_t *eloop) noexcept
559 service_set->stop_all_services(ShutdownType::REBOOT);
562 /* handle SIGQUIT (if we are system init) */
563 static void sigquit_cb(EventLoop_t *eloop) noexcept
565 // This performs an immediate shutdown, without service rollback.
566 close_control_socket();
567 execl("/sbin/shutdown", "/sbin/shutdown", "--system", (char *) 0);
568 log(LogLevel::ERROR, "Error executing /sbin/shutdown: ", strerror(errno));
571 /* handle SIGTERM/SIGQUIT(non-system-daemon) - stop all services and shut down */
572 static void sigterm_cb(EventLoop_t *eloop) noexcept
574 service_set->stop_all_services();