aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Nugent <davidn@FreeBSD.org>1997-08-02 00:22:52 +0000
committerDavid Nugent <davidn@FreeBSD.org>1997-08-02 00:22:52 +0000
commit8889c700f314bb2d6fc652ff35a5f3d2d72f5edb (patch)
treeb30a25fc6d98b86c39709c71ad1c1c2baef283d7
parent4c33feed58599855e0c2d38e375d8a20900f33d1 (diff)
downloadsrc-8889c700f314bb2d6fc652ff35a5f3d2d72f5edb.tar.gz
src-8889c700f314bb2d6fc652ff35a5f3d2d72f5edb.zip
Add /etc/rc.shutdown capability to init.
Add sample /etc/rc.shutdown (which is just a shell for now). Submitted by: Ollivier Robert <roberto@keltia.freenix.fr>
Notes
Notes: svn path=/head/; revision=27837
-rw-r--r--etc/Makefile4
-rw-r--r--etc/rc.shutdown26
-rw-r--r--sbin/init/init.813
-rw-r--r--sbin/init/init.c175
-rw-r--r--sbin/init/pathnames.h1
5 files changed, 199 insertions, 20 deletions
diff --git a/etc/Makefile b/etc/Makefile
index 607099b4fc78..b19a1251a801 100644
--- a/etc/Makefile
+++ b/etc/Makefile
@@ -1,5 +1,5 @@
# from: @(#)Makefile 5.11 (Berkeley) 5/21/91
-# $Id: Makefile,v 1.152 1997/07/05 19:35:22 pst Exp $
+# $Id: Makefile,v 1.153 1997/07/18 03:49:47 asami Exp $
# -rw-r--r--
BINOWN= root
@@ -9,7 +9,7 @@ BIN1= aliases amd.map csh.cshrc csh.login csh.logout dm.conf \
inetd.conf login.conf login.access motd modems networks \
newsyslog.conf phones pccard.conf.sample printcap profile protocols \
rc rc.conf rc.firewall rc.local rc.network rc.pccard rc.serial \
- etc.${MACHINE}/rc.${MACHINE} \
+ rc.shutdown etc.${MACHINE}/rc.${MACHINE} \
remote security services shells \
syslog.conf ttys etc.${MACHINE}/disktab rpc make.conf \
${.CURDIR}/../gnu/usr.bin/man/manpath/manpath.config \
diff --git a/etc/rc.shutdown b/etc/rc.shutdown
new file mode 100644
index 000000000000..f935834d1898
--- /dev/null
+++ b/etc/rc.shutdown
@@ -0,0 +1,26 @@
+#!/bin/sh
+# $Id$
+
+# site-specific closing actions for daemons run by init on shutdown
+# or before going single-user from multi-user.
+# Output and errors are directed to console by init, and the
+# console is the controlling terminal.
+
+stty status '^T'
+
+# Set shell to ignore SIGINT (2), but not children;
+# shell catches SIGQUIT (3) and returns to single user after fsck.
+trap : 2
+trap : 3 # shouldn't be needed
+
+HOME=/; export HOME
+PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin
+export PATH
+
+echo -n Shutting down daemon processes:
+
+# Insert shutdown procedures here
+
+
+echo '.'
+exit 0
diff --git a/sbin/init/init.8 b/sbin/init/init.8
index 0591d9dcfe02..1b5bf5f7c7b2 100644
--- a/sbin/init/init.8
+++ b/sbin/init/init.8
@@ -33,7 +33,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)init.8 8.3 (Berkeley) 4/18/94
-.\" $Id: init.8,v 1.8 1997/02/22 14:32:34 peter Exp $
+.\" $Id: init.8,v 1.9 1997/04/01 20:41:04 mpp Exp $
.\"
.Dd April 18, 1994
.Dt INIT 8
@@ -241,6 +241,15 @@ signal, i.e.
This is useful for shutting the machine down cleanly from inside the kernel
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
is so critical that if it dies, the system will reboot itself
@@ -280,6 +289,8 @@ Record of all logins and logouts.
The terminal initialization information file.
.It Pa /etc/rc
System startup commands.
+.It Pa /etc/rc.shutdown
+System shutdown commands.
.El
.Sh SEE ALSO
.Xr kill 1 ,
diff --git a/sbin/init/init.c b/sbin/init/init.c
index a0b95c99d9be..d549f4a3f6cf 100644
--- a/sbin/init/init.c
+++ b/sbin/init/init.c
@@ -33,7 +33,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: init.c,v 1.22 1997/07/05 19:36:55 ache Exp $
+ * $Id: init.c,v 1.23 1997/07/08 11:51:11 ache Exp $
*/
#ifndef lint
@@ -47,6 +47,7 @@ static char sccsid[] = "@(#)init.c 8.1 (Berkeley) 7/15/93";
#endif /* not lint */
#include <sys/param.h>
+#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/sysctl.h>
#include <sys/wait.h>
@@ -91,6 +92,7 @@ static char sccsid[] = "@(#)init.c 8.1 (Berkeley) 7/15/93";
#define WINDOW_WAIT 3 /* wait N secs after starting window */
#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"
#define RESOURCE_GETTY "default"
@@ -103,6 +105,7 @@ void warning __P((char *, ...));
void emergency __P((char *, ...));
void disaster __P((int));
void badsys __P((int));
+int runshutdown __P((void));
/*
* We really need a recursive typedef...
@@ -309,7 +312,7 @@ handle(va_alist)
sa.sa_handler = handler;
sigfillset(&mask_everything);
- while (sig = va_arg(ap, int)) {
+ while ((sig = va_arg(ap, int)) != NULL) {
sa.sa_mask = mask_everything;
/* XXX SA_RESTART? */
sa.sa_flags = sig == SIGCHLD ? SA_NOCLDSTOP : 0;
@@ -340,7 +343,7 @@ delset(va_alist)
va_start(ap, maskp);
#endif
- while (sig = va_arg(ap, int))
+ while ((sig = va_arg(ap, int)) != NULL)
sigdelset(maskp, sig);
va_end(ap);
}
@@ -451,7 +454,7 @@ disaster(sig)
int sig;
{
emergency("fatal signal: %s",
- sig < (unsigned) NSIG ? sys_siglist[sig] : "unknown signal");
+ (unsigned)sig < NSIG ? sys_siglist[sig] : "unknown signal");
sleep(STALL_TIMEOUT);
_exit(sig); /* reboot */
@@ -891,7 +894,7 @@ construct_argv(command)
if ((argv[argc++] = strk(command)) == 0)
return 0;
- while (argv[argc++] = strk((char *) 0))
+ while ((argv[argc++] = strk((char *) 0)) != NULL)
continue;
return argv;
}
@@ -1051,8 +1054,8 @@ read_ttys()
* Allocate a session entry for each active port.
* Note that sp starts at 0.
*/
- while (typ = getttyent())
- if (snext = new_session(sp, ++session_index, typ))
+ while ((typ = getttyent()) != NULL)
+ if ((snext = new_session(sp, ++session_index, typ)) != NULL)
sp = snext;
endttyent();
@@ -1195,11 +1198,11 @@ collect_child(pid)
sp->se_process = 0;
if (sp->se_flags & SE_SHUTDOWN) {
- if (sprev = sp->se_prev)
+ if ((sprev = sp->se_prev) != NULL)
sprev->se_next = sp->se_next;
else
sessions = sp->se_next;
- if (snext = sp->se_next)
+ if ((snext = sp->se_next) != NULL)
snext->se_prev = sp->se_prev;
free_session(sp);
return;
@@ -1298,7 +1301,7 @@ clean_ttys()
return (state_func_t) multi_user;
devlen = sizeof(_PATH_DEV) - 1;
- while (typ = getttyent()) {
+ while ((typ = getttyent()) != NULL) {
++session_index;
for (sprev = 0, sp = sessions; sp; sprev = sp, sp = sp->se_next)
@@ -1329,13 +1332,13 @@ clean_ttys()
kill(sp->se_process, SIGHUP);
}
else if ( !old_getty
- || !old_type && sp->se_type
- || old_type && !sp->se_type
- || !old_window && sp->se_window
- || old_window && !sp->se_window
- || strcmp(old_getty, sp->se_getty) != 0
- || old_window && strcmp(old_window, sp->se_window) != 0
- || old_type && strcmp(old_type, sp->se_type) != 0
+ || (!old_type && sp->se_type)
+ || (old_type && !sp->se_type)
+ || (!old_window && sp->se_window)
+ || (old_window && !sp->se_window)
+ || (strcmp(old_getty, sp->se_getty) != 0)
+ || (old_window && strcmp(old_window, sp->se_window) != 0)
+ || (old_type && strcmp(old_type, sp->se_type) != 0)
) {
/* Don't set SE_SHUTDOWN here */
sp->se_nspace = 0;
@@ -1380,6 +1383,7 @@ void
alrm_handler(sig)
int sig;
{
+ (void)sig;
clang = 1;
}
@@ -1390,6 +1394,7 @@ state_func_t
death()
{
register session_t *sp;
+ register int rcdown;
register int i;
pid_t pid;
static const int death_sigs[2] = { SIGTERM, SIGKILL };
@@ -1402,6 +1407,9 @@ death()
(void) revoke(sp->se_device);
}
+ /* Try to run the rc.shutdown script within a period of time */
+ rcdown = runshutdown();
+
for (i = 0; i < 2; ++i) {
if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH)
return (state_func_t) single_user;
@@ -1421,6 +1429,139 @@ death()
return (state_func_t) single_user;
}
+
+/*
+ * Run the system shutdown script.
+ *
+ * Exit codes: XXX I should document more
+ * -2 shutdown script terminated abnormally
+ * -1 fatal error - can't run script
+ * 0 good.
+ * >0 some error (exit code)
+ */
+int
+runshutdown()
+{
+ pid_t pid, wpid;
+ int status;
+ int shutdowntimeout;
+ size_t len;
+ char *argv[3];
+ struct sigaction sa;
+
+ if ((pid = fork()) == 0) {
+ int fd;
+
+ setsid();
+ 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);
+
+ /*
+ * Clean our descriptor table to be sure of
+ * getting /dev/console as control terminal.
+ */
+ for (fd = getdtablesize(); fd-- > 0; )
+ (void)close(fd);
+
+ if ((fd = open(_PATH_CONSOLE, O_RDWR)) == -1)
+ warning("can't open %s: %m", _PATH_CONSOLE);
+ else {
+ if (ioctl(fd, TIOCSCTTY, (char *)NULL) == -1)
+ warning("can't get %s for controlling terminal: %m", _PATH_CONSOLE);
+ (void) dup2(fd, 1);
+ (void) dup2(fd, 2);
+ }
+
+ /*
+ * Run the shutdown script.
+ */
+ argv[0] = "sh";
+ argv[1] = _PATH_RUNDOWN;
+ argv[2] = 0;
+
+ sigprocmask(SIG_SETMASK, &sa.sa_mask, (sigset_t *) 0);
+
+ execv(_PATH_BSHELL, argv);
+ warning("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;
+ }
+
+ len = sizeof(shutdowntimeout);
+ if (sysctlbyname("kern.shutdown_timeout",
+ &shutdowntimeout,
+ &len, NULL, 0) == -1 || shutdowntimeout < 2)
+ shutdowntimeout = DEATH_SCRIPT;
+ alarm(shutdowntimeout);
+ clang = 0;
+ /*
+ * Copied from single_user(). This is a bit paranoid.
+ * Use the same ALRM handler.
+ */
+ do {
+ if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
+ collect_child(wpid);
+ if (clang == 1) {
+ /* we were waiting for the sub-shell */
+ kill(wpid, SIGTERM);
+ warning("timeout expired for %s on %s: %m; going to single used mode",
+ _PATH_BSHELL, _PATH_RUNDOWN);
+ return -1;
+ }
+ if (wpid == -1) {
+ if (errno == EINTR)
+ continue;
+ warning("wait for %s on %s failed: %m; going to single user mode",
+ _PATH_BSHELL, _PATH_RUNDOWN);
+ return -1;
+ }
+ 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);
+
+ /* Turn off the alarm */
+ alarm(0);
+
+ if (WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM &&
+ requested_transition == catatonia) {
+ /*
+ * /etc/rc.shutdown 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 -2;
+ }
+
+ if ((status = WEXITSTATUS(status)) != 0)
+ warning("%s returned status %d", _PATH_RUNDOWN, status);
+
+ return status;
+}
+
char *
strk (char *p)
{
diff --git a/sbin/init/pathnames.h b/sbin/init/pathnames.h
index abb874a4b988..27837f680b03 100644
--- a/sbin/init/pathnames.h
+++ b/sbin/init/pathnames.h
@@ -40,3 +40,4 @@
#define _PATH_SLOGGER "/sbin/session_logger"
#define _PATH_RUNCOM "/etc/rc"
+#define _PATH_RUNDOWN "/etc/rc.shutdown"