1/* 2 * System V init functionality 3 * 4 * Copyright (C) 2013, Broadcom Corporation. All Rights Reserved. 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * 18 * $Id: init.c 241182 2011-02-17 21:50:03Z $ 19 */ 20 21#include <stdio.h> 22#include <stdlib.h> 23#include <errno.h> 24#include <paths.h> 25#include <signal.h> 26#include <stdarg.h> 27#include <string.h> 28#include <termios.h> 29#include <unistd.h> 30#include <limits.h> 31#include <sys/fcntl.h> 32#include <sys/ioctl.h> 33#include <sys/mount.h> 34#include <sys/reboot.h> 35#include <sys/types.h> 36#include <sys/wait.h> 37#include <sys/time.h> 38#include <sys/poll.h> 39 40#include <shutils.h> 41 42#include <rc.h> 43#include <bcmparams.h> 44#include <wlutils.h> 45#include <pmon.h> 46 47#define loop_forever() do { sleep(1); } while (1) 48#define SHELL "/bin/sh" 49 50/* Set terminal settings to reasonable defaults */ 51static void set_term(int fd) 52{ 53 struct termios tty; 54 55 tcgetattr(fd, &tty); 56 57 /* set control chars */ 58 tty.c_cc[VINTR] = 3; /* C-c */ 59 tty.c_cc[VQUIT] = 28; /* C-\ */ 60 tty.c_cc[VERASE] = 127; /* C-? */ 61 tty.c_cc[VKILL] = 21; /* C-u */ 62 tty.c_cc[VEOF] = 4; /* C-d */ 63 tty.c_cc[VSTART] = 17; /* C-q */ 64 tty.c_cc[VSTOP] = 19; /* C-s */ 65 tty.c_cc[VSUSP] = 26; /* C-z */ 66 67 /* use line dicipline 0 */ 68 tty.c_line = 0; 69 70 /* Make it be sane */ 71 tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD; 72 tty.c_cflag |= CREAD|HUPCL|CLOCAL; 73 74 75 /* input modes */ 76 tty.c_iflag = ICRNL | IXON | IXOFF; 77 78 /* output modes */ 79 tty.c_oflag = OPOST | ONLCR; 80 81 /* local modes */ 82 tty.c_lflag = 83 ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; 84 85 tcsetattr(fd, TCSANOW, &tty); 86} 87 88int 89console_init() 90{ 91 int fd; 92 93 /* Clean up */ 94 ioctl(0, TIOCNOTTY, 0); 95 close(0); 96 close(1); 97 close(2); 98 setsid(); 99 100 /* Reopen console */ 101 if ((fd = open(_PATH_CONSOLE, O_RDWR)) < 0) { 102 perror(_PATH_CONSOLE); 103 return errno; 104 } 105 dup2(fd, 0); 106 dup2(fd, 1); 107 dup2(fd, 2); 108 109 ioctl(0, TIOCSCTTY, 1); 110 tcsetpgrp(0, getpgrp()); 111 set_term(0); 112 113 return 0; 114} 115 116#if defined(BB_SH) 117#undef CONFIG_FEATURE_SH_IS_NONE 118#endif 119 120#if !defined(__CONFIG_BUSYBOX__) || !defined(CONFIG_FEATURE_SH_IS_NONE) 121pid_t 122run_shell(int timeout, int nowait) 123{ 124 pid_t pid; 125 char tz[1000]; 126 char *envp[] = { 127 "TERM=vt100", 128 "HOME=/", 129 "PATH=/usr/bin:/bin:/usr/sbin:/sbin", 130 "SHELL=" SHELL, 131 "USER=root", 132 tz, 133 NULL 134 }; 135 int sig; 136 137 /* Wait for user input */ 138 cprintf("Hit enter to continue..."); 139 if (waitfor(STDIN_FILENO, timeout) <= 0) 140 return 0; 141 142 switch ((pid = fork())) { 143 case -1: 144 perror("fork"); 145 return 0; 146 case 0: 147 /* Reset signal handlers set for parent process */ 148 for (sig = 0; sig < (_NSIG-1); sig++) 149 signal(sig, SIG_DFL); 150 151 /* Reopen console */ 152 console_init(); 153 154 /* Pass on TZ */ 155 snprintf(tz, sizeof(tz), "TZ=%s", getenv("TZ")); 156 157 /* Now run it. The new program will take over this PID, 158 * so nothing further in init.c should be run. 159 */ 160 execve(SHELL, (char *[]) { "/bin/sh", NULL }, envp); 161 162 /* We're still here? Some error happened. */ 163 perror(SHELL); 164 exit(errno); 165 default: 166 if (nowait) 167 return pid; 168 else { 169 waitpid(pid, NULL, 0); 170 return 0; 171 } 172 } 173} 174#else /* Busybox configured w/o a shell */ 175pid_t 176run_shell(int timeout, int nowait) 177{ 178 /* Wait for usr input to say we're ignoring it */ 179 if (waitfor(STDIN_FILENO, timeout) > 0) { 180 char c; 181 struct pollfd pfd = { STDIN_FILENO, POLLIN, 0 }; 182 183 /* Read while available (flush input) */ 184 while ((poll(&pfd, 1, 0) > 0) && (pfd.revents & POLLIN)) 185 read(STDIN_FILENO, &c, 1); 186 187 cprintf("Busybox configured w/o a shell\n"); 188 } 189 return 0; 190} 191#endif /* !__CONFIG_BUSYBOX__ || !CONFIG_FEATURE_SH_IS_NONE */ 192 193static void 194shutdown_system(void) 195{ 196 int sig; 197 198#ifdef __CONFIG_USBAP__ 199 { 200 int ret = 0, i = 0; 201 char ifname[16] = {0}; 202 203 for (i = 1; i <= DEV_NUMIFS; i++) { 204 sprintf(ifname, "eth%d", i); 205 if (wl_probe(ifname)) 206 break; 207 } 208 209 sprintf(ifname, "eth%d", i - 1); 210 if ((ret = wl_ioctl(ifname, WLC_UP, NULL, 0))) 211 fprintf(stderr, "%s:%d:(%s): cannot bringup, err = %d\n", 212 __FUNCTION__, __LINE__, ifname, ret); 213 214 if ((ret = wl_iovar_setint(ifname, "dngl_wd", 1))) 215 fprintf(stderr, "%s:%d:(%s): setting iovar \"%s\" to 0x%x failed," 216 " err = %d\n", __FUNCTION__, __LINE__, ifname, "dngl_wd", 217 (unsigned int)1, ret); 218 sleep(1); 219 } 220#endif /* __CONFIG_USBAP__ */ 221 222 /* Disable signal handlers */ 223 for (sig = 0; sig < (_NSIG-1); sig++) 224 signal(sig, SIG_DFL); 225 226 cprintf("Sending SIGTERM to all processes\n"); 227 kill(-1, SIGTERM); 228 sleep(1); 229 230 cprintf("Sending SIGKILL to all processes\n"); 231 kill(-1, SIGKILL); 232 sleep(1); 233 234 sync(); 235} 236 237static int fatal_signals[] = { 238 SIGQUIT, 239 SIGILL, 240 SIGABRT, 241 SIGFPE, 242 SIGPIPE, 243 SIGBUS, 244 SIGSEGV, 245 SIGSYS, 246 SIGTRAP, 247 SIGPWR, 248 SIGTERM, /* reboot */ 249 SIGUSR1, /* halt */ 250}; 251 252void 253fatal_signal(int sig) 254{ 255 char *message = NULL; 256 257 switch (sig) { 258 case SIGQUIT: message = "Quit"; break; 259 case SIGILL: message = "Illegal instruction"; break; 260 case SIGABRT: message = "Abort"; break; 261 case SIGFPE: message = "Floating exception"; break; 262 case SIGPIPE: message = "Broken pipe"; break; 263 case SIGBUS: message = "Bus error"; break; 264 case SIGSEGV: message = "Segmentation fault"; break; 265 case SIGSYS: message = "Bad system call"; break; 266 case SIGTRAP: message = "Trace trap"; break; 267 case SIGPWR: message = "Power failure"; break; 268 case SIGTERM: message = "Terminated"; break; 269 case SIGUSR1: message = "User-defined signal 1"; break; 270 } 271 272 if (message) 273 cprintf("%s\n", message); 274 else 275 cprintf("Caught signal %d\n", sig); 276 277 shutdown_system(); 278 sleep(2); 279 280 /* wklin modified start, 01/17/2007 */ 281#if 1 282 /* NEVER HALT */ 283 reboot(RB_AUTOBOOT); 284#else 285 /* Halt on SIGUSR1 */ 286 reboot(sig == SIGUSR1 ? RB_HALT_SYSTEM : RB_AUTOBOOT); 287#endif 288 /* wklin modified end, 01/17/2007 */ 289 loop_forever(); 290} 291 292static void 293reap(int sig) 294{ 295 pid_t pid; 296 pmon_func_t func; 297 298 while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) { 299 dprintf("Reaped %d\n", pid); 300 if ((func = pmon_get_func(pid)) != NULL) { 301 pmon_unregister(pid); 302 (*func)(); 303 } 304 } 305} 306 307 308void 309signal_init(void) 310{ 311 int i; 312 313 for (i = 0; i < sizeof(fatal_signals)/sizeof(fatal_signals[0]); i++) 314 signal(fatal_signals[i], fatal_signal); 315 316 signal(SIGCHLD, reap); 317} 318