mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-30 16:51:41 +00:00
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
|
||||
# $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 \
|
||||
|
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.
|
||||
.\"
|
||||
.\" @(#)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 ,
|
||||
|
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
|
||||
* 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)
|
||||
{
|
||||
|
@ -40,3 +40,4 @@
|
||||
|
||||
#define _PATH_SLOGGER "/sbin/session_logger"
|
||||
#define _PATH_RUNCOM "/etc/rc"
|
||||
#define _PATH_RUNDOWN "/etc/rc.shutdown"
|
||||
|
Loading…
Reference in New Issue
Block a user