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 15 #include <fcntl.h> 16 #include <pwd.h> 17 #include <sys/reboot.h> 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <unistd.h> 21 #include <sys/types.h> 22 #include <signal.h> 23 24 #include "container.h" 25 #include "procd.h" 26 #include "syslog.h" 27 #include "plug/hotplug.h" 28 #include "watchdog.h" 29 #include "service/service.h" 30 #include "utils/utils.h" 31 32 enum { 33 STATE_NONE = 0, 34 STATE_EARLY, 35 STATE_UBUS, 36 STATE_INIT, 37 STATE_RUNNING, 38 STATE_SHUTDOWN, 39 STATE_HALT, 40 __STATE_MAX, 41 }; 42 43 static int state = STATE_NONE; 44 static int reboot_event; 45 46 static void set_stdio(const char* tty) 47 { 48 if (patch_stdio(tty)) 49 ERROR("failed to set stdio\n"); 50 else 51 fcntl(STDERR_FILENO, F_SETFL, fcntl(STDERR_FILENO, F_GETFL) | O_NONBLOCK); 52 } 53 54 static void set_console(void) 55 { 56 const char* tty; 57 char* split; 58 char line[ 20 ]; 59 const char* try[] = { "tty0", "console", NULL }; /* Try the most common outputs */ 60 int f, i = 0; 61 62 tty = get_cmdline_val("console",line,sizeof(line)); 63 if (tty != NULL) { 64 split = strchr(tty, ','); 65 if ( split != NULL ) 66 *split = '\0'; 67 } else { 68 // Try a default 69 tty=try[i]; 70 i++; 71 } 72 73 if (chdir("/dev")) { 74 ERROR("failed to change dir to /dev: %m\n"); 75 return; 76 } 77 while (tty!=NULL) { 78 f = open(tty, O_RDONLY|O_NOCTTY); 79 if (f >= 0) { 80 close(f); 81 break; 82 } 83 84 tty=try[i]; 85 i++; 86 } 87 if (chdir("/")) 88 ERROR("failed to change dir to /: %m\n"); 89 90 if (tty != NULL) 91 set_stdio(tty); 92 } 93 94 static void perform_halt() 95 { 96 if (reboot_event == RB_POWER_OFF) 97 LOG("- power down -\n"); 98 else 99 LOG("- reboot -\n"); 100 101 /* Allow time for last message to reach serial console, etc */ 102 sleep(1); 103 104 if (is_container()) { 105 reboot(reboot_event); 106 exit(EXIT_SUCCESS); 107 return; 108 } 109 110 /* We have to fork here, since the kernel calls do_exit(EXIT_SUCCESS) 111 * in linux/kernel/sys.c, which can cause the machine to panic when 112 * the init process exits... */ 113 if (!vfork()) { /* child */ 114 reboot(reboot_event); 115 _exit(EXIT_SUCCESS); 116 } 117 118 while (1) 119 sleep(1); 120 } 121 122 static void state_enter(void) 123 { 124 char ubus_cmd[] = "/sbin/ubusd"; 125 struct passwd *p; 126 127 switch (state) { 128 case STATE_EARLY: 129 LOG("- early -\n"); 130 watchdog_init(0); 131 hotplug("/etc/hotplug.json"); 132 procd_coldplug(); 133 break; 134 135 case STATE_UBUS: 136 // try to reopen incase the wdt was not available before coldplug 137 watchdog_init(0); 138 set_stdio("console"); 139 p = getpwnam("ubus"); 140 if (p) { 141 int ret; 142 LOG("- ubus -\n"); 143 mkdir(p->pw_dir, 0755); 144 ret = chown(p->pw_dir, p->pw_uid, p->pw_gid); 145 if (ret) 146 LOG("- ubus - failed to chown(%s)\n", p->pw_dir); 147 } else { 148 LOG("- ubus (running as root!) -\n"); 149 } 150 151 procd_connect_ubus(); 152 service_start_early("ubus", ubus_cmd, p?"ubus":NULL, p?"ubus":NULL); 153 break; 154 155 case STATE_INIT: 156 LOG("- init -\n"); 157 procd_inittab(); 158 procd_inittab_run("respawn"); 159 procd_inittab_run("askconsole"); 160 procd_inittab_run("askfirst"); 161 procd_inittab_run("sysinit"); 162 163 // switch to syslog log channel 164 ulog_open(ULOG_SYSLOG, LOG_DAEMON, "procd"); 165 break; 166 167 case STATE_RUNNING: 168 LOG("- init complete -\n"); 169 procd_inittab_run("respawnlate"); 170 procd_inittab_run("askconsolelate"); 171 break; 172 173 case STATE_SHUTDOWN: 174 ulog_open(ULOG_KMSG, LOG_DAEMON, "procd"); 175 /* Redirect output to the console for the users' benefit */ 176 set_console(); 177 LOG("- shutdown -\n"); 178 procd_inittab_run("shutdown"); 179 sync(); 180 break; 181 182 case STATE_HALT: 183 // To prevent killed processes from interrupting the sleep 184 signal(SIGCHLD, SIG_IGN); 185 LOG("- SIGTERM processes -\n"); 186 kill(-1, SIGTERM); 187 sync(); 188 sleep(1); 189 LOG("- SIGKILL processes -\n"); 190 kill(-1, SIGKILL); 191 sync(); 192 sleep(1); 193 #ifndef DISABLE_INIT 194 perform_halt(); 195 #else 196 exit(EXIT_SUCCESS); 197 #endif 198 break; 199 200 default: 201 ERROR("Unhandled state %d\n", state); 202 return; 203 }; 204 } 205 206 void procd_state_next(void) 207 { 208 DEBUG(4, "Change state %d -> %d\n", state, state + 1); 209 state++; 210 state_enter(); 211 } 212 213 void procd_state_ubus_connect(void) 214 { 215 if (state == STATE_UBUS) 216 procd_state_next(); 217 } 218 219 void procd_shutdown(int event) 220 { 221 if (state >= STATE_SHUTDOWN) 222 return; 223 DEBUG(2, "Shutting down system with event %x\n", event); 224 reboot_event = event; 225 state = STATE_SHUTDOWN; 226 state_enter(); 227 } 228
This page was automatically generated by LXR 0.3.1. • OpenWrt