From owner-freebsd-hackers Wed Jan 21 07:16:17 1998 Return-Path: Received: (from majordom@localhost) by hub.freebsd.org (8.8.8/8.8.8) id HAA01756 for hackers-outgoing; Wed, 21 Jan 1998 07:16:17 -0800 (PST) (envelope-from owner-freebsd-hackers@FreeBSD.ORG) Received: from ibd.dbio.ro (ibd.dbio.ro [193.231.0.2]) by hub.freebsd.org (8.8.8/8.8.8) with ESMTP id HAA01624 for ; Wed, 21 Jan 1998 07:15:25 -0800 (PST) (envelope-from calin@ibd.dbio.ro) Received: from localhost (calin@localhost) by ibd.dbio.ro (8.8.7/8.8.7) with SMTP id RAA00343 for ; Wed, 21 Jan 1998 17:20:17 +0200 (EET) (envelope-from calin@ibd.dbio.ro) Date: Wed, 21 Jan 1998 17:20:16 +0200 (EET) From: Calin Andrian To: freebsd-hackers@FreeBSD.ORG Subject: Kernel patches for POWEROFF Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Sender: owner-freebsd-hackers@FreeBSD.ORG Precedence: bulk While playing with my APC back-ups I was advised by Bruce M. Walter that the POST_SYNC queue is not the safe place for a poweroff routine. The way to do it is to patch the kernel. The patches follow. The new, improved and packed with these diffs APC Back-UPS monitor is now: ftp://ftp.dbio.ro/pub/FreeBSD/local/apcb-0.2.tgz Sorry for respawning so rapidly. WHAT THE DIFFS CHANGE: at_shutdown() has a new queue named SHUTDOWN_POWEROFF which calls functions that are supposed to turn off the power (after POST_SYNC queue is done). This happens when /sbin/reboot and its links are run with -p switch. Maybe it should have been a single function not a whole queue, but the list ops were already there, so... /sbin/reboot no longer defines RB_HALT when called with -p switch. This means that if the poweroff fails, the system reboots for /sbin/reboot and halts for /sbin/halt. For example, if the APC back-ups has AC input, you cannot shut down the UPS (it ignores you). So, if the power was restored after you committed the system shutdown, the system restarts immediately. The original /sbin/reboot didn't allow this. If you don't want to reboot, use /sbin/halt ! DIFFS: (3 pcs) *** /usr/src/sys/kern/kern_shutdown.c.orig Wed Jan 21 12:53:39 1998 --- /usr/src/sys/kern/kern_shutdown.c Wed Jan 21 13:13:45 1998 *************** *** 118,123 **** --- 118,124 ---- */ static sle_p shutdown_list1; static sle_p shutdown_list2; + static sle_p shutdown_list3; static void dumpsys(void); *************** *** 247,252 **** --- 248,265 ---- (*ep->function)(howto, ep->arg); ep = ep->next; } + if (howto & RB_POWEROFF) { + printf("\nTurning off power...\n"); + DELAY(1000 * 1000); + ep = shutdown_list3; + while (ep) { + shutdown_list3 = ep->next; + (*ep->function)(howto, ep->arg); + ep = ep->next; + } + DELAY(5000 * 1000); /* Wait 5 secs for power off */ + /* Continue if power off failed */ + } splhigh(); if (howto & RB_HALT) { printf("\n"); *************** *** 411,416 **** --- 424,432 ---- case SHUTDOWN_POST_SYNC: epp = &shutdown_list2; break; + case SHUTDOWN_POWEROFF: + epp = &shutdown_list3; + break; default: printf("bad exit callout list specified\n"); return (EINVAL); *************** *** 451,456 **** --- 467,484 ---- ep = *epp; } epp = &shutdown_list2; + ep = *epp; + while (ep) { + if ((ep->function == function) && (ep->arg == arg)) { + *epp = ep->next; + free(ep, M_TEMP); + count++; + } else { + epp = &ep->next; + } + ep = *epp; + } + epp = &shutdown_list3; ep = *epp; while (ep) { if ((ep->function == function) && (ep->arg == arg)) { *** /usr/src/sbin/reboot/reboot.c.orig Wed Jan 21 13:09:08 1998 --- /usr/src/sbin/reboot/reboot.c Wed Jan 21 13:09:36 1998 *************** *** 85,91 **** break; case 'p': pflag = 1; ! howto |= (RB_POWEROFF | RB_HALT); break; case 'q': qflag = 1; --- 85,91 ---- break; case 'p': pflag = 1; ! howto |= RB_POWEROFF; break; case 'q': qflag = 1; *** /usr/src/sys/sys/systm.h.orig Wed Jan 21 13:11:56 1998 --- /usr/src/sys/sys/systm.h Wed Jan 21 13:11:27 1998 *************** *** 171,176 **** --- 171,177 ---- int rm_at_shutdown(bootlist_fn function, void *arg); #define SHUTDOWN_PRE_SYNC 0 #define SHUTDOWN_POST_SYNC 1 + #define SHUTDOWN_POWEROFF 2 /* forking */ /* XXX not yet */ typedef void (*forklist_fn)(struct proc *parent,struct proc *child,int flags);