Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 7 Jul 1997 22:51:49 +0200
From:      Ollivier Robert <roberto@keltia.freenix.fr>
To:        hackers@FreeBSD.ORG
Subject:   /etc/rc.shutdown (Was: Re: DEVFS permissions &c.)
Message-ID:  <19970707225149.19828@keltia.freenix.fr>
In-Reply-To: <Mutt.19970112183542.j@uriah.heep.sax.de>; from J Wunsch on Sun, Jan 12, 1997 at 06:35:42PM %2B0100
References:  <Mutt.19970111201007.j@uriah.heep.sax.de> <16902.853042470@time.cdrom.com> <Mutt.19970112112012.j@uriah.heep.sax.de> <Mutt.19970112160314.roberto@keltia.freenix.fr> <Mutt.19970112183542.j@uriah.heep.sax.de>

next in thread | previous in thread | raw e-mail | index | archive | help
[ digging this old mail from my archive, I love Glimpse ]

According to J Wunsch (a long time ago):
> I think stall() is the wrong thing to do here.  If the shutdown script
> fails, it's best to log what can be logged, and proceed to really shut
> down the system to the desired state.

stall() is the same function as warning() except that it waits for
STALL_TIMEOUT (browsing through init.c again, there are a fes places where
warning() is used and then a sleep() is done just after...). Both are
syslogging.

So even with stall, it will proceed if runshutdown() returns.

In this case, stall is better IMO because if you're at the console you'll
have time to see the message... If not, you won't be too disturbed (except
by waiting a bit more of course).

> Here's an alarm() missing, to prevent infinite hangs of the shutdown
> script.  Such an infinite hang should be answered with sending
> rc.shutdown a terminate signal, and by syslogging it.

Will do.

What do you people think of this (against current of course) ? My ALRM
handling may be a bit off track so I welcome comments (and diffs :-)).

Index: init.8
===================================================================
RCS file: /spare/FreeBSD-current/src/sbin/init/init.8,v
retrieving revision 1.9
diff -u -2 -r1.9 init.8
--- init.8	1997/04/01 20:41:04	1.9
+++ init.8	1997/07/07 20:19:36
@@ -242,4 +242,13 @@
 or from X when the machine appears to be hung.
 .Pp
+When shuting down the machine,
+.Nm init
+will try to run the
+.Pa /etc/rc.shutdown
+script. This script can be used to cleanly terminate specific programs such
+as
+.Nm innd
+(the InterNetNews server).
+.Pp
 The role of
 .Nm init
@@ -281,4 +290,6 @@
 .It Pa /etc/rc
 System startup commands.
+.It Pa /etc/rc.shutdown
+System shutdown commands.
 .El
 .Sh SEE ALSO
Index: init.c
===================================================================
RCS file: /spare/FreeBSD-current/src/sbin/init/init.c,v
retrieving revision 1.17
diff -u -2 -r1.17 init.c
--- init.c	1997/06/13 06:24:42	1.17
+++ init.c	1997/07/07 20:49:39
@@ -98,4 +98,5 @@
 #define	STALL_TIMEOUT		30	/* wait N secs after warning */
 #define	DEATH_WATCH		10	/* wait N secs for procs to die */
+#define DEATH_SCRIPT		120	/* wait for 2mn for /etc/rc.shutdown */
 #define RESOURCE_RC		"daemon"
 #define RESOURCE_WINDOW 	"default"
@@ -110,4 +111,5 @@
 void disaster __P((int));
 void badsys __P((int));
+int  runshutdown __P((void));
 
 /*
@@ -1385,4 +1387,5 @@
 {
 	register session_t *sp;
+	register int rcdown;
 	register int i;
 	pid_t pid;
@@ -1392,4 +1395,10 @@
 		sp->se_flags |= SE_SHUTDOWN;
 
+	/* Try to run the rc.shutdown script within a period of time */
+	rcdown = runshutdown();
+	if (rcdown)		
+		stall("Could not run %s, proceeding with shutdown anyway.", 
+		      _PATH_RUNDOWN);
+    
 	/* NB: should send a message to the session logger to avoid blocking. */
 	logwtmp("~", "shutdown", "");
@@ -1413,4 +1422,99 @@
 
 	return (state_func_t) single_user;
+}
+
+/*
+ * Run the system shutdown script.
+ *
+ * Exit codes:      XXX I should document more
+ * 0        good.
+ * 1        fatal error
+ * 2        some error
+ */
+int
+runshutdown()
+{
+	pid_t pid, wpid;
+	int status;
+	char *argv[3];
+	struct sigaction sa;
+
+	if ((pid = fork()) == 0) {
+		sigemptyset(&sa.sa_mask);
+		sa.sa_flags = 0;
+		sa.sa_handler = SIG_IGN;
+		(void) sigaction(SIGTSTP, &sa, (struct sigaction *)0);
+		(void) sigaction(SIGHUP, &sa, (struct sigaction *)0);
+
+		setctty(_PATH_CONSOLE);
+
+		argv[0] = "sh";
+		argv[1] = _PATH_RUNDOWN;
+		argv[2] = 0;
+
+		sigprocmask(SIG_SETMASK, &sa.sa_mask, (sigset_t *) 0);
+
+		execv(_PATH_BSHELL, argv);
+		stall("can't exec %s for %s: %m", _PATH_BSHELL, _PATH_RUNDOWN);
+		_exit(1);	/* force single user mode */
+	}
+
+	if (pid == -1) {
+		emergency("can't fork for %s on %s: %m",
+			_PATH_BSHELL, _PATH_RUNDOWN);
+		while (waitpid(-1, (int *) 0, WNOHANG) > 0)
+			continue;
+		sleep(STALL_TIMEOUT);
+		return 1;
+	}
+
+	/*
+	 * Copied from single_user().  This is a bit paranoid.
+	 * Use the same ALRM handler.
+	 */
+	alarm(DEATH_SCRIPT);
+	do {
+		if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
+			collect_child(wpid);
+		if (wpid == -1 || clang == 1) {
+			if (errno == EINTR)
+				continue;
+			if (clang) {
+				/* we were waiting for the sub-shell */
+				kill(wpid, SIGTERM);
+				warning("timeout expired for %s on %s: %m; goinh to single used mode",
+					_PATH_BSHELL, _PATH_RUNDOWN);
+			}
+			else
+				warning("wait for %s on %s failed: %m; going to single user mode",
+				_PATH_BSHELL, _PATH_RUNDOWN);
+			return 2;
+		}
+		if (wpid == pid && WIFSTOPPED(status)) {
+			warning("init: %s on %s stopped, restarting\n",
+				_PATH_BSHELL, _PATH_RUNDOWN);
+			kill(pid, SIGCONT);
+			wpid = -1;
+		}
+	} while (wpid != pid && !clang);
+
+	if (WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM &&
+	    requested_transition == catatonia) {
+		/* /etc/rc executed /sbin/reboot; wait for the end quietly */
+		sigset_t s;
+
+		sigfillset(&s);
+		for (;;)
+			sigsuspend(&s);
+	}
+
+	if (!WIFEXITED(status)) {
+		warning("%s on %s terminated abnormally, going to single user mode",
+			_PATH_BSHELL, _PATH_RUNDOWN);
+		return 1;
+	}
+
+	if (WEXITSTATUS(status))
+		return 2;
 }
 char *
Index: pathnames.h
===================================================================
RCS file: /spare/FreeBSD-current/src/sbin/init/pathnames.h,v
retrieving revision 1.1.1.1
diff -u -2 -r1.1.1.1 pathnames.h
--- pathnames.h	1994/05/26 06:34:19	1.1.1.1
+++ pathnames.h	1997/07/07 20:19:36
@@ -41,2 +41,3 @@
 #define	_PATH_SLOGGER	"/sbin/session_logger"
 #define	_PATH_RUNCOM	"/etc/rc"
+#define _PATH_RUNDOWN   "/etc/rc.shutdown"


-- 
Ollivier ROBERT -=- FreeBSD: There are no limits -=- roberto@keltia.freenix.fr
FreeBSD keltia.freenix.fr 3.0-CURRENT #20: Fri Jun 13 00:16:13 CEST 1997



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?19970707225149.19828>