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