[comp.protocols.appletalk] Automatic shutdown of Aufs file-server

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