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