kern_shutdown.c revision 21673
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 * $FreeBSD: head/sys/kern/kern_shutdown.c 21673 1997-01-14 07:20:47Z jkh $ 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/conf.h> 57#include <sys/sysproto.h> 58 59#include <machine/pcb.h> 60#include <machine/clock.h> 61#include <machine/cons.h> 62#include <machine/md_var.h> 63 64#include <sys/utsname.h> 65#include <sys/signalvar.h> 66 67#ifndef PANIC_REBOOT_WAIT_TIME 68#define PANIC_REBOOT_WAIT_TIME 15 /* default to 15 seconds */ 69#endif 70 71/* 72 * Note that stdarg.h and the ANSI style va_start macro is used for both 73 * ANSI and traditional C compilers. 74 */ 75#include <machine/stdarg.h> 76 77#if defined(DDB) 78#ifdef DDB_UNATTENDED 79 static int debugger_on_panic = 0; 80#else 81 static int debugger_on_panic = 1; 82#endif 83 84SYSCTL_INT(_debug, OID_AUTO, debugger_on_panic, CTLFLAG_RW, 85 &debugger_on_panic, 0, ""); 86#endif 87 88 89/* 90 * Variable panicstr contains argument to first call to panic; used as flag 91 * to indicate that the kernel has already called panic. 92 */ 93const char *panicstr; 94 95/* 96 * callout list for things to do a shutdown 97 */ 98typedef struct shutdown_list_element { 99 struct shutdown_list_element *next; 100 bootlist_fn function; 101 void *arg; 102} *sle_p; 103 104/* 105 * there are two shutdown lists. Some things need to be shut down 106 * Earlier than others. 107 */ 108static sle_p shutdown_list1; 109static sle_p shutdown_list2; 110 111 112static void dumpsys(void); 113 114#ifndef _SYS_SYSPROTO_H_ 115struct reboot_args { 116 int opt; 117}; 118#endif 119/* ARGSUSED */ 120 121/* 122 * The system call that results in a reboot 123 */ 124int 125reboot(p, uap, retval) 126 struct proc *p; 127 struct reboot_args *uap; 128 int *retval; 129{ 130 int error; 131 132 if ((error = suser(p->p_ucred, &p->p_acflag))) 133 return (error); 134 135 boot(uap->opt); 136 return (0); 137} 138 139/* 140 * Called by events that want to shut down.. e.g <CTL><ALT><DEL> on a PC 141 */ 142void 143shutdown_nice(void) 144{ 145 /* Send a signal to init(8) and have it shutdown the world */ 146 if (initproc != NULL) { 147 psignal(initproc, SIGINT); 148 } else { 149 /* No init(8) running, so simply reboot */ 150 boot(RB_NOSYNC); 151 } 152 return; 153} 154static int waittime = -1; 155static struct pcb dumppcb; 156 157/* 158 * Go through the rigmarole of shutting down.. 159 * this used to be in machdep.c but I'll be dammned if I could see 160 * anything machine dependant in it. 161 */ 162void 163boot(howto) 164 int howto; 165{ 166 sle_p ep; 167 168 ep = shutdown_list1; 169 while (ep) { 170 shutdown_list1 = ep->next; 171 (*ep->function)(howto, ep->arg); 172 ep = ep->next; 173 } 174 if (!cold && (howto & RB_NOSYNC) == 0 && waittime < 0) { 175 register struct buf *bp; 176 int iter, nbusy; 177 178 waittime = 0; 179 printf("\nsyncing disks... "); 180 181 sync(&proc0, NULL, NULL); 182 183 for (iter = 0; iter < 20; iter++) { 184 nbusy = 0; 185 for (bp = &buf[nbuf]; --bp >= buf; ) { 186 if ((bp->b_flags & (B_BUSY | B_INVAL)) == B_BUSY) { 187 nbusy++; 188 } 189 } 190 if (nbusy == 0) 191 break; 192 printf("%d ", nbusy); 193 DELAY(40000 * iter); 194 } 195 if (nbusy) { 196 /* 197 * Failed to sync all blocks. Indicate this and don't 198 * unmount filesystems (thus forcing an fsck on reboot). 199 */ 200 printf("giving up\n"); 201#ifdef SHOW_BUSYBUFS 202 nbusy = 0; 203 for (bp = &buf[nbuf]; --bp >= buf; ) { 204 if ((bp->b_flags & (B_BUSY | B_INVAL)) == B_BUSY) { 205 nbusy++; 206 printf("%d: dev:%08x, flags:%08x, blkno:%d, lblkno:%d\n", nbusy, bp->b_dev, bp->b_flags, bp->b_blkno, bp->b_lblkno); 207 } 208 } 209 DELAY(5000000); /* 5 seconds */ 210#endif 211 } else { 212 printf("done\n"); 213 /* 214 * Unmount filesystems 215 */ 216 if (panicstr == 0) 217 vfs_unmountall(); 218 } 219 DELAY(100000); /* wait for console output to finish */ 220 } 221 ep = shutdown_list2; 222 while (ep) { 223 shutdown_list2 = ep->next; 224 (*ep->function)(howto, ep->arg); 225 ep = ep->next; 226 } 227 splhigh(); 228 if (howto & RB_HALT) { 229 printf("\n"); 230 printf("The operating system has halted.\n"); 231 printf("Please press any key to reboot.\n\n"); 232 switch (cngetc()) { 233 case -1: /* No console, just die */ 234 cpu_halt(); 235 /* NOTREACHED */ 236 default: 237 break; 238 } 239 } else { 240 if (howto & RB_DUMP) { 241 if (!cold) { 242 savectx(&dumppcb); 243 dumppcb.pcb_cr3 = rcr3(); 244 dumpsys(); 245 } 246 247 if (PANIC_REBOOT_WAIT_TIME != 0) { 248 if (PANIC_REBOOT_WAIT_TIME != -1) { 249 int loop; 250 printf("Automatic reboot in %d seconds - press a key on the console to abort\n", 251 PANIC_REBOOT_WAIT_TIME); 252 for (loop = PANIC_REBOOT_WAIT_TIME * 10; loop > 0; --loop) { 253 DELAY(1000 * 100); /* 1/10th second */ 254 /* Did user type a key? */ 255 if (cncheckc() != -1) 256 break; 257 } 258 if (!loop) 259 goto die; 260 } 261 } else { /* zero time specified - reboot NOW */ 262 goto die; 263 } 264 printf("--> Press a key on the console to reboot <--\n"); 265 cngetc(); 266 } 267 } 268die: 269 printf("Rebooting...\n"); 270 DELAY(1000000); /* wait 1 sec for printf's to complete and be read */ 271 /* cpu_boot(howto); */ /* doesn't do anything at the moment */ 272 cpu_reset(); 273 for(;;) ; 274 /* NOTREACHED */ 275} 276 277/* 278 * Magic number for savecore 279 * 280 * exported (symorder) and used at least by savecore(8) 281 * 282 */ 283static u_long const dumpmag = 0x8fca0101UL; 284 285static int dumpsize = 0; /* also for savecore */ 286 287static int dodump = 1; 288SYSCTL_INT(_machdep, OID_AUTO, do_dump, CTLFLAG_RW, &dodump, 0, ""); 289 290/* 291 * Doadump comes here after turning off memory management and 292 * getting on the dump stack, either when called above, or by 293 * the auto-restart code. 294 */ 295static void 296dumpsys(void) 297{ 298 299 if (!dodump) 300 return; 301 if (dumpdev == NODEV) 302 return; 303 if ((minor(dumpdev)&07) != 1) 304 return; 305 if (!(bdevsw[major(dumpdev)])) 306 return; 307 if (!(bdevsw[major(dumpdev)]->d_dump)) 308 return; 309 dumpsize = Maxmem; 310 printf("\ndumping to dev %lx, offset %ld\n", dumpdev, dumplo); 311 printf("dump "); 312 switch ((*bdevsw[major(dumpdev)]->d_dump)(dumpdev)) { 313 314 case ENXIO: 315 printf("device bad\n"); 316 break; 317 318 case EFAULT: 319 printf("device not ready\n"); 320 break; 321 322 case EINVAL: 323 printf("area improper\n"); 324 break; 325 326 case EIO: 327 printf("i/o error\n"); 328 break; 329 330 case EINTR: 331 printf("aborted from console\n"); 332 break; 333 334 default: 335 printf("succeeded\n"); 336 break; 337 } 338} 339 340/* 341 * Panic is called on unresolvable fatal errors. It prints "panic: mesg", 342 * and then reboots. If we are called twice, then we avoid trying to sync 343 * the disks as this often leads to recursive panics. 344 */ 345void 346panic(const char *fmt, ...) 347{ 348 int bootopt; 349 va_list ap; 350 351 bootopt = RB_AUTOBOOT | RB_DUMP; 352 if (panicstr) 353 bootopt |= RB_NOSYNC; 354 else 355 panicstr = fmt; 356 357 printf("panic: "); 358 va_start(ap, fmt); 359 vprintf(fmt, ap); 360 va_end(ap); 361 printf("\n"); 362 363#if defined(DDB) 364 if (debugger_on_panic) 365 Debugger ("panic"); 366#endif 367 boot(bootopt); 368} 369 370/* 371 * Two routines to handle adding/deleting items on the 372 * shutdown callout lists 373 * 374 * at_shutdown(): 375 * Take the arguments given and put them onto the shutdown callout list. 376 * However first make sure that it's not already there. 377 * returns 0 on success. 378 */ 379int 380at_shutdown(bootlist_fn function, void *arg, int position) 381{ 382 sle_p ep, *epp; 383 384 switch(position) { 385 case SHUTDOWN_PRE_SYNC: 386 epp = &shutdown_list1; 387 break; 388 case SHUTDOWN_POST_SYNC: 389 epp = &shutdown_list2; 390 break; 391 default: 392 printf("bad exit callout list specified\n"); 393 return (EINVAL); 394 } 395 if (rm_at_shutdown(function, arg)) 396 printf("exit callout entry already present\n"); 397 ep = malloc(sizeof(*ep), M_TEMP, M_NOWAIT); 398 if (ep == NULL) 399 return (ENOMEM); 400 ep->next = *epp; 401 ep->function = function; 402 ep->arg = arg; 403 *epp = ep; 404 return (0); 405} 406 407/* 408 * Scan the exit callout lists for the given items and remove them. 409 * Returns the number of items removed. 410 */ 411int 412rm_at_shutdown(bootlist_fn function, void *arg) 413{ 414 sle_p *epp, ep; 415 int count; 416 417 count = 0; 418 epp = &shutdown_list1; 419 ep = *epp; 420 while (ep) { 421 if ((ep->function == function) && (ep->arg == arg)) { 422 *epp = ep->next; 423 free(ep, M_TEMP); 424 count++; 425 } else { 426 epp = &ep->next; 427 } 428 ep = *epp; 429 } 430 epp = &shutdown_list2; 431 ep = *epp; 432 while (ep) { 433 if ((ep->function == function) && (ep->arg == arg)) { 434 *epp = ep->next; 435 free(ep, M_TEMP); 436 count++; 437 } else { 438 epp = &ep->next; 439 } 440 ep = *epp; 441 } 442 return (count); 443} 444 445