/* * Copyright 2005 by Gemtek Technology Co., Ltd * * All Rights Reserved * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation, and that the name of Gemtek not be * used in advertising or publicity pertaining to distribution of the * software without specific, written prior permission. * */ /* * System V init functionality * * Copyright 2005, Broadcom Corporation * All Rights Reserved. * * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. * * $Id$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define loop_forever() do { sleep(1); } while (1) #define SHELL "/bin/sh" /* Set terminal settings to reasonable defaults */ static void set_term(int fd) { struct termios tty; tcgetattr(fd, &tty); /* set control chars */ tty.c_cc[VINTR] = 3; /* C-c */ tty.c_cc[VQUIT] = 28; /* C-\ */ tty.c_cc[VERASE] = 127; /* C-? */ tty.c_cc[VKILL] = 21; /* C-u */ tty.c_cc[VEOF] = 4; /* C-d */ tty.c_cc[VSTART] = 17; /* C-q */ tty.c_cc[VSTOP] = 19; /* C-s */ tty.c_cc[VSUSP] = 26; /* C-z */ /* use line dicipline 0 */ tty.c_line = 0; /* Make it be sane */ tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD; tty.c_cflag |= CREAD|HUPCL|CLOCAL; /* input modes */ tty.c_iflag = ICRNL | IXON | IXOFF; /* output modes */ tty.c_oflag = OPOST | ONLCR; /* local modes */ tty.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; tcsetattr(fd, TCSANOW, &tty); } int console_init() { int fd; /* Clean up */ ioctl(0, TIOCNOTTY, 0); close(0); close(1); close(2); setsid(); /* Reopen console */ if ((fd = open(_PATH_CONSOLE, O_RDWR)) < 0) { perror(_PATH_CONSOLE); return errno; } dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); ioctl(0, TIOCSCTTY, 1); tcsetpgrp(0, getpgrp()); set_term(0); return 0; } // PANTELTJE // thiswas defined in old busybox. (In Config.h or there about). #define BB_SH #if !defined(__CONFIG_BUSYBOX__) || defined(BB_SH) pid_t run_shell(int timeout, int nowait) { pid_t pid; char tz[1000]; char *envp[] = { "TERM=vt100", "HOME=/", #ifdef DanielAdd "PATH=/usr/bin:/bin:/usr/sbin:/sbin:/tmp", #else "PATH=/usr/bin:/bin:/usr/sbin:/sbin", #endif "SHELL=" SHELL, "USER=root", tz, NULL }; int sig; /* Wait for user input */ cprintf("Hit enter to continue...\n"); if (waitfor(STDIN_FILENO, timeout) <= 0) return 0; switch ((pid = fork())) { case -1: perror("fork"); return 0; case 0: /* Reset signal handlers set for parent process */ for (sig = 0; sig < (_NSIG-1); sig++) signal(sig, SIG_DFL); /* Reopen console */ console_init(); /* Pass on TZ */ snprintf(tz, sizeof(tz), "TZ=%s", getenv("TZ")); /* Now run it. The new program will take over this PID, * so nothing further in init.c should be run. */ execve(SHELL, (char *[]) { "/bin/sh", NULL }, envp); /* We're still here? Some error happened. */ perror(SHELL); exit(errno); default: if (nowait) return pid; else { waitpid(pid, NULL, 0); return 0; } } } #else /* Busybox configured w/o a shell */ pid_t run_shell(int timeout, int nowait) { /* Wait for usr input to say we're ignoring it */ if (waitfor(STDIN_FILENO, timeout) > 0) { char c; struct pollfd pfd = { STDIN_FILENO, POLLIN, 0 }; /* Read while available (flush input) */ while ( (poll(&pfd, 1, 0) > 0) && (pfd.revents & POLLIN) ) read(STDIN_FILENO, &c, 1); cprintf("Busybox configured w/o a shell\n"); } return 0; } #endif static void shutdown_system(void) { int sig; /* Disable signal handlers */ for (sig = 0; sig < (_NSIG-1); sig++) signal(sig, SIG_DFL); #ifdef DanielAdd sleep(1); #endif cprintf("Sending SIGTERM to all processes\n"); kill(-1, SIGTERM); sleep(1); cprintf("Sending SIGKILL to all processes\n"); kill(-1, SIGKILL); sleep(1); sync(); } static int fatal_signals[] = { SIGQUIT, SIGILL, SIGABRT, SIGFPE, SIGPIPE, SIGBUS, SIGSEGV, SIGSYS, SIGTRAP, SIGPWR, SIGTERM, /* reboot */ SIGUSR1, /* halt */ }; void fatal_signal(int sig) { char *message = NULL; switch (sig) { case SIGQUIT: message = "Quit"; break; case SIGILL: message = "Illegal instruction"; break; case SIGABRT: message = "Abort"; break; case SIGFPE: message = "Floating exception"; break; case SIGPIPE: message = "Broken pipe"; break; case SIGBUS: message = "Bus error"; break; case SIGSEGV: message = "Segmentation fault"; break; case SIGSYS: message = "Bad system call"; break; case SIGTRAP: message = "Trace trap"; break; case SIGPWR: message = "Power failure"; break; case SIGTERM: message = "Terminated"; break; case SIGUSR1: message = "User-defined signal 1"; break; } if (message) cprintf("%s\n", message); else cprintf("Caught signal %d\n", sig); shutdown_system(); sleep(2); /* Halt on SIGUSR1 */ reboot(sig == SIGUSR1 ? RB_HALT_SYSTEM : RB_AUTOBOOT); loop_forever(); } static void reap(int sig) { pid_t pid; while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) dprintf("Reaped %d\n", pid); } void signal_init(void) { int i; for (i = 0; i < sizeof(fatal_signals)/sizeof(fatal_signals[0]); i++) signal(fatal_signals[i], fatal_signal); signal(SIGCHLD, reap); }