dinit.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. #include <iostream>
  2. #include <list>
  3. #include <cstring>
  4. #include <csignal>
  5. #include <cstddef>
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #include <sys/un.h>
  9. #include <sys/socket.h>
  10. #include <unistd.h>
  11. #include <fcntl.h>
  12. #include "service.h"
  13. #include "ev++.h"
  14. #include "control.h"
  15. #include "dinit-log.h"
  16. /* TODO: prevent services from respawning too quickly */
  17. /* TODO: detect/guard against dependency cycles */
  18. /* TODO: optional automatic restart of services */
  19. /*
  20. * "simpleinit" from util-linux package handles signals as follows:
  21. * SIGTSTP - spawn no more gettys (in preparation for shutdown etc).
  22. * In dinit terms this should probably mean "no more auto restarts"
  23. * (for any service). (Actually the signal acts as a toggle, if
  24. * respawn is disabled it will be re-enabled and init will
  25. * act as if SIGHUP had also been sent)
  26. * SIGTERM - kill spawned gettys (which are still alive)
  27. * Interestingly, simpleinit just sends a SIGTERM to the gettys.
  28. * "shutdown" however has already sent SIGTERM to every process...
  29. * "/sbin/initctl -r" - rollback services (ran by "shutdown"/halt etc)
  30. * shouldn't return until all services have been stopped.
  31. * shutdown calls this *after* sending SIGTERM to all processes.
  32. * I guess this allows user processes, if any are still around,
  33. * to die before (or just as) the services fall out from underneath
  34. * them. On the other hand it largely subverts the ordered service
  35. * shutdown that init provides.
  36. * SIGQUIT - init will exec() shutdown. shutdown will detect that it is
  37. * running as pid 1 and will just loop and reap child processes.
  38. * This is used by shutdown so that init will not hang on to its
  39. * inode, allowing the filesystem to be re-mounted readonly
  40. * (this is only an issue if the init binary has been unlinked,
  41. * since it's then holding an inode which can't be maintained
  42. * when the filesystem is unmounted).
  43. *
  44. * Not sent by shutdown:
  45. * SIGHUP - re-read inittab and spawn any new getty entries
  46. * SIGINT - (ctrl+alt+del handler) - fork & exec "reboot"
  47. *
  48. * On the contrary dinit currently uses:
  49. * SIGTERM - roll back services and then fork/exec /sbin/halt
  50. * SIGINT - roll back services and then fork/exec /sbin/reboot
  51. *
  52. * It's an open question about whether dinit should roll back services *before*
  53. * running halt/reboot, since those commands should prompt rollback of services
  54. * anyway. But it seems safe to do so.
  55. */
  56. static bool got_sigterm = false;
  57. static ServiceSet *service_set;
  58. static bool am_system_init = false; // true if we are the system init process
  59. static bool reboot = false; // whether to reboot (instead of halting)
  60. static bool control_socket_open = false;
  61. static void sigint_reboot_cb(struct ev_loop *loop, ev_signal *w, int revents);
  62. static void sigquit_cb(struct ev_loop *loop, ev_signal *w, int revents);
  63. static void sigterm_cb(struct ev_loop *loop, ev_signal *w, int revents);
  64. void open_control_socket(struct ev_loop *loop);
  65. struct ev_io control_socket_io;
  66. int main(int argc, char **argv)
  67. {
  68. using namespace std;
  69. am_system_init = (getpid() == 1);
  70. if (am_system_init) {
  71. // setup STDIN, STDOUT, STDERR so that we can use them
  72. int onefd = open("/dev/console", O_RDONLY, 0);
  73. dup2(onefd, 0);
  74. int twofd = open("/dev/console", O_RDWR, 0);
  75. dup2(twofd, 1);
  76. dup2(twofd, 2);
  77. }
  78. /* Set up signal handlers etc */
  79. /* SIG_CHILD is ignored by default: good */
  80. /* sigemptyset(&sigwait_set); */
  81. /* sigaddset(&sigwait_set, SIGCHLD); */
  82. /* sigaddset(&sigwait_set, SIGINT); */
  83. /* sigaddset(&sigwait_set, SIGTERM); */
  84. /* sigprocmask(SIG_BLOCK, &sigwait_set, NULL); */
  85. /* list of services to start */
  86. list<const char *> services_to_start;
  87. /* service directory name */
  88. const char * service_dir = "/etc/dinit.d";
  89. // Arguments, if given, specify a list of services to start.
  90. // If we are running as init (PID=1), the kernel gives us any command line
  91. // arguments it was given but didn't recognize, including "single" (usually
  92. // for "boot to single user mode" aka just start the shell). We can treat
  93. // them as service names. In the worst case we can't find any of the named
  94. // services, and so we'll start the "boot" service by default.
  95. if (argc > 1) {
  96. for (int i = 1; i < argc; i++) {
  97. if (argv[i][0] == '-') {
  98. // An option...
  99. if (strcmp(argv[i], "--services-dir") == 0 ||
  100. strcmp(argv[i], "-d") == 0) {
  101. ++i;
  102. if (i < argc) {
  103. service_dir = argv[i];
  104. }
  105. else {
  106. // error TODO
  107. }
  108. }
  109. else if (strcmp(argv[i], "--help") == 0) {
  110. cout << "dinit, an init with dependency management" << endl;
  111. cout << " --help : display help" << endl;
  112. cout << " --services-dir <dir>, -d <dir> : set base directory for service description files (-d <dir>)" << endl;
  113. cout << " <service-name> : start service with name <service-name>" << endl;
  114. return 0;
  115. }
  116. else {
  117. // unrecognized
  118. if (! am_system_init) {
  119. cerr << "Unrecognized option: " << argv[i] << endl;
  120. return 1;
  121. }
  122. }
  123. }
  124. else {
  125. // LILO puts "auto" on the kernel command line for unattended boots; we'll filter it.
  126. if (! am_system_init || strcmp(argv[i], "auto") != 0) {
  127. services_to_start.push_back(argv[i]);
  128. }
  129. }
  130. }
  131. }
  132. if (services_to_start.empty()) {
  133. services_to_start.push_back("boot");
  134. }
  135. // Set up signal handlers
  136. ev_signal sigint_ev_signal;
  137. if (am_system_init) {
  138. ev_signal_init(&sigint_ev_signal, sigint_reboot_cb, SIGINT);
  139. }
  140. else {
  141. ev_signal_init(&sigint_ev_signal, sigterm_cb, SIGINT);
  142. }
  143. ev_signal sigquit_ev_signal;
  144. if (am_system_init) {
  145. // PID 1: SIGQUIT exec's shutdown
  146. ev_signal_init(&sigquit_ev_signal, sigquit_cb, SIGQUIT);
  147. }
  148. else {
  149. // Otherwise: SIGQUIT terminates dinit
  150. ev_signal_init(&sigquit_ev_signal, sigterm_cb, SIGQUIT);
  151. }
  152. ev_signal sigterm_ev_signal;
  153. ev_signal_init(&sigterm_ev_signal, sigterm_cb, SIGTERM);
  154. /* Set up libev */
  155. struct ev_loop *loop = ev_default_loop(EVFLAG_AUTO /* | EVFLAG_SIGNALFD */);
  156. ev_signal_start(loop, &sigint_ev_signal);
  157. ev_signal_start(loop, &sigquit_ev_signal);
  158. ev_signal_start(loop, &sigterm_ev_signal);
  159. // Try to open control socket (may fail due to readonly filesystem)
  160. open_control_socket(loop);
  161. /* start requested services */
  162. service_set = new ServiceSet(service_dir);
  163. for (list<const char *>::iterator i = services_to_start.begin();
  164. i != services_to_start.end();
  165. ++i) {
  166. try {
  167. service_set->startService(*i);
  168. }
  169. catch (ServiceNotFound &snf) {
  170. log(LogLevel::ERROR, "Could not find service description: " + snf.serviceName);
  171. // TODO catch bad_alloc
  172. }
  173. catch (ServiceLoadExc &sle) {
  174. log(LogLevel::ERROR, "Problem loading service description: " + sle.serviceName);
  175. // TODO catch bad_alloc
  176. }
  177. }
  178. event_loop:
  179. // Process events until all services have terminated.
  180. while (service_set->count_active_services() != 0) {
  181. ev_loop(loop, EVLOOP_ONESHOT);
  182. }
  183. if (am_system_init) {
  184. log(LogLevel::INFO, " No more active services.");
  185. if (reboot) {
  186. cout << " Will reboot.";
  187. }
  188. else if (got_sigterm) {
  189. cout << " Will halt.";
  190. }
  191. else {
  192. cout << " Re-initiating boot sequence.";
  193. }
  194. cout << endl;
  195. }
  196. if (am_system_init) {
  197. if (reboot) {
  198. // TODO log error from fork
  199. if (fork() == 0) {
  200. execl("/sbin/reboot", "/sbin/reboot", (char *) 0);
  201. }
  202. }
  203. else if (got_sigterm) {
  204. // TODO log error from fork
  205. if (fork() == 0) {
  206. execl("/sbin/halt", "/sbin/halt", (char *) 0);
  207. }
  208. }
  209. else {
  210. // Hmmmmmm.
  211. // It could be that we started in single user mode, and the
  212. // user has now exited the shell. We'll try and re-start the
  213. // boot process...
  214. try {
  215. service_set->startService("boot");
  216. goto event_loop; // yes, the "evil" goto
  217. }
  218. catch (...) {
  219. // Now WTF do we do? try and reboot
  220. log(LogLevel::ERROR, "Could not start 'boot' service; rebooting.");
  221. if (fork() == 0) {
  222. execl("/sbin/reboot", "/sbin/reboot", (char *) 0);
  223. }
  224. }
  225. }
  226. // PID 1 should never exit:
  227. while (true) {
  228. pause();
  229. }
  230. }
  231. return 0;
  232. }
  233. // Callback for control socket
  234. static void control_socket_cb(struct ev_loop *loop, ev_io *w, int revents)
  235. {
  236. // TODO limit the number of active connections. Keep a tally, and disable the
  237. // control connection listening socket watcher if it gets high, and re-enable
  238. // it once it falls below the maximum.
  239. // Accept a connection
  240. int sockfd = w->fd;
  241. int newfd = accept4(sockfd, nullptr, nullptr, SOCK_NONBLOCK | SOCK_CLOEXEC);
  242. if (newfd != -1) {
  243. new ControlConn(loop, service_set, newfd); // will delete itself when it's finished
  244. // TODO keep a set of control connections so that we can close them when
  245. // terminating?
  246. }
  247. }
  248. void open_control_socket(struct ev_loop *loop)
  249. {
  250. if (! control_socket_open) {
  251. // TODO make this use a per-user address if PID != 1, and make the address
  252. // overridable from the command line
  253. const char * saddrname = "/dev/dinitctl";
  254. struct sockaddr_un name;
  255. if (am_system_init) {
  256. unlink(saddrname);
  257. }
  258. name.sun_family = AF_UNIX;
  259. strcpy(name.sun_path, saddrname); // TODO make this safe for long names
  260. int namelen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(saddrname);
  261. int sockfd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
  262. if (sockfd == -1) {
  263. log(LogLevel::ERROR, std::string("Error creating control socket: ") + strerror(errno));
  264. // TODO catch/prevent bad_alloc
  265. return;
  266. }
  267. if (bind(sockfd, (struct sockaddr *) &name, namelen) == -1) {
  268. log(LogLevel::ERROR, std::string("Error binding control socket: ") + strerror(errno));
  269. // TODO catch/prevent bad_alloc
  270. close(sockfd);
  271. return;
  272. }
  273. // No connections can be made until we listen, so it is fine to change the permissions now
  274. // (and anyway there is no way to atomically create the socket and set permissions):
  275. if (chmod(saddrname, S_IRUSR | S_IWUSR) == -1) {
  276. log(LogLevel::ERROR, std::string("Error setting control socket permissions: ") + strerror(errno));
  277. // TODO catch/prevent bad_alloc
  278. close(sockfd);
  279. return;
  280. }
  281. if (listen(sockfd, 10) == -1) {
  282. log(LogLevel::ERROR, std::string("Error listening on control socket: ") + strerror(errno));
  283. // TODO catch/prevent bad_alloc
  284. close(sockfd);
  285. return;
  286. }
  287. control_socket_open = true;
  288. ev_io_init(&control_socket_io, control_socket_cb, sockfd, EV_READ);
  289. ev_io_start(loop, &control_socket_io);
  290. }
  291. }
  292. /* handle SIGINT signal (generated by kernel when ctrl+alt+del pressed) */
  293. static void sigint_reboot_cb(struct ev_loop *loop, ev_signal *w, int revents)
  294. {
  295. reboot = true;
  296. log_to_console = true;
  297. service_set->stop_all_services();
  298. }
  299. /* handle SIGQUIT (if we are system init) */
  300. static void sigquit_cb(struct ev_loop *loop, ev_signal *w, int revents)
  301. {
  302. // This allows remounting the filesystem read-only if the dinit binary has been
  303. // unlinked. In that case the kernel holds the binary open, so that it can't be
  304. // properly removed.
  305. execl("/sbin/shutdown", "/sbin/shutdown", (char *) 0);
  306. log(LogLevel::ERROR, std::string("Error executing /sbin/shutdown: ") + strerror(errno));
  307. // TODO catch/prevent bad_alloc
  308. }
  309. /* handle SIGTERM - stop all services */
  310. static void sigterm_cb(struct ev_loop *loop, ev_signal *w, int revents)
  311. {
  312. got_sigterm = true;
  313. log_to_console = true;
  314. service_set->stop_all_services();
  315. }