11 #include <sys/socket.h>
19 #include "dinit-log.h"
23 #include <sys/reboot.h>
27 * "simpleinit" from util-linux-ng package handles signals as follows:
28 * SIGTSTP - spawn no more gettys (in preparation for shutdown etc).
29 * In dinit terms this should probably mean "no more auto restarts"
30 * (for any service). (Actually the signal acts as a toggle, if
31 * respawn is disabled it will be re-enabled and init will
32 * act as if SIGHUP had also been sent)
33 * SIGTERM - kill spawned gettys (which are still alive)
34 * Interestingly, simpleinit just sends a SIGTERM to the gettys,
35 * which will not normall kill shells (eg bash ignores SIGTERM).
36 * "/sbin/initctl -r" - rollback services (ran by "shutdown"/halt etc);
37 * shouldn't return until all services have been stopped.
38 * shutdown calls this after sending SIGTERM to processes running
39 * with uid >= 100 ("mortals").
40 * SIGQUIT - init will exec() shutdown. shutdown will detect that it is
41 * running as pid 1 and will just loop and reap child processes.
42 * This is used by shutdown so that init will not hang on to its
43 * inode, allowing the filesystem to be re-mounted readonly
44 * (this is only an issue if the init binary has been unlinked,
45 * since it's then holding an inode which can't be maintained
46 * when the filesystem is unmounted).
48 * Not sent by shutdown:
49 * SIGHUP - re-read inittab and spawn any new getty entries
50 * SIGINT - (ctrl+alt+del handler) - fork & exec "reboot"
52 * On the contrary dinit currently uses:
53 * SIGTERM - roll back services and then fork/exec /sbin/halt
54 * SIGINT - roll back services and then fork/exec /sbin/reboot
55 * SIGQUIT - exec() /sbin/shutdown as per above.
57 * It's an open question about whether dinit should roll back services *before*
58 * running halt/reboot, since those commands should prompt rollback of services
59 * anyway. But it seems safe to do so.
63 using namespace dasynq;
64 using EventLoop_t = EventLoop<NullMutex>;
66 EventLoop_t eventLoop = EventLoop_t();
68 static void sigint_reboot_cb(EventLoop_t *eloop) noexcept;
69 static void sigquit_cb(EventLoop_t *eloop) noexcept;
70 static void sigterm_cb(EventLoop_t *eloop) noexcept;
71 static void open_control_socket(EventLoop_t *loop) noexcept;
72 static void close_control_socket(EventLoop_t *loop) noexcept;
74 static void control_socket_cb(EventLoop_t *loop, int fd);
76 class ControlSocketWatcher : public FdWatcher<NullMutex>
78 Rearm gotEvent(EventLoop_t * loop, int fd, int flags)
80 control_socket_cb(loop, fd);
85 // TODO the fd is already stored, must we really store it again...
88 void registerWith(EventLoop_t * loop, int fd, int flags)
91 FdWatcher<NullMutex>::registerWith(loop, fd, flags);
95 ControlSocketWatcher control_socket_io;
100 static ServiceSet *service_set;
102 static bool am_system_init = false; // true if we are the system init process
104 static bool control_socket_open = false;
105 static bool external_log_open = false;
106 int active_control_conns = 0;
108 // Control socket path. We maintain a string (control_socket_str) in case we need
109 // to allocate storage, but control_socket_path is the authoritative value.
110 static const char *control_socket_path = "/dev/dinitctl";
111 static std::string control_socket_str;
113 static const char *log_socket_path = "/dev/log";
115 static const char *user_home_path = nullptr;
118 // Get user home (and set user_home_path). (The return may become invalid after
119 // changing the evironment (HOME variable) or using the getpwuid() function).
120 const char * get_user_home()
122 if (user_home_path == nullptr) {
123 user_home_path = getenv("HOME");
124 if (user_home_path == nullptr) {
125 struct passwd * pwuid_p = getpwuid(getuid());
126 if (pwuid_p != nullptr) {
127 user_home_path = pwuid_p->pw_dir;
131 return user_home_path;
136 class CallbackSignalHandler : public SignalWatcher<NullMutex>
139 typedef void (*cb_func_t)(EventLoop_t *);
145 CallbackSignalHandler() : cb_func(nullptr) { }
146 CallbackSignalHandler(cb_func_t pcb_func) : cb_func(pcb_func) { }
148 void setCbFunc(cb_func_t cb_func)
150 this->cb_func = cb_func;
153 Rearm gotSignal(EventLoop_t * eloop, int signo, SigInfo_p siginfo) override
155 service_set->stop_all_services(ShutdownType::REBOOT);
160 class ControlSocketWatcher : public FdWatcher<NullMutex>
162 Rearm gotEvent(EventLoop_t * loop, int fd, int flags)
164 control_socket_cb(loop, fd);
170 int main(int argc, char **argv)
174 am_system_init = (getpid() == 1);
175 const char * service_dir = nullptr;
176 string service_dir_str; // to hold storage for above if necessary
177 bool control_socket_path_set = false;
179 // list of services to start
180 list<const char *> services_to_start;
182 // Arguments, if given, specify a list of services to start.
183 // If we are running as init (PID=1), the kernel gives us any command line
184 // arguments it was given but didn't recognize, including "single" (usually
185 // for "boot to single user mode" aka just start the shell). We can treat
186 // them as service names. In the worst case we can't find any of the named
187 // services, and so we'll start the "boot" service by default.
189 for (int i = 1; i < argc; i++) {
190 if (argv[i][0] == '-') {
192 if (strcmp(argv[i], "--services-dir") == 0 ||
193 strcmp(argv[i], "-d") == 0) {
195 service_dir = argv[i];
198 cerr << "dinit: '--services-dir' (-d) requires an argument" << endl;
202 else if (strcmp(argv[i], "--system") == 0 ||
203 strcmp(argv[i], "-s") == 0) {
204 am_system_init = true;
206 else if (strcmp(argv[i], "--socket-path") == 0 ||
207 strcmp(argv[i], "-p") == 0) {
209 control_socket_path = argv[i];
210 control_socket_path_set = true;
213 cerr << "dinit: '--socket-path' (-p) requires an argument" << endl;
217 else if (strcmp(argv[i], "--help") == 0) {
218 cout << "dinit, an init with dependency management" << endl;
219 cout << " --help display help" << 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;
231 if (! am_system_init) {
232 cerr << "dinit: Unrecognized option: " << argv[i] << endl;
238 // LILO puts "auto" on the kernel command line for unattended boots; we'll filter it.
239 if (! am_system_init || strcmp(argv[i], "auto") != 0) {
240 services_to_start.push_back(argv[i]);
246 if (am_system_init) {
247 // setup STDIN, STDOUT, STDERR so that we can use them
248 int onefd = open("/dev/console", O_RDONLY, 0);
250 int twofd = open("/dev/console", O_RDWR, 0);
254 if (onefd > 2) close(onefd);
255 if (twofd > 2) close(twofd);
258 /* Set up signal handlers etc */
259 /* SIG_CHILD is ignored by default: good */
260 sigset_t sigwait_set;
261 sigemptyset(&sigwait_set);
262 sigaddset(&sigwait_set, SIGCHLD);
263 sigaddset(&sigwait_set, SIGINT);
264 sigaddset(&sigwait_set, SIGTERM);
265 sigprocmask(SIG_BLOCK, &sigwait_set, NULL);
267 // Terminal access control signals - we block these so that dinit can't be
268 // suspended if it writes to the terminal after some other process has claimed
270 signal(SIGTSTP, SIG_IGN);
271 signal(SIGTTIN, SIG_IGN);
272 signal(SIGTTOU, SIG_IGN);
274 if (! am_system_init && ! control_socket_path_set) {
275 const char * userhome = get_user_home();
276 if (userhome != nullptr) {
277 control_socket_str = userhome;
278 control_socket_str += "/.dinitctl";
279 control_socket_path = control_socket_str.c_str();
283 /* service directory name */
284 if (service_dir == nullptr && ! am_system_init) {
285 const char * userhome = get_user_home();
286 if (userhome != nullptr) {
287 service_dir_str = get_user_home();
288 service_dir_str += "/dinit.d";
289 service_dir = service_dir_str.c_str();
293 if (service_dir == nullptr) {
294 service_dir = "/etc/dinit.d";
297 if (services_to_start.empty()) {
298 services_to_start.push_back("boot");
301 // Set up signal handlers
302 CallbackSignalHandler sigint_watcher;
303 if (am_system_init) {
304 sigint_watcher.setCbFunc(sigint_reboot_cb);
307 sigint_watcher.setCbFunc(sigterm_cb);
310 CallbackSignalHandler sigquit_watcher;
311 if (am_system_init) {
312 // PID 1: SIGQUIT exec's shutdown
313 sigquit_watcher.setCbFunc(sigquit_cb);
316 // Otherwise: SIGQUIT terminates dinit
317 sigquit_watcher.setCbFunc(sigterm_cb);
320 auto sigterm_watcher = CallbackSignalHandler(sigterm_cb);
322 sigint_watcher.registerWatch(&eventLoop, SIGINT);
323 sigquit_watcher.registerWatch(&eventLoop, SIGQUIT);
324 sigterm_watcher.registerWatch(&eventLoop, SIGTERM);
326 // Try to open control socket (may fail due to readonly filesystem)
327 open_control_socket(&eventLoop);
330 if (am_system_init) {
331 // Disable non-critical kernel output to console
332 klogctl(6 /* SYSLOG_ACTION_CONSOLE_OFF */, nullptr, 0);
333 // Make ctrl+alt+del combination send SIGINT to PID 1 (this process)
334 reboot(RB_DISABLE_CAD);
338 /* start requested services */
339 service_set = new ServiceSet(service_dir);
341 init_log(service_set);
343 for (list<const char *>::iterator i = services_to_start.begin();
344 i != services_to_start.end();
347 service_set->startService(*i);
349 catch (ServiceNotFound &snf) {
350 log(LogLevel::ERROR, snf.serviceName, ": Could not find service description.");
352 catch (ServiceLoadExc &sle) {
353 log(LogLevel::ERROR, sle.serviceName, ": ", sle.excDescription);
355 catch (std::bad_alloc &badalloce) {
356 log(LogLevel::ERROR, "Out of memory when trying to start service: ", *i, ".");
362 // Process events until all services have terminated.
363 while (service_set->count_active_services() != 0) {
367 ShutdownType shutdown_type = service_set->getShutdownType();
369 if (am_system_init) {
370 logMsgBegin(LogLevel::INFO, "No more active services.");
372 if (shutdown_type == ShutdownType::REBOOT) {
373 logMsgEnd(" Will reboot.");
375 else if (shutdown_type == ShutdownType::HALT) {
376 logMsgEnd(" Will halt.");
378 else if (shutdown_type == ShutdownType::POWEROFF) {
379 logMsgEnd(" Will power down.");
382 logMsgEnd(" Re-initiating boot sequence.");
386 while (! is_log_flushed()) {
390 close_control_socket(&eventLoop);
392 if (am_system_init) {
393 if (shutdown_type == ShutdownType::CONTINUE) {
394 // It could be that we started in single user mode, and the
395 // user has now exited the shell. We'll try and re-start the
398 service_set->startService("boot");
399 goto event_loop; // yes, the "evil" goto
402 // Now WTF do we do? try to reboot
403 log(LogLevel::ERROR, "Could not start 'boot' service; rebooting.");
404 shutdown_type = ShutdownType::REBOOT;
408 const char * cmd_arg;
409 if (shutdown_type == ShutdownType::HALT) {
412 else if (shutdown_type == ShutdownType::REBOOT) {
420 // Fork and execute dinit-reboot.
421 execl("/sbin/shutdown", "/sbin/shutdown", "--system", cmd_arg, nullptr);
422 log(LogLevel::ERROR, "Could not execute /sbin/shutdown: ", strerror(errno));
424 // PID 1 must not actually exit, although we should never reach this point:
433 // Callback for control socket
434 static void control_socket_cb(EventLoop_t *loop, int sockfd)
436 // TODO limit the number of active connections. Keep a tally, and disable the
437 // control connection listening socket watcher if it gets high, and re-enable
438 // it once it falls below the maximum.
440 // Accept a connection
441 int newfd = accept4(sockfd, nullptr, nullptr, SOCK_NONBLOCK | SOCK_CLOEXEC);
445 new ControlConn(loop, service_set, newfd); // will delete itself when it's finished
447 catch (std::exception &exc) {
448 log(LogLevel::ERROR, "Accepting control connection: ", exc.what());
454 static void open_control_socket(EventLoop_t *loop) noexcept
456 if (! control_socket_open) {
457 const char * saddrname = control_socket_path;
458 uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + strlen(saddrname) + 1;
460 struct sockaddr_un * name = static_cast<sockaddr_un *>(malloc(sockaddr_size));
461 if (name == nullptr) {
462 log(LogLevel::ERROR, "Opening control socket: out of memory");
466 if (am_system_init) {
467 // Unlink any stale control socket file, but only if we are system init, since otherwise
468 // the 'stale' file may not be stale at all:
472 name->sun_family = AF_UNIX;
473 strcpy(name->sun_path, saddrname);
475 // OpenBSD and Linux both allow combining NONBLOCK/CLOEXEC flags with socket type, however
476 // it's not actually POSIX. (TODO).
477 int sockfd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
479 log(LogLevel::ERROR, "Error creating control socket: ", strerror(errno));
484 if (bind(sockfd, (struct sockaddr *) name, sockaddr_size) == -1) {
485 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));
507 control_socket_open = true;
508 control_socket_io.registerWith(&eventLoop, sockfd, IN_EVENTS);
512 static void close_control_socket(EventLoop_t *loop) noexcept
514 if (control_socket_open) {
515 int fd = control_socket_io.fd;
516 control_socket_io.deregisterWatch(&eventLoop);
519 // Unlink the socket:
520 unlink(control_socket_path);
524 static void setup_external_log() noexcept
526 if (! external_log_open) {
528 const char * saddrname = log_socket_path;
529 uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + strlen(saddrname) + 1;
531 struct sockaddr_un * name = static_cast<sockaddr_un *>(malloc(sockaddr_size));
532 if (name == nullptr) {
533 log(LogLevel::ERROR, "Connecting to log socket: out of memory");
537 name->sun_family = AF_UNIX;
538 strcpy(name->sun_path, saddrname);
540 int sockfd = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
542 log(LogLevel::ERROR, "Error creating log socket: ", strerror(errno));
547 if (connect(sockfd, (struct sockaddr *) name, sockaddr_size) == 0 || errno == EINPROGRESS) {
548 // TODO for EINPROGRESS, set up a watcher so we can properly wait until
549 // connection is established (or fails) before we pass it to the logging subsystem.
551 setup_main_log(sockfd);
553 catch (std::exception &e) {
554 log(LogLevel::ERROR, "Setting up log failed: ", e.what());
559 // Note if connect fails, we haven't warned at all, because the syslog server might not
560 // have started yet. TODO, have a special startup flag to indicate when syslog should
569 // Called from service when the system is "rw ready" (filesystem mounted r/w etc).
570 // May be called more than once.
571 void system_rw_ready() noexcept
573 open_control_socket(&eventLoop);
574 setup_external_log();
577 /* handle SIGINT signal (generated by kernel when ctrl+alt+del pressed) */
578 static void sigint_reboot_cb(EventLoop_t *eloop) noexcept
580 service_set->stop_all_services(ShutdownType::REBOOT);
583 /* handle SIGQUIT (if we are system init) */
584 static void sigquit_cb(EventLoop_t *eloop) noexcept
586 // This allows remounting the filesystem read-only if the dinit binary has been
587 // unlinked. In that case the kernel holds the binary open, so that it can't be
589 close_control_socket(eloop);
590 execl("/sbin/shutdown", "/sbin/shutdown", (char *) 0);
591 log(LogLevel::ERROR, "Error executing /sbin/shutdown: ", strerror(errno));
594 /* handle SIGTERM/SIGQUIT - stop all services (not used for system daemon) */
595 static void sigterm_cb(EventLoop_t *eloop) noexcept
597 service_set->stop_all_services();