1/* 2 * System V init functionality 3 * 4 * Copyright 2004, Broadcom Corporation 5 * All Rights Reserved. 6 * 7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY 8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM 9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS 10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. 11 * 12 * $Id: init.c,v 1.2 2008/11/12 09:21:23 james26_jang Exp $ 13 */ 14 15#include <stdio.h> 16#include <stdlib.h> 17#include <errno.h> 18#include <paths.h> 19#include <signal.h> 20#include <stdarg.h> 21#include <string.h> 22#include <termios.h> 23#include <unistd.h> 24#include <limits.h> 25#include <sys/fcntl.h> 26#include <sys/ioctl.h> 27#include <sys/mount.h> 28#include <sys/reboot.h> 29#include <sys/types.h> 30#include <sys/wait.h> 31#include <sys/time.h> 32 33#include <shutils.h> 34 35#define loop_forever() do { sleep(1); } while (1) 36#define SHELL "/bin/sh" 37 38/* Set terminal settings to reasonable defaults */ 39static void set_term(int fd) 40{ 41 struct termios tty; 42 43 tcgetattr(fd, &tty); 44 45 /* set control chars */ 46 tty.c_cc[VINTR] = 3; /* C-c */ 47 tty.c_cc[VQUIT] = 28; /* C-\ */ 48 tty.c_cc[VERASE] = 127; /* C-? */ 49 tty.c_cc[VKILL] = 21; /* C-u */ 50 tty.c_cc[VEOF] = 4; /* C-d */ 51 tty.c_cc[VSTART] = 17; /* C-q */ 52 tty.c_cc[VSTOP] = 19; /* C-s */ 53 tty.c_cc[VSUSP] = 26; /* C-z */ 54 55 /* use line dicipline 0 */ 56 tty.c_line = 0; 57 58 /* Make it be sane */ 59 tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD; 60 tty.c_cflag |= CREAD|HUPCL|CLOCAL; 61 62 63 /* input modes */ 64 tty.c_iflag = ICRNL | IXON | IXOFF; 65 66 /* output modes */ 67 tty.c_oflag = OPOST | ONLCR; 68 69 /* local modes */ 70 tty.c_lflag = 71 ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; 72 73 tcsetattr(fd, TCSANOW, &tty); 74} 75 76int 77console_init() 78{ 79 int fd; 80 81 /* Clean up */ 82 ioctl(0, TIOCNOTTY, 0); 83 close(0); 84 close(1); 85 close(2); 86 setsid(); 87 88 /* Reopen console */ 89 if ((fd = open(_PATH_CONSOLE, O_RDWR)) < 0) { 90 perror(_PATH_CONSOLE); 91 return errno; 92 } 93 dup2(fd, 0); 94 dup2(fd, 1); 95 dup2(fd, 2); 96 97 ioctl(0, TIOCSCTTY, 1); 98 tcsetpgrp(0, getpgrp()); 99 set_term(0); 100 101 return 0; 102} 103 104pid_t 105run_shell(int timeout, int nowait) 106{ 107 pid_t pid; 108 char tz[1000]; 109 char *envp[] = { 110 "TERM=vt100", 111 "HOME=/", 112 "PATH=/usr/bin:/bin:/usr/sbin:/sbin", 113 "SHELL=" SHELL, 114 "USER=root", 115 "LD_LIBRARY_PATH=/shares/lib:/shares/usr/gift-nasoc/lib", 116 tz, 117 NULL 118 }; 119 int sig; 120 121 /* Wait for user input */ 122 cprintf("Hit enter to continue..."); 123 if (waitfor(STDIN_FILENO, timeout) <= 0) 124 return 0; 125 126 switch ((pid = fork())) { 127 case -1: 128 perror("fork"); 129 return 0; 130 case 0: 131 /* Reset signal handlers set for parent process */ 132 for (sig = 0; sig < (_NSIG-1); sig++) 133 signal(sig, SIG_DFL); 134 135 /* Reopen console */ 136 console_init(); 137 138 /* Pass on TZ */ 139 snprintf(tz, sizeof(tz), "TZ=%s", getenv("TZ")); 140 141 /* Now run it. The new program will take over this PID, 142 * so nothing further in init.c should be run. */ 143 execve(SHELL, (char *[]) { "/bin/sh", NULL }, envp); 144 145 /* We're still here? Some error happened. */ 146 perror(SHELL); 147 exit(errno); 148 default: 149 if (nowait) 150 return pid; 151 else { 152 waitpid(pid, NULL, 0); 153 return 0; 154 } 155 } 156} 157 158static void 159shutdown_system(void) 160{ 161 int sig; 162 163 /* Disable signal handlers */ 164 for (sig = 0; sig < (_NSIG-1); sig++) 165 signal(sig, SIG_DFL); 166 167 cprintf("Sending SIGTERM to all processes\n"); 168 kill(-1, SIGTERM); 169 sleep(1); 170 171 cprintf("Sending SIGKILL to all processes\n"); 172 kill(-1, SIGKILL); 173 sleep(1); 174 175 sync(); 176} 177 178static int fatal_signals[] = { 179 SIGQUIT, 180 SIGILL, 181 SIGABRT, 182 SIGFPE, 183 SIGPIPE, 184 SIGBUS, 185 SIGSEGV, 186 SIGSYS, 187 SIGTRAP, 188 SIGPWR, 189 SIGTERM, /* reboot */ 190 SIGUSR1, /* halt */ 191}; 192 193void 194fatal_signal(int sig) 195{ 196 char *message = NULL; 197 198 switch (sig) { 199 case SIGQUIT: message = "Quit"; break; 200 case SIGILL: message = "Illegal instruction"; break; 201 case SIGABRT: message = "Abort"; break; 202 case SIGFPE: message = "Floating exception"; break; 203 case SIGPIPE: message = "Broken pipe"; break; 204 case SIGBUS: message = "Bus error"; break; 205 case SIGSEGV: message = "Segmentation fault"; break; 206 case SIGSYS: message = "Bad system call"; break; 207 case SIGTRAP: message = "Trace trap"; break; 208 case SIGPWR: message = "Power failure"; break; 209 case SIGTERM: message = "Terminated"; break; 210 case SIGUSR1: message = "User-defined signal 1"; break; 211 } 212 213 if (message) 214 cprintf("%s\n", message); 215 else 216 cprintf("Caught signal %d\n", sig); 217 218 shutdown_system(); 219 sleep(2); 220 221 /* Halt on SIGUSR1 */ 222 reboot(sig == SIGUSR1 ? RB_HALT_SYSTEM : RB_AUTOBOOT); 223 loop_forever(); 224} 225 226static void 227reap(int sig) 228{ 229 pid_t pid; 230 231 while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) 232 dprintf("Reaped %d\n", pid); 233} 234 235 236void 237signal_init(void) 238{ 239 int i; 240 241 for (i = 0; i < sizeof(fatal_signals)/sizeof(fatal_signals[0]); i++) 242 signal(fatal_signals[i], fatal_signal); 243 244 signal(SIGCHLD, reap); 245} 246