Date: Fri, 3 Apr 1998 18:41:43 -0800 (PST) From: tonyg@nt.com.au To: freebsd-gnats-submit@FreeBSD.ORG Subject: bin/6206: Enhancements to the shutdown program Message-ID: <199804040241.SAA08346@hub.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 6206 >Category: bin >Synopsis: Enhancements to the shutdown program >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Fri Apr 3 18:50:00 PST 1998 >Last-Modified: >Originator: Tony Griffiths >Organization: Network Technologies P/L >Release: 2.2.6-STABLE >Environment: fjholden:sbin/shutdown# uname -a FreeBSD fjholden.OntheNet.com.au 2.2.6-STABLE FreeBSD 2.2.6-STABLE #0: Thu Mar 26 16:47:50 EST 1998 root@fjholden.OntheNet.com.au:/usr/src/sys/compile/FJHOLDEN i386 >Description: Add script execution with timeout to the shutdown program to allow orderly termination of applications. >How-To-Repeat: Machine readable diffs can be obtained using anonymous ftp from- ftp://diablo.onthenet.com.au/pub/unix/FreeBSD/shutdown-diffs.tar.gz >Fix: *** pathnames.h-orig Thu May 26 16:34:58 1994 --- pathnames.h Mon Mar 30 10:49:12 1998 *************** *** 39,41 **** --- 39,42 ---- #define _PATH_HALT "/sbin/halt" #define _PATH_REBOOT "/sbin/reboot" #define _PATH_WALL "/usr/bin/wall" + #define _PATH_RUNDOWN "/etc/rc.shutdown" *** shutdown.8-orig Wed Mar 11 12:10:48 1998 --- shutdown.8 Wed Mar 11 15:29:03 1998 *************** *** 31,37 **** .\" .\" @(#)shutdown.8 8.1 (Berkeley) 6/5/93 .\" ! .Dd June 5, 1993 .Dt SHUTDOWN 8 .Os BSD 4 .Sh NAME --- 31,37 ---- .\" .\" @(#)shutdown.8 8.1 (Berkeley) 6/5/93 .\" ! .Dd March 11, 1998 .Dt SHUTDOWN 8 .Os BSD 4 .Sh NAME *************** *** 40,46 **** .Sh SYNOPSIS .Nm shutdown .Op Fl ! .Op Fl hkrn .Ar time .Op Ar warning-message ... .Sh DESCRIPTION --- 40,46 ---- .Sh SYNOPSIS .Nm shutdown .Op Fl ! .Op Fl hkrnst .Ar time .Op Ar warning-message ... .Sh DESCRIPTION *************** *** 76,81 **** --- 76,107 ---- .Xr reboot 8 at the specified .Ar time . + .It Fl s Ar rundown-script + .Nm Shutdown + executes the specified shell script using the Bourne shell + before performing the + .Xr reboot 8 + or + .Xr halt 8 + function. If this argument is omitted, the file /etc/rc.shutdown is + executed (if it exists). If an alternate script is specified, it's full + path must be provided. In the case where a + .Xr stat 2 + of the specified script file fails, then this parameter is (silently) + ignored and no rundown script will be executed. + .It Fl t Ar timeout + .Nm Shutdown + will wait for a maximum period of the specified time, or if the option is + not specified the value of the + .Xr sysctl 8 + variable kern.shutdown_timeout (default 120 seconds) before terminating + any rundown script and proceeding. A minimum timeout value of 10 seconds + is allowed. There is no (reasonable) maximum value. The script should + wait for any applications to terminate before + exiting at which time shutdown will proceed. If the timeout period elapses, + a SIGTERM + .Xr signal 3 + is sent to the rundown process and shutdown continues. .It Ar time .Ar Time is the time at which *************** *** 134,146 **** .Bl -tag -width /etc/nologin -compact .It Pa /etc/nologin tells login not to let anyone log in .El .Sh SEE ALSO .Xr login 1 , .Xr wall 1 , .Xr nologin 5 , .Xr halt 8 , ! .Xr reboot 8 .Sh BACKWARD COMPATIBILITY The hours and minutes in the second time format may be separated by a colon (``:'') for backward compatibility. --- 160,175 ---- .Bl -tag -width /etc/nologin -compact .It Pa /etc/nologin tells login not to let anyone log in + .It Pa /etc/rc.shutdown + is the default rundown script .El .Sh SEE ALSO .Xr login 1 , .Xr wall 1 , .Xr nologin 5 , .Xr halt 8 , ! .Xr reboot 8 , ! .Xr sysctl 8 .Sh BACKWARD COMPATIBILITY The hours and minutes in the second time format may be separated by a colon (``:'') for backward compatibility. *** shutdown.c-orig Sun Feb 1 00:01:08 1998 --- shutdown.c Mon Mar 30 10:49:11 1998 *************** *** 43,48 **** --- 43,51 ---- static char sccsid[] = "@(#)shutdown.c 8.2 (Berkeley) 2/16/94"; #endif /* not lint */ + #include <sys/types.h> + #include <sys/stat.h> + #include <sys/wait.h> #include <sys/param.h> #include <sys/time.h> #include <sys/resource.h> *************** *** 58,63 **** --- 61,68 ---- #include <string.h> #include <unistd.h> #include <err.h> + #include <errno.h> + #include <stdarg.h> #include "pathnames.h" *************** *** 66,71 **** --- 71,85 ---- #define _PATH_NOLOGIN "./nologin" #endif + #ifdef LOGIN_CAP + #define RESOURCE_RC "daemon" + #endif + + #define STALL_TIMEOUT 30 /* Wait N seconds after warning */ + #define MIN_TIMEOUT 10 /* Min time to allow script to run to completion */ + #define DEATH_SCRIPT 120 /* Default of 2m for rundown script */ + #define RUNDOWN_SCRIPT ((script_name[0]==0)?_PATH_RUNDOWN:script_name) + #define H *60*60 #define M *60 #define S *1 *************** *** 85,90 **** --- 99,108 ---- static time_t offset, shuttime; static int dohalt, doreboot, killflg, mbuflen; static char *nosync, *whom, mbuf[BUFSIZ]; + volatile int clang; + pid_t pid, wpid; + char script_name[FILENAME_MAX]; + int shutdowntimeout; void badtime __P((void)); void die_you_gravy_sucking_pig_dog __P((void)); *************** *** 96,101 **** --- 114,139 ---- void timewarn __P((int)); void usage __P((void)); + void + warning(char *message, ...) + { + va_list ap; + va_start(ap, message); + + vsyslog(LOG_ALERT, message, ap); + va_end(ap); + } + + void + emergency(char *message, ...) + { + va_list ap; + va_start(ap, message); + + vsyslog(LOG_EMERG, message, ap); + va_end(ap); + } + int main(argc, argv) int argc; *************** *** 112,118 **** #endif nosync = NULL; readstdin = 0; ! while ((ch = getopt(argc, argv, "-hknr")) != -1) switch (ch) { case '-': readstdin = 1; --- 150,158 ---- #endif nosync = NULL; readstdin = 0; ! shutdowntimeout = 0; ! memset(script_name, '\0', sizeof(script_name)); ! while ((ch = getopt(argc, argv, "-hknrs:t:")) != -1) switch (ch) { case '-': readstdin = 1; *************** *** 129,134 **** --- 169,180 ---- case 'r': doreboot = 1; break; + case 's': + strncpy(script_name, optarg, sizeof(script_name)-1); + break; + case 't': + shutdowntimeout = atoi(optarg); + break; case '?': default: usage(); *************** *** 307,312 **** --- 353,359 ---- void die_you_gravy_sucking_pig_dog() { + (void)runshutdown(); /* Run the /etc/rc.shutdown script! */ syslog(LOG_NOTICE, "%s by %s: %s", doreboot ? "reboot" : dohalt ? "halt" : "shutdown", whom, mbuf); *************** *** 422,427 **** --- 469,605 ---- } } + /* + * Run the system shutdown script (/etc/rc.shutdown). + * + * Exit codes: + * -2 shutdown script terminated abnormally + * -1 fatal error - can't run script + * 0 good. + * >0 some error (exit code) + * + * Note: SIGALRM comes here. + */ + void + alrm_shutdown(int sig) + { + kill(pid, SIGTERM); + errno = ETIMEDOUT; + clang = 1; + } + + int + runshutdown() + { + int status; + size_t len; + char *argv[3]; + struct sigaction sa; + struct stat sb; + + /* + * rc.shutdown is optional, so to prevent any unnecessary + * complaints from the shell we simply don't run it if the + * file does not exist. If the stat() here fails for other + * reasons, we'll let the shell complain. + */ + if (stat(RUNDOWN_SCRIPT, &sb) == -1 && errno == ENOENT) + return 0; + + if ((pid = fork()) == 0) { + int fd; + + /* Assume that shutdown has already grab console as ctty before */ + + 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); + + if ((fd = open(_PATH_CONSOLE, O_RDWR)) == -1) + warning("shutdown: can't open %s: %m", _PATH_CONSOLE); + else { + (void) dup2(fd, STDIN_FILENO); + (void) dup2(fd, STDOUT_FILENO); + (void) dup2(fd, STDERR_FILENO); + if (fd > STDERR_FILENO) + close(fd); + } + + /* + * Run the shutdown script. + */ + argv[0] = "sh"; + argv[1] = RUNDOWN_SCRIPT; + argv[2] = 0; + + sigprocmask(SIG_SETMASK, &sa.sa_mask, (sigset_t *) 0); + + #ifdef LOGIN_CAP + setprocresources(RESOURCE_RC); + #endif + execv(_PATH_BSHELL, argv); + /* Should never get here! */ + warning("can't exec %s for %s: %m", _PATH_BSHELL, RUNDOWN_SCRIPT); + _exit(1); /* force single user mode */ + } + + if (pid == -1) { + emergency("can't fork() for %s on %s: %m", + _PATH_BSHELL, RUNDOWN_SCRIPT); + while (waitpid(-1, (int *) 0, WNOHANG) > 0) + continue; + sleep(STALL_TIMEOUT); + return -1; + } + + len = sizeof(shutdowntimeout); + if ( (shutdowntimeout < MIN_TIMEOUT) && + (sysctlbyname("kern.shutdown_timeout", + &shutdowntimeout, + &len, NULL, 0) == -1) ) + shutdowntimeout = DEATH_SCRIPT; + (void)signal(SIGALRM, alrm_shutdown); + alarm(shutdowntimeout); + clang = 0; + /* + * Copied from single_user(). This is a bit paranoid. + * Use the same ALRM handler. + */ + do { + wpid = waitpid(-1, &status, WUNTRACED); + if (clang == 1) { + /* we were waiting for the sub-shell */ + warning("timeout expired for %s on %s: %m; proceeding with shutdown", + _PATH_BSHELL, RUNDOWN_SCRIPT); + break; + } + if (wpid == -1) { + if (errno == EINTR) + continue; + warning("wait for %s on %s failed: %m; proceeding with shutdown", + _PATH_BSHELL, RUNDOWN_SCRIPT); + break; + } + if (wpid == pid && WIFSTOPPED(status)) { + warning("%s on %s stopped, restarting\n", + _PATH_BSHELL, RUNDOWN_SCRIPT); + kill(pid, SIGCONT); + wpid = -1; + } + } while (wpid != pid && !clang); + + /* Turn off the alarm */ + alarm(0); + (void)signal(SIGALRM, SIG_DFL); + + if ((status = WEXITSTATUS(status)) != 0) + warning("%s returned status %d", RUNDOWN_SCRIPT, status); + + return status; + } + #define NOMSG "\n\nNO LOGINS: System going down at " void nolog() *************** *** 462,467 **** void usage() { ! fprintf(stderr, "usage: shutdown [-hknr] shutdowntime [ message ]\n"); exit(1); } --- 640,645 ---- void usage() { ! fprintf(stderr, "usage: shutdown [-hknrs[script]t[time]] shutdowntime [ message ]\n"); exit(1); } >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199804040241.SAA08346>