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>
This commit is contained in:
parent
4c33feed58
commit
8889c700f3
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=27837
@ -1,5 +1,5 @@
|
|||||||
# from: @(#)Makefile 5.11 (Berkeley) 5/21/91
|
# 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--
|
# -rw-r--r--
|
||||||
BINOWN= root
|
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 \
|
inetd.conf login.conf login.access motd modems networks \
|
||||||
newsyslog.conf phones pccard.conf.sample printcap profile protocols \
|
newsyslog.conf phones pccard.conf.sample printcap profile protocols \
|
||||||
rc rc.conf rc.firewall rc.local rc.network rc.pccard rc.serial \
|
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 \
|
remote security services shells \
|
||||||
syslog.conf ttys etc.${MACHINE}/disktab rpc make.conf \
|
syslog.conf ttys etc.${MACHINE}/disktab rpc make.conf \
|
||||||
${.CURDIR}/../gnu/usr.bin/man/manpath/manpath.config \
|
${.CURDIR}/../gnu/usr.bin/man/manpath/manpath.config \
|
||||||
|
26
etc/rc.shutdown
Normal file
26
etc/rc.shutdown
Normal file
@ -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
|
@ -33,7 +33,7 @@
|
|||||||
.\" SUCH DAMAGE.
|
.\" SUCH DAMAGE.
|
||||||
.\"
|
.\"
|
||||||
.\" @(#)init.8 8.3 (Berkeley) 4/18/94
|
.\" @(#)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
|
.Dd April 18, 1994
|
||||||
.Dt INIT 8
|
.Dt INIT 8
|
||||||
@ -241,6 +241,15 @@ signal, i.e.
|
|||||||
This is useful for shutting the machine down cleanly from inside the kernel
|
This is useful for shutting the machine down cleanly from inside the kernel
|
||||||
or from X when the machine appears to be hung.
|
or from X when the machine appears to be hung.
|
||||||
.Pp
|
.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
|
The role of
|
||||||
.Nm init
|
.Nm init
|
||||||
is so critical that if it dies, the system will reboot itself
|
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.
|
The terminal initialization information file.
|
||||||
.It Pa /etc/rc
|
.It Pa /etc/rc
|
||||||
System startup commands.
|
System startup commands.
|
||||||
|
.It Pa /etc/rc.shutdown
|
||||||
|
System shutdown commands.
|
||||||
.El
|
.El
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr kill 1 ,
|
.Xr kill 1 ,
|
||||||
|
175
sbin/init/init.c
175
sbin/init/init.c
@ -33,7 +33,7 @@
|
|||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* 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
|
#ifndef lint
|
||||||
@ -47,6 +47,7 @@ static char sccsid[] = "@(#)init.c 8.1 (Berkeley) 7/15/93";
|
|||||||
#endif /* not lint */
|
#endif /* not lint */
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#include <sys/wait.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 WINDOW_WAIT 3 /* wait N secs after starting window */
|
||||||
#define STALL_TIMEOUT 30 /* wait N secs after warning */
|
#define STALL_TIMEOUT 30 /* wait N secs after warning */
|
||||||
#define DEATH_WATCH 10 /* wait N secs for procs to die */
|
#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_RC "daemon"
|
||||||
#define RESOURCE_WINDOW "default"
|
#define RESOURCE_WINDOW "default"
|
||||||
#define RESOURCE_GETTY "default"
|
#define RESOURCE_GETTY "default"
|
||||||
@ -103,6 +105,7 @@ void warning __P((char *, ...));
|
|||||||
void emergency __P((char *, ...));
|
void emergency __P((char *, ...));
|
||||||
void disaster __P((int));
|
void disaster __P((int));
|
||||||
void badsys __P((int));
|
void badsys __P((int));
|
||||||
|
int runshutdown __P((void));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We really need a recursive typedef...
|
* We really need a recursive typedef...
|
||||||
@ -309,7 +312,7 @@ handle(va_alist)
|
|||||||
sa.sa_handler = handler;
|
sa.sa_handler = handler;
|
||||||
sigfillset(&mask_everything);
|
sigfillset(&mask_everything);
|
||||||
|
|
||||||
while (sig = va_arg(ap, int)) {
|
while ((sig = va_arg(ap, int)) != NULL) {
|
||||||
sa.sa_mask = mask_everything;
|
sa.sa_mask = mask_everything;
|
||||||
/* XXX SA_RESTART? */
|
/* XXX SA_RESTART? */
|
||||||
sa.sa_flags = sig == SIGCHLD ? SA_NOCLDSTOP : 0;
|
sa.sa_flags = sig == SIGCHLD ? SA_NOCLDSTOP : 0;
|
||||||
@ -340,7 +343,7 @@ delset(va_alist)
|
|||||||
va_start(ap, maskp);
|
va_start(ap, maskp);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (sig = va_arg(ap, int))
|
while ((sig = va_arg(ap, int)) != NULL)
|
||||||
sigdelset(maskp, sig);
|
sigdelset(maskp, sig);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
@ -451,7 +454,7 @@ disaster(sig)
|
|||||||
int sig;
|
int sig;
|
||||||
{
|
{
|
||||||
emergency("fatal signal: %s",
|
emergency("fatal signal: %s",
|
||||||
sig < (unsigned) NSIG ? sys_siglist[sig] : "unknown signal");
|
(unsigned)sig < NSIG ? sys_siglist[sig] : "unknown signal");
|
||||||
|
|
||||||
sleep(STALL_TIMEOUT);
|
sleep(STALL_TIMEOUT);
|
||||||
_exit(sig); /* reboot */
|
_exit(sig); /* reboot */
|
||||||
@ -891,7 +894,7 @@ construct_argv(command)
|
|||||||
|
|
||||||
if ((argv[argc++] = strk(command)) == 0)
|
if ((argv[argc++] = strk(command)) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
while (argv[argc++] = strk((char *) 0))
|
while ((argv[argc++] = strk((char *) 0)) != NULL)
|
||||||
continue;
|
continue;
|
||||||
return argv;
|
return argv;
|
||||||
}
|
}
|
||||||
@ -1051,8 +1054,8 @@ read_ttys()
|
|||||||
* Allocate a session entry for each active port.
|
* Allocate a session entry for each active port.
|
||||||
* Note that sp starts at 0.
|
* Note that sp starts at 0.
|
||||||
*/
|
*/
|
||||||
while (typ = getttyent())
|
while ((typ = getttyent()) != NULL)
|
||||||
if (snext = new_session(sp, ++session_index, typ))
|
if ((snext = new_session(sp, ++session_index, typ)) != NULL)
|
||||||
sp = snext;
|
sp = snext;
|
||||||
|
|
||||||
endttyent();
|
endttyent();
|
||||||
@ -1195,11 +1198,11 @@ collect_child(pid)
|
|||||||
sp->se_process = 0;
|
sp->se_process = 0;
|
||||||
|
|
||||||
if (sp->se_flags & SE_SHUTDOWN) {
|
if (sp->se_flags & SE_SHUTDOWN) {
|
||||||
if (sprev = sp->se_prev)
|
if ((sprev = sp->se_prev) != NULL)
|
||||||
sprev->se_next = sp->se_next;
|
sprev->se_next = sp->se_next;
|
||||||
else
|
else
|
||||||
sessions = sp->se_next;
|
sessions = sp->se_next;
|
||||||
if (snext = sp->se_next)
|
if ((snext = sp->se_next) != NULL)
|
||||||
snext->se_prev = sp->se_prev;
|
snext->se_prev = sp->se_prev;
|
||||||
free_session(sp);
|
free_session(sp);
|
||||||
return;
|
return;
|
||||||
@ -1298,7 +1301,7 @@ clean_ttys()
|
|||||||
return (state_func_t) multi_user;
|
return (state_func_t) multi_user;
|
||||||
|
|
||||||
devlen = sizeof(_PATH_DEV) - 1;
|
devlen = sizeof(_PATH_DEV) - 1;
|
||||||
while (typ = getttyent()) {
|
while ((typ = getttyent()) != NULL) {
|
||||||
++session_index;
|
++session_index;
|
||||||
|
|
||||||
for (sprev = 0, sp = sessions; sp; sprev = sp, sp = sp->se_next)
|
for (sprev = 0, sp = sessions; sp; sprev = sp, sp = sp->se_next)
|
||||||
@ -1329,13 +1332,13 @@ clean_ttys()
|
|||||||
kill(sp->se_process, SIGHUP);
|
kill(sp->se_process, SIGHUP);
|
||||||
}
|
}
|
||||||
else if ( !old_getty
|
else if ( !old_getty
|
||||||
|| !old_type && sp->se_type
|
|| (!old_type && sp->se_type)
|
||||||
|| old_type && !sp->se_type
|
|| (old_type && !sp->se_type)
|
||||||
|| !old_window && sp->se_window
|
|| (!old_window && sp->se_window)
|
||||||
|| old_window && !sp->se_window
|
|| (old_window && !sp->se_window)
|
||||||
|| strcmp(old_getty, sp->se_getty) != 0
|
|| (strcmp(old_getty, sp->se_getty) != 0)
|
||||||
|| old_window && strcmp(old_window, sp->se_window) != 0
|
|| (old_window && strcmp(old_window, sp->se_window) != 0)
|
||||||
|| old_type && strcmp(old_type, sp->se_type) != 0
|
|| (old_type && strcmp(old_type, sp->se_type) != 0)
|
||||||
) {
|
) {
|
||||||
/* Don't set SE_SHUTDOWN here */
|
/* Don't set SE_SHUTDOWN here */
|
||||||
sp->se_nspace = 0;
|
sp->se_nspace = 0;
|
||||||
@ -1380,6 +1383,7 @@ void
|
|||||||
alrm_handler(sig)
|
alrm_handler(sig)
|
||||||
int sig;
|
int sig;
|
||||||
{
|
{
|
||||||
|
(void)sig;
|
||||||
clang = 1;
|
clang = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1390,6 +1394,7 @@ state_func_t
|
|||||||
death()
|
death()
|
||||||
{
|
{
|
||||||
register session_t *sp;
|
register session_t *sp;
|
||||||
|
register int rcdown;
|
||||||
register int i;
|
register int i;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
static const int death_sigs[2] = { SIGTERM, SIGKILL };
|
static const int death_sigs[2] = { SIGTERM, SIGKILL };
|
||||||
@ -1402,6 +1407,9 @@ death()
|
|||||||
(void) revoke(sp->se_device);
|
(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) {
|
for (i = 0; i < 2; ++i) {
|
||||||
if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH)
|
if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH)
|
||||||
return (state_func_t) single_user;
|
return (state_func_t) single_user;
|
||||||
@ -1421,6 +1429,139 @@ death()
|
|||||||
|
|
||||||
return (state_func_t) single_user;
|
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 *
|
char *
|
||||||
strk (char *p)
|
strk (char *p)
|
||||||
{
|
{
|
||||||
|
@ -40,3 +40,4 @@
|
|||||||
|
|
||||||
#define _PATH_SLOGGER "/sbin/session_logger"
|
#define _PATH_SLOGGER "/sbin/session_logger"
|
||||||
#define _PATH_RUNCOM "/etc/rc"
|
#define _PATH_RUNCOM "/etc/rc"
|
||||||
|
#define _PATH_RUNDOWN "/etc/rc.shutdown"
|
||||||
|
Loading…
Reference in New Issue
Block a user