state.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /*
  2. * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
  3. * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU Lesser General Public License version 2.1
  7. * as published by the Free Software Foundation
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. */
  14. #include <fcntl.h>
  15. #include <pwd.h>
  16. #include <sys/reboot.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <unistd.h>
  20. #include <sys/types.h>
  21. #include <signal.h>
  22. #include "container.h"
  23. #include "procd.h"
  24. #include "syslog.h"
  25. #include "plug/hotplug.h"
  26. #include "watchdog.h"
  27. #include "service/service.h"
  28. #include "utils/utils.h"
  29. enum {
  30. STATE_NONE = 0,
  31. STATE_EARLY,
  32. STATE_UBUS,
  33. STATE_INIT,
  34. STATE_RUNNING,
  35. STATE_SHUTDOWN,
  36. STATE_HALT,
  37. __STATE_MAX,
  38. };
  39. static int state = STATE_NONE;
  40. static int reboot_event;
  41. static void set_stdio(const char* tty)
  42. {
  43. if (chdir("/dev") ||
  44. !freopen(tty, "r", stdin) ||
  45. !freopen(tty, "w", stdout) ||
  46. !freopen(tty, "w", stderr))
  47. ERROR("failed to set stdio: %m\n");
  48. else
  49. fcntl(STDERR_FILENO, F_SETFL, fcntl(STDERR_FILENO, F_GETFL) | O_NONBLOCK);
  50. if (chdir("/"))
  51. ERROR("failed to change dir to /: %m\n");
  52. }
  53. static void set_console(void)
  54. {
  55. const char* tty;
  56. char* split;
  57. char line[ 20 ];
  58. const char* try[] = { "tty0", "console", NULL }; /* Try the most common outputs */
  59. int f, i = 0;
  60. tty = get_cmdline_val("console",line,sizeof(line));
  61. if (tty != NULL) {
  62. split = strchr(tty, ',');
  63. if ( split != NULL )
  64. *split = '\0';
  65. } else {
  66. // Try a default
  67. tty=try[i];
  68. i++;
  69. }
  70. if (chdir("/dev")) {
  71. ERROR("failed to change dir to /dev: %m\n");
  72. return;
  73. }
  74. while (tty!=NULL) {
  75. f = open(tty, O_RDONLY|O_NOCTTY);
  76. if (f >= 0) {
  77. close(f);
  78. break;
  79. }
  80. tty=try[i];
  81. i++;
  82. }
  83. if (chdir("/"))
  84. ERROR("failed to change dir to /: %m\n");
  85. if (tty != NULL)
  86. set_stdio(tty);
  87. }
  88. static void perform_halt()
  89. {
  90. if (reboot_event == RB_POWER_OFF)
  91. LOG("- power down -\n");
  92. else
  93. LOG("- reboot -\n");
  94. /* Allow time for last message to reach serial console, etc */
  95. sleep(1);
  96. if (is_container()) {
  97. reboot(reboot_event);
  98. exit(EXIT_SUCCESS);
  99. return;
  100. }
  101. /* We have to fork here, since the kernel calls do_exit(EXIT_SUCCESS)
  102. * in linux/kernel/sys.c, which can cause the machine to panic when
  103. * the init process exits... */
  104. if (!vfork()) { /* child */
  105. reboot(reboot_event);
  106. _exit(EXIT_SUCCESS);
  107. }
  108. while (1)
  109. sleep(1);
  110. }
  111. static void state_enter(void)
  112. {
  113. char ubus_cmd[] = "/sbin/ubusd";
  114. struct passwd *p;
  115. switch (state) {
  116. case STATE_EARLY:
  117. LOG("- early -\n");
  118. watchdog_init(0);
  119. hotplug("/etc/hotplug.json");
  120. procd_coldplug();
  121. break;
  122. case STATE_UBUS:
  123. // try to reopen incase the wdt was not available before coldplug
  124. watchdog_init(0);
  125. set_stdio("console");
  126. p = getpwnam("ubus");
  127. if (p) {
  128. int ret;
  129. LOG("- ubus -\n");
  130. mkdir(p->pw_dir, 0755);
  131. ret = chown(p->pw_dir, p->pw_uid, p->pw_gid);
  132. if (ret)
  133. LOG("- ubus - failed to chown(%s)\n", p->pw_dir);
  134. } else {
  135. LOG("- ubus (running as root!) -\n");
  136. }
  137. procd_connect_ubus();
  138. service_start_early("ubus", ubus_cmd, p?"ubus":NULL, p?"ubus":NULL);
  139. break;
  140. case STATE_INIT:
  141. LOG("- init -\n");
  142. procd_inittab();
  143. procd_inittab_run("respawn");
  144. procd_inittab_run("askconsole");
  145. procd_inittab_run("askfirst");
  146. procd_inittab_run("sysinit");
  147. // switch to syslog log channel
  148. ulog_open(ULOG_SYSLOG, LOG_DAEMON, "procd");
  149. break;
  150. case STATE_RUNNING:
  151. LOG("- init complete -\n");
  152. procd_inittab_run("respawnlate");
  153. procd_inittab_run("askconsolelate");
  154. break;
  155. case STATE_SHUTDOWN:
  156. /* Redirect output to the console for the users' benefit */
  157. set_console();
  158. LOG("- shutdown -\n");
  159. procd_inittab_run("shutdown");
  160. sync();
  161. break;
  162. case STATE_HALT:
  163. // To prevent killed processes from interrupting the sleep
  164. signal(SIGCHLD, SIG_IGN);
  165. LOG("- SIGTERM processes -\n");
  166. kill(-1, SIGTERM);
  167. sync();
  168. sleep(1);
  169. LOG("- SIGKILL processes -\n");
  170. kill(-1, SIGKILL);
  171. sync();
  172. sleep(1);
  173. #ifndef DISABLE_INIT
  174. perform_halt();
  175. #else
  176. exit(EXIT_SUCCESS);
  177. #endif
  178. break;
  179. default:
  180. ERROR("Unhandled state %d\n", state);
  181. return;
  182. };
  183. }
  184. void procd_state_next(void)
  185. {
  186. DEBUG(4, "Change state %d -> %d\n", state, state + 1);
  187. state++;
  188. state_enter();
  189. }
  190. void procd_state_ubus_connect(void)
  191. {
  192. if (state == STATE_UBUS)
  193. procd_state_next();
  194. }
  195. void procd_shutdown(int event)
  196. {
  197. if (state >= STATE_SHUTDOWN)
  198. return;
  199. DEBUG(2, "Shutting down system with event %x\n", event);
  200. reboot_event = event;
  201. state = STATE_SHUTDOWN;
  202. state_enter();
  203. }