+static void set_stdio(const char* tty)
+{
+ if (chdir("/dev") ||
+ !freopen(tty, "r", stdin) ||
+ !freopen(tty, "w", stdout) ||
+ !freopen(tty, "w", stderr) ||
+ chdir("/"))
+ ERROR("failed to set stdio: %m\n");
+ else
+ fcntl(STDERR_FILENO, F_SETFL, fcntl(STDERR_FILENO, F_GETFL) | O_NONBLOCK);
+}
+
+static void set_console(void)
+{
+ const char* tty;
+ char* split;
+ char line[ 20 ];
+ const char* try[] = { "tty0", "console", NULL }; /* Try the most common outputs */
+ int f, i = 0;
+
+ tty = get_cmdline_val("console",line,sizeof(line));
+ if (tty != NULL) {
+ split = strchr(tty, ',');
+ if ( split != NULL )
+ *split = '\0';
+ } else {
+ // Try a default
+ tty=try[i];
+ i++;
+ }
+
+ if (chdir("/dev")) {
+ ERROR("failed to change dir to /dev: %m\n");
+ return;
+ }
+ while (tty!=NULL) {
+ f = open(tty, O_RDONLY);
+ if (f >= 0) {
+ close(f);
+ break;
+ }
+
+ tty=try[i];
+ i++;
+ }
+ if (chdir("/"))
+ ERROR("failed to change dir to /: %m\n");
+
+ if (tty != NULL)
+ set_stdio(tty);
+}
+
+static void perform_halt()
+{
+ if (reboot_event == RB_POWER_OFF)
+ LOG("- power down -\n");
+ else
+ LOG("- reboot -\n");
+
+ /* Allow time for last message to reach serial console, etc */
+ sleep(1);
+
+ if (is_container()) {
+ reboot(reboot_event);
+ exit(EXIT_SUCCESS);
+ return;
+ }
+
+ /* We have to fork here, since the kernel calls do_exit(EXIT_SUCCESS)
+ * in linux/kernel/sys.c, which can cause the machine to panic when
+ * the init process exits... */
+ if (!vfork()) { /* child */
+ reboot(reboot_event);
+ _exit(EXIT_SUCCESS);
+ }
+
+ while (1)
+ sleep(1);
+}
+