kern_shutdown.c revision 17658
1/*-
2 * Copyright (c) 1986, 1988, 1991, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *	This product includes software developed by the University of
21 *	California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 *    may be used to endorse or promote products derived from this software
24 *    without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 *	@(#)kern_shutdown.c	8.3 (Berkeley) 1/21/94
39 * $Id: subr_prf.c,v 1.37 1996/05/09 18:58:06 gpalmer Exp $
40 */
41
42#include "opt_ddb.h"
43
44#include <sys/param.h>
45#include <sys/systm.h>
46#include <sys/reboot.h>
47#include <sys/msgbuf.h>
48#include <sys/proc.h>
49#include <sys/vnode.h>
50#include <sys/tty.h>
51#include <sys/tprintf.h>
52#include <sys/syslog.h>
53#include <sys/malloc.h>
54#include <sys/kernel.h>
55#include <sys/sysctl.h>
56#include <sys/devconf.h>
57#include <sys/conf.h>
58#include <sys/sysproto.h>
59
60#include <machine/pcb.h>
61#include <machine/clock.h>
62#include <machine/cons.h>
63#include <machine/md_var.h>
64
65#include <sys/utsname.h>
66#include <sys/signalvar.h>
67
68#ifndef PANIC_REBOOT_WAIT_TIME
69#define PANIC_REBOOT_WAIT_TIME 15 /* default to 15 seconds */
70#endif
71
72/*
73 * Note that stdarg.h and the ANSI style va_start macro is used for both
74 * ANSI and traditional C compilers.
75 */
76#include <machine/stdarg.h>
77
78#if defined(DDB)
79#ifdef DDB_UNATTENDED
80	static int debugger_on_panic = 0;
81#else
82	static int debugger_on_panic = 1;
83#endif
84
85SYSCTL_INT(_debug, OID_AUTO, debugger_on_panic, CTLFLAG_RW,
86	&debugger_on_panic, 0, "");
87#endif
88
89
90/*
91 * Variable panicstr contains argument to first call to panic; used as flag
92 * to indicate that the kernel has already called panic.
93 */
94const char *panicstr;
95
96/*
97 * callout list for things to do a shutdown
98 */
99typedef struct shutdown_list_element {
100	struct shutdown_list_element *next;
101	bootlist_fn function;
102	void *arg;
103} *sle_p;
104
105static sle_p shutdown_list;
106
107
108
109/* This implements a "TEXT_SET" for cleanup functions */
110static void	dummy_cleanup __P((void));
111static void
112dummy_cleanup() {}
113TEXT_SET(cleanup_set, dummy_cleanup);
114
115typedef void (*cleanup_func_t)(void);
116extern const struct linker_set cleanup_set;
117static const cleanup_func_t *cleanups =
118        (const cleanup_func_t *)&cleanup_set.ls_items[0];
119static void dumpsys(void);
120
121#ifndef _SYS_SYSPROTO_H_
122struct reboot_args {
123	int	opt;
124};
125#endif
126/* ARGSUSED */
127
128/*
129 * The system call that results in a reboot
130 */
131int
132reboot(p, uap, retval)
133	struct proc *p;
134	struct reboot_args *uap;
135	int *retval;
136{
137	int error;
138
139	if ((error = suser(p->p_ucred, &p->p_acflag)))
140		return (error);
141
142	boot(uap->opt);
143	return (0);
144}
145
146/*
147 * Called by events that want to shut down.. e.g  <CTL><ALT><DEL> on a PC
148 */
149void
150shutdown_nice(void)
151{
152	/* Send a signal to init(8) and have it shutdown the world */
153	if (initproc != NULL) {
154		psignal(initproc, SIGINT);
155	} else {
156		/* No init(8) running, so simply reboot */
157		boot(RB_NOSYNC);
158	}
159	return;
160}
161static int	waittime = -1;
162static struct pcb dumppcb;
163
164/*
165 *  Go through the rigmarole of shutting down..
166 * this used to be in machdep.c but I'll be dammned if I could see
167 * anything machine dependant in it.
168 */
169__dead void
170boot(howto)
171	int howto;
172{
173	sle_p ep = shutdown_list;
174
175	/*
176	 * eventually the at_shutdown() method will totally replace the
177	 * linker set but for now leave them both (so 3rd partys
178	 * modules that might use it can not break).
179	 * The linker set is no good for LKMs etc.
180	 */
181	if ((howto & RB_NOSYNC) == 0 ) {
182		printf("\ncleaning up... ");
183                while(*cleanups) {
184			printf("Using obsolete shutdown callout..\n");
185			printf("update code to use at_shutdown()\n");
186                        (**cleanups++)();
187                }
188	}
189	while(ep) {
190		shutdown_list = ep->next;
191		(*ep->function)(howto, ep->arg);
192		ep = ep->next;
193	}
194	if (!cold && (howto & RB_NOSYNC) == 0 && waittime < 0) {
195		register struct buf *bp;
196		int iter, nbusy;
197
198		waittime = 0;
199		printf("\nsyncing disks... ");
200
201		sync(&proc0, NULL, NULL);
202
203		for (iter = 0; iter < 20; iter++) {
204			nbusy = 0;
205			for (bp = &buf[nbuf]; --bp >= buf; ) {
206				if ((bp->b_flags & (B_BUSY | B_INVAL)) == B_BUSY) {
207					nbusy++;
208				}
209			}
210			if (nbusy == 0)
211				break;
212			printf("%d ", nbusy);
213			DELAY(40000 * iter);
214		}
215		if (nbusy) {
216			/*
217			 * Failed to sync all blocks. Indicate this and don't
218			 * unmount filesystems (thus forcing an fsck on reboot).
219			 */
220			printf("giving up\n");
221#ifdef SHOW_BUSYBUFS
222			nbusy = 0;
223			for (bp = &buf[nbuf]; --bp >= buf; ) {
224				if ((bp->b_flags & (B_BUSY | B_INVAL)) == B_BUSY) {
225					nbusy++;
226					printf("%d: dev:%08x, flags:%08x, blkno:%d, lblkno:%d\n", nbusy, bp->b_dev, bp->b_flags, bp->b_blkno, bp->b_lblkno);
227				}
228			}
229			DELAY(5000000);	/* 5 seconds */
230#endif
231		} else {
232			printf("done\n");
233			/*
234			 * Unmount filesystems
235			 */
236			if (panicstr == 0)
237				vfs_unmountall();
238		}
239		DELAY(100000);			/* wait for console output to finish */
240		dev_shutdownall(FALSE);
241	}
242	splhigh();
243	if (howto & RB_HALT) {
244		printf("\n");
245		printf("The operating system has halted.\n");
246		printf("Please press any key to reboot.\n\n");
247		cngetc();
248	} else {
249		if (howto & RB_DUMP) {
250			if (!cold) {
251				savectx(&dumppcb);
252				dumppcb.pcb_cr3 = rcr3();
253				dumpsys();
254			}
255
256			if (PANIC_REBOOT_WAIT_TIME != 0) {
257				if (PANIC_REBOOT_WAIT_TIME != -1) {
258					int loop;
259					printf("Automatic reboot in %d seconds - press a key on the console to abort\n",
260						PANIC_REBOOT_WAIT_TIME);
261					for (loop = PANIC_REBOOT_WAIT_TIME * 10; loop > 0; --loop) {
262						DELAY(1000 * 100); /* 1/10th second */
263						if (cncheckc()) /* Did user type a key? */
264							break;
265					}
266					if (!loop)
267						goto die;
268				}
269			} else { /* zero time specified - reboot NOW */
270				goto die;
271			}
272			printf("--> Press a key on the console to reboot <--\n");
273			cngetc();
274		}
275	}
276die:
277	printf("Rebooting...\n");
278	DELAY(1000000);	/* wait 1 sec for printf's to complete and be read */
279	cpu_reset();
280	for(;;) ;
281	/* NOTREACHED */
282}
283
284/*
285 * Magic number for savecore
286 *
287 * exported (symorder) and used at least by savecore(8)
288 *
289 */
290static u_long const	dumpmag = 0x8fca0101UL;
291
292static int	dumpsize = 0;		/* also for savecore */
293
294static int	dodump = 1;
295SYSCTL_INT(_machdep, OID_AUTO, do_dump, CTLFLAG_RW, &dodump, 0, "");
296
297/*
298 * Doadump comes here after turning off memory management and
299 * getting on the dump stack, either when called above, or by
300 * the auto-restart code.
301 */
302static void
303dumpsys(void)
304{
305
306	if (!dodump)
307		return;
308	if (dumpdev == NODEV)
309		return;
310	if ((minor(dumpdev)&07) != 1)
311		return;
312	if (!(bdevsw[major(dumpdev)]))
313		return;
314	if (!(bdevsw[major(dumpdev)]->d_dump))
315		return;
316	dumpsize = Maxmem;
317	printf("\ndumping to dev %lx, offset %ld\n", dumpdev, dumplo);
318	printf("dump ");
319	switch ((*bdevsw[major(dumpdev)]->d_dump)(dumpdev)) {
320
321	case ENXIO:
322		printf("device bad\n");
323		break;
324
325	case EFAULT:
326		printf("device not ready\n");
327		break;
328
329	case EINVAL:
330		printf("area improper\n");
331		break;
332
333	case EIO:
334		printf("i/o error\n");
335		break;
336
337	case EINTR:
338		printf("aborted from console\n");
339		break;
340
341	default:
342		printf("succeeded\n");
343		break;
344	}
345}
346
347/*
348 * Panic is called on unresolvable fatal errors.  It prints "panic: mesg",
349 * and then reboots.  If we are called twice, then we avoid trying to sync
350 * the disks as this often leads to recursive panics.
351 */
352#ifdef __GNUC__
353__dead			/* panic() does not return */
354#endif
355void
356panic(const char *fmt, ...)
357{
358	int bootopt;
359	va_list ap;
360
361	bootopt = RB_AUTOBOOT | RB_DUMP;
362	if (panicstr)
363		bootopt |= RB_NOSYNC;
364	else
365		panicstr = fmt;
366
367	printf("panic: ");
368	va_start(ap, fmt);
369	vprintf(fmt, ap);
370	va_end(ap);
371	printf("\n");
372
373#if defined(DDB)
374	if (debugger_on_panic)
375		Debugger ("panic");
376#endif
377	boot(bootopt);
378}
379
380
381/*********************************************************
382 * general routines to handle adding/deleting items on the
383 * shutdown callout list
384 *****
385 * Take the arguments given and put them onto the shutdown callout list.
386 * However first make sure that it's not already there.
387 * returns 0 on success.
388 */
389int
390at_shutdown(bootlist_fn function, void *arg)
391{
392	sle_p ep;
393	if(rm_at_shutdown(function, arg)) {
394		printf("exit callout entry already present\n");
395	}
396	ep = malloc(sizeof(*ep),M_TEMP,M_NOWAIT);
397	if(!ep) return ENOMEM;
398	ep->next = shutdown_list;
399	ep->function = function;
400	ep->arg = arg;
401	shutdown_list = ep;
402	return 0;
403}
404/*
405 * Scan the exit callout list for the given items and remove them.
406 * Returns the number of items removed.
407 */
408int
409rm_at_shutdown(bootlist_fn function, void *arg)
410{
411	sle_p *epp,ep;
412	int count = 0;
413
414	epp = &shutdown_list;
415	ep = *epp;
416	while(ep) {
417		if((ep->function == function) && (ep->arg = arg)) {
418			*epp = ep->next;
419			free(ep,M_TEMP);
420			count++;
421		} else {
422			epp = &ep->next;
423		}
424		ep = *epp;
425	}
426	return count;
427}
428
429
430