dplatt@coherent.com (Dave Platt) (10/11/88)
I've made some modifications to the Aufs file-server software in the CAP 5.0 distribution. With these changes in place, Aufs will "notice" that the superuser has issued a "shutdown" command; Aufs will notify its clients of the impending shutdown and ask that they log off. It is no longer necessary to manually send a "kill" signal to the Aufs daemon in order to trigger the shutdown sequence. Mechanism: The main Aufs daemon now checks roughly once per minute for the appearance of the "/etc/nologin" file. This file is written by the "/etc/shutdown" program five minutes before the system is actually shut down. When the Aufs daemon sees that this file has appeared, it sends a "terminate" signal to all session subprocesses (just as if it had received a "kill" signal from the superuser). When the user-session subprocesses receive a "terminate" signal, they check to see whether the /etc/nologin file exists. If it does, they enter an accelerated 3-minute shutdown cycle, rather than the usual 5-minute cycle. This ensures that the subprocesses will have had time to complete the 3-minute cycle and exit cleanly before the 5-minute /etc/shutdown sequence is completed. I've made one additional change to the shutdown code. When the main server process decides to shut down (either due to a "kill" signal or due to the appearance of the /etc/nologin file), it _immediately_ calls SrvrShutdown() to remove itself from the host's name-binding tables. In the release version of CAP 5.0, Aufs would not remove itself from the NBP tables until it was ready to exit; new users could connect to the server during the 5-minute shutdown cycle and be abruptly cut off without warning. These modifications were written for a SunOS 3.5 system, but should work OK on other BSD variants. Use 'em at your own risk; your mileage may vary. *** aufs.c.dist Wed Oct 5 13:51:58 1988 --- aufs.c Wed Oct 5 15:37:43 1988 *************** *** 61,66 **** --- 61,70 ---- # define NOSHUTDOWNCODE #endif + #ifndef NOSHUTDOWNCODE + # include <sys/stat.h> + #endif + /* known attention codes */ #define AFPSHUTDOWNTIME(x) (0x8000|((x)&0xfff)) #define AFPSHUTDOWNCANCEL (0x8fff) *************** *** 91,96 **** --- 95,103 ---- private int cno = -1; /* current connection */ #ifndef NOSHUTDOWNCODE private int minutes_to_shutdown = -1; + private struct stat nologin_status; + private int nologin_probe_cycle = 0; + private int nbp_shutdown_performed = 0; #endif /* if wait3 and usetimes isn't set, then we handle rusage from wait3 */ *************** *** 481,486 **** --- 488,504 ---- log("Waiting for session %d to activate", cno); /* won't wait if we set comp above */ while (comp > 0) { + #ifndef NOSHUTDOWNCODE + if (nologin_probe_cycle++ > 10) + { + nologin_probe_cycle = 0; + if (minutes_to_shutdown < 0 && + stat("/etc/nologin", &nologin_status) == 0) + { + killin3(); /* start shutdown */ + } + } + #endif abSleep(sectotick(5),TRUE); gcinferior(); } *************** *** 558,565 **** if (statflg) SrvrPrintStats(); /* print stats */ if (mypid == parent_pid) ! if ((err = SrvrShutdown(&srvr_entity_name)) != noErr) ! log("NBPRemove failed: code %d\n", err); exit(0); } --- 576,586 ---- if (statflg) SrvrPrintStats(); /* print stats */ if (mypid == parent_pid) ! #ifndef NOSHUTDOWNCODE ! if (!nbp_shutdown_performed) ! #endif ! if ((err = SrvrShutdown(&srvr_entity_name)) != noErr) ! log("NBPRemove failed: code %d\n", err); exit(0); } *************** *** 850,859 **** { int dying(); ! if (minutes_to_shutdown >= 0) /* already in shutdown mode */ ! return; ! log("Superior told us to shutdown by time -- initiating 5 minute shutdown"); ! minutes_to_shutdown = 5; dying(); /* start */ } --- 877,897 ---- { int dying(); ! if (stat("/etc/nologin", &nologin_status) == 0) ! { ! if (minutes_to_shutdown >= 0 && minutes_to_shutdown <= 3) ! /* already in shutdown mode */ ! return; ! log("Noticed /etc/nologin file: initiating 3-minute shutdown"); ! minutes_to_shutdown = 3; ! } ! else ! { ! if (minutes_to_shutdown >= 0) /* already in shutdown mode */ ! return; ! log("Superior told us to shutdown by time -- initiating 5 minute shutdown"); ! minutes_to_shutdown = 5; ! } dying(); /* start */ } *************** *** 868,875 **** signal (SIGHUP, SIG_IGN); log("Parent received SIGHUP -- immediate shutdown"); killpg (parent_pid, SIGHUP); ! if ((err = SrvrShutdown(&srvr_entity_name)) != noErr) ! log("NBPRemove failed: code %d\n", err); exit(0); } --- 906,914 ---- signal (SIGHUP, SIG_IGN); log("Parent received SIGHUP -- immediate shutdown"); killpg (parent_pid, SIGHUP); ! if (!nbp_shutdown_performed) ! if ((err = SrvrShutdown(&srvr_entity_name)) != noErr) ! log("NBPRemove failed: code %d\n", err); exit(0); } *************** *** 879,897 **** --- 918,966 ---- killin5() { int killinn(); + int err; signal (SIGTERM, SIG_IGN); log("Shutdown by time -- initiating 5 minute shutdown"); killpg (parent_pid, SIGTERM); minutes_to_shutdown = 4; + if (!nbp_shutdown_performed) + { + if ((err = SrvrShutdown(&srvr_entity_name)) == noErr) + nbp_shutdown_performed = 1; + else + log("NBPRemove failed: code %d\n", err); + } /* in case children get blocked up */ signal(SIGALRM, killinn); alarm(68); /* a litte more than a minute */ } + killin3() + { + int killinn(); + int err; + + signal (SIGTERM, SIG_IGN); + log("Shutdown by /etc/nologin -- initiating 3 minute shutdown"); + killpg (parent_pid, SIGTERM); + minutes_to_shutdown = 2; + if (!nbp_shutdown_performed) + { + if ((err = SrvrShutdown(&srvr_entity_name)) == noErr) + nbp_shutdown_performed = 1; + else + log("NBPRemove failed: code %d\n", err); + } + /* in case children get blocked up */ + signal(SIGALRM, killinn); + alarm(68); /* a litte more than a minute */ + } + killinn() { int killinn(); + int err; if (minutes_to_shutdown < 0) /* not in die mode */ return; -- Dave Platt VOICE: (415) 493-8805 USNAIL: Coherent Thought Inc. 3350 West Bayshore #205 Palo Alto CA 94303 UUCP: ...!{ames,sun,uunet}!coherent!dplatt DOMAIN: dplatt@coherent.com INTERNET: coherent!dplatt@ames.arpa, ...@sun.com, ...@uunet.uu.net