summaryrefslogtreecommitdiffstats
path: root/login-utils/shutdown.c
diff options
context:
space:
mode:
Diffstat (limited to 'login-utils/shutdown.c')
-rw-r--r--login-utils/shutdown.c239
1 files changed, 160 insertions, 79 deletions
diff --git a/login-utils/shutdown.c b/login-utils/shutdown.c
index a63cbd6e9..8ba13b647 100644
--- a/login-utils/shutdown.c
+++ b/login-utils/shutdown.c
@@ -1,6 +1,6 @@
/* shutdown.c - shutdown a Linux system
* Initially written by poe@daimi.aau.dk
- * Currently maintained at ftp://ftp.daimi.aau.dk/pub/linux/poe/
+ * Currently maintained at ftp://ftp.daimi.aau.dk/pub/Software/Linux/
*/
/*
@@ -24,6 +24,9 @@
* Various changes and additions to resemble SunOS 4 shutdown/reboot/halt(8)
* more closely by Scott Telford (s.telford@ed.ac.uk) 93/05/18.
* (I butchered Scotts patches somewhat. - poe)
+ *
+ * Changes by Richard Gooch <rgooch@atnf.csiro.au> (butchered by aeb)
+ * introducing shutdown.conf.
*/
#include <stdio.h>
@@ -35,6 +38,7 @@
#include <string.h>
#include <ctype.h>
#include <signal.h>
+#include <errno.h>
#include <sys/param.h>
#include <termios.h>
#include <mntent.h>
@@ -42,11 +46,12 @@
#include <sys/wait.h>
#include <syslog.h>
#include <sys/resource.h>
+#include "linux_reboot.h"
#include "pathnames.h"
-void usage(), int_handler(), write_user(struct utmp *);
-void wall(), write_wtmp(), unmount_disks(), unmount_disks_ourselves();
-void swap_off();
+static void usage(), int_handler(), write_user(struct utmp *);
+static void wall(), write_wtmp(), unmount_disks(), unmount_disks_ourselves();
+static void swap_off(), do_halt(char *);
char *prog; /* name of the program */
int opt_reboot; /* true if -r option or reboot command */
@@ -57,10 +62,15 @@ char message[90]; /* reason for shutdown if any... */
int opt_single = 0; /* true is we want to boot singleuser */
char *whom; /* who is shutting the system down */
int opt_msgset = 0; /* message set on command line */
+ /* change 1 to 0 if no file is to be used by default */
+int opt_use_config_file = 1; /* read _PATH_SHUTDOWN_CONF */
+char halt_action[256]; /* to find out what to do upon halt */
/* #define DEBUGGING */
#define WR(s) write(fd, s, strlen(s))
+#define ERRSTRING sys_errlist[errno]
+
void
usage()
@@ -70,19 +80,31 @@ usage()
exit(1);
}
+void
+my_puts(char *s)
+{
+ /* Use a fresh stdout after forking */
+ freopen(_PATH_CONSOLE, "w", stdout);
+ puts(s);
+ fflush(stdout);
+}
+
void
int_handler()
{
unlink(_PATH_NOLOGIN);
signal(SIGINT, SIG_DFL);
- puts("Shutdown process aborted\n");
+ my_puts("Shutdown process aborted");
exit(1);
}
int
-main(argc, argv)
- int argc;
- char *argv[];
+iswhitespace(int a) {
+ return (a == ' ' || a == '\t');
+}
+
+int
+main(int argc, char *argv[])
{
int c,i;
int fd;
@@ -90,7 +112,8 @@ main(argc, argv)
#ifndef DEBUGGING
if(geteuid()) {
- fprintf(stderr, "%s: Only root can shut a system down.\n", argv[0]);
+ fprintf(stderr, "%s: Only root can shut a system down.\n",
+ argv[0]);
exit(1);
}
#endif
@@ -98,7 +121,10 @@ main(argc, argv)
if(*argv[0] == '-') argv[0]++; /* allow shutdown as login shell */
prog = argv[0];
if((ptr = strrchr(argv[0], '/'))) prog = ++ptr;
-
+
+ /* All names (halt, reboot, fasthalt, fastboot, shutdown)
+ refer to the same program with the same options,
+ only the defaults differ. */
if(!strcmp("halt", prog)) {
opt_reboot = 0;
opt_quiet = 1;
@@ -114,78 +140,105 @@ main(argc, argv)
opt_quiet = 1;
opt_fast = 0;
timeout = 0;
- if(argc > 1 && !strcmp(argv[1], "-s")) opt_single = 1;
} else if(!strcmp("fastboot", prog)) {
opt_reboot = 1;
opt_quiet = 1;
opt_fast = 1;
timeout = 0;
- if(argc > 1 && !strcmp(argv[1], "-s")) opt_single = 1;
} else {
/* defaults */
opt_reboot = 0;
opt_quiet = 0;
opt_fast = 0;
timeout = 2*60;
+ }
- c = 0;
- while(++c < argc) {
- if(argv[c][0] == '-') {
- for(i = 1; argv[c][i]; i++) {
+ c = 0;
+ while(++c < argc) {
+ if(argv[c][0] == '-') {
+ for(i = 1; argv[c][i]; i++) {
switch(argv[c][i]) {
- case 'h':
- opt_reboot = 0;
- break;
- case 'r':
- opt_reboot = 1;
- break;
- case 'f':
- opt_fast = 1;
- break;
- case 'q':
- opt_quiet = 1;
- break;
- case 's':
- opt_single = 1;
- break;
+ case 'C':
+ opt_use_config_file = 1;
+ break;
+ case 'h':
+ opt_reboot = 0;
+ break;
+ case 'r':
+ opt_reboot = 1;
+ break;
+ case 'f':
+ opt_fast = 1;
+ break;
+ case 'q':
+ opt_quiet = 1;
+ break;
+ case 's':
+ opt_single = 1;
+ break;
- default:
- usage();
+ default:
+ usage();
}
- }
- } else if(!strcmp("now", argv[c])) {
- timeout = 0;
- } else if(argv[c][0] == '+') {
- timeout = 60 * atoi(&argv[c][1]);
- } else if (isdigit(argv[c][0])) {
- char *colon;
- int hour = 0;
- int minute = 0;
- time_t tics;
- struct tm *tt;
- int now, then;
+ }
+ } else if(!strcmp("now", argv[c])) {
+ timeout = 0;
+ } else if(argv[c][0] == '+') {
+ timeout = 60 * atoi(&argv[c][1]);
+ } else if (isdigit(argv[c][0])) {
+ char *colon;
+ int hour = 0;
+ int minute = 0;
+ time_t tics;
+ struct tm *tt;
+ int now, then;
- if((colon = strchr(argv[c], ':'))) {
- *colon = '\0';
- hour = atoi(argv[c]);
- minute = atoi(++colon);
- } else usage();
+ if((colon = strchr(argv[c], ':'))) {
+ *colon = '\0';
+ hour = atoi(argv[c]);
+ minute = atoi(++colon);
+ } else usage();
- (void) time(&tics);
- tt = localtime(&tics);
+ (void) time(&tics);
+ tt = localtime(&tics);
- now = 3600 * tt->tm_hour + 60 * tt->tm_min;
- then = 3600 * hour + 60 * minute;
- timeout = then - now;
- if(timeout < 0) {
- fprintf(stderr, "That must be tomorrow, can't you wait till then?\n");
- exit(1);
- }
- } else {
- strncpy(message, argv[c], sizeof(message));
- message[sizeof(message)-1] = '\0';
- opt_msgset = 1;
+ now = 3600 * tt->tm_hour + 60 * tt->tm_min;
+ then = 3600 * hour + 60 * minute;
+ timeout = then - now;
+ if(timeout < 0) {
+ fprintf(stderr, "That must be tomorrow, "
+ "can't you wait till then?\n");
+ exit(1);
+ }
+ } else {
+ strncpy(message, argv[c], sizeof(message));
+ message[sizeof(message)-1] = '\0';
+ opt_msgset = 1;
+ }
+ }
+
+ halt_action[0] = 0;
+
+ /* No doubt we shall want to extend this some day
+ and register a series of commands to be executed
+ at various points during the shutdown sequence,
+ and to define the number of milliseconds to sleep, etc. */
+ if (opt_use_config_file) {
+ char line[256], *p;
+ FILE *fp;
+
+ /* Read and parse the config file */
+ halt_action[0] = '\0';
+ if ((fp = fopen (_PATH_SHUTDOWN_CONF, "r")) != NULL) {
+ if (fgets (line, sizeof(line), fp) != NULL &&
+ strncasecmp (line, "HALT_ACTION", 11) == 0 &&
+ iswhitespace(line[11])) {
+ p = line+11;
+ while(iswhitespace(*p))
+ p++;
+ strcpy(halt_action, p);
}
+ fclose (fp);
}
}
@@ -212,6 +265,7 @@ main(argc, argv)
/* so much for option-processing, now begin termination... */
if(!(whom = getlogin())) whom = "ghost";
+ if(strlen(whom) > 40) whom[40] = 0; /* see write_user() */
setpriority(PRIO_PROCESS, 0, PRIO_MIN);
signal(SIGINT, int_handler);
@@ -261,7 +315,8 @@ main(argc, argv)
kill(1, SIGTSTP); /* tell init not to spawn more getty's */
write_wtmp();
if(opt_single)
- close(open(_PATH_SINGLE, O_CREAT|O_WRONLY, 0644));
+ if((fd = open(_PATH_SINGLE, O_CREAT|O_WRONLY, 0644)) >= 0)
+ close(fd);
sync();
@@ -272,7 +327,7 @@ main(argc, argv)
#ifndef DEBUGGING
/* a gentle kill of all other processes except init */
kill(-1, SIGTERM);
- sleep(2);
+ sleep(2); /* default 2, some people need 5 */
/* now use brute force... */
kill(-1, SIGKILL);
@@ -292,14 +347,14 @@ main(argc, argv)
sleep(1);
if(opt_reboot) {
- reboot(0xfee1dead, 672274793, 0x1234567);
+ my_reboot(LINUX_REBOOT_CMD_RESTART); /* RB_AUTOBOOT */
+ my_puts("\nWhy am I still alive after reboot?");
} else {
- freopen(_PATH_CONSOLE, "w", stdout);
- printf("\nNow you can turn off the power...\n");
- fflush(stdout);
+ my_puts("\nNow you can turn off the power...");
+
/* allow C-A-D now, faith@cs.unc.edu, re-fixed 8-Jul-96 */
- reboot(0xfee1dead, 672274793, 0x89abcdef);
- reboot(0xfee1dead, 672274793, 0xcdef0123);
+ my_reboot(LINUX_REBOOT_CMD_CAD_ON); /* RB_ENABLE_CAD */
+ do_halt(halt_action);
}
/* NOTREACHED */
exit(0); /* to quiet gcc */
@@ -308,6 +363,31 @@ main(argc, argv)
/*** end of main() ***/
void
+do_halt(char *action) {
+ if (strcasecmp (action, "power_off") == 0) {
+ printf("Calling kernel power-off facility...\n");
+ fflush(stdout);
+ my_reboot(LINUX_REBOOT_CMD_POWER_OFF);
+ printf("Error powering off\t%s\n", ERRSTRING);
+ fflush(stdout);
+ sleep (2);
+ } else
+
+ /* This should be improved; e.g. Mike Jagdis wants "/sbin/mdstop -a" */
+ /* Maybe we should also fork and wait */
+ if (action[0] == '/') {
+ printf("Executing the program \"%s\" ...\n", action);
+ fflush(stdout);
+ execl(action, action, NULL);
+ printf("Error executing\t%s\n", ERRSTRING);
+ fflush(stdout);
+ sleep (2);
+ }
+
+ my_reboot(LINUX_REBOOT_CMD_HALT); /* RB_HALT_SYSTEM */
+}
+
+void
write_user(struct utmp *ut)
{
int fd;
@@ -319,7 +399,7 @@ write_user(struct utmp *ut)
(void) strncat(term, ut->ut_line, sizeof(ut->ut_line));
/* try not to get stuck on a mangled ut_line entry... */
- if((fd = open(term, O_RDWR|O_NONBLOCK)) < 0)
+ if((fd = open(term, O_WRONLY|O_NONBLOCK)) < 0)
return;
sprintf(msg, "\007\r\nURGENT: broadcast message from %s:\r\n", whom);
@@ -393,7 +473,7 @@ swap_off()
sync();
if ((pid = fork()) < 0) {
- printf("Cannot fork for swapoff. Shrug!\n");
+ my_puts("Cannot fork for swapoff. Shrug!");
return;
}
if (!pid) {
@@ -401,7 +481,8 @@ swap_off()
execl("/etc/swapoff", SWAPOFF_ARGS, NULL);
execl("/bin/swapoff", SWAPOFF_ARGS, NULL);
execlp("swapoff", SWAPOFF_ARGS, NULL);
- puts("Cannot exec swapoff, hoping umount will do the trick.");
+ my_puts("Cannot exec swapoff, "
+ "hoping umount will do the trick.");
exit(0);
}
while ((result = wait(&status)) != -1 && result != pid)
@@ -419,20 +500,20 @@ unmount_disks()
sync();
if ((pid = fork()) < 0) {
- printf("Cannot fork for umount, trying manually.\n");
+ my_puts("Cannot fork for umount, trying manually.");
unmount_disks_ourselves();
return;
}
if (!pid) {
execl(_PATH_UMOUNT, UMOUNT_ARGS, NULL);
- printf("Cannot exec %s, trying umount.\n", _PATH_UMOUNT);
+ my_puts("Cannot exec " _PATH_UMOUNT ", trying umount.");
execlp("umount", UMOUNT_ARGS, NULL);
- puts("Cannot exec umount, giving up on umount.");
+ my_puts("Cannot exec umount, giving up on umount.");
exit(0);
}
while ((result = wait(&status)) != -1 && result != pid)
;
- puts("Unmounting any remaining filesystems...");
+ my_puts("Unmounting any remaining filesystems...");
unmount_disks_ourselves();
}
@@ -450,7 +531,7 @@ unmount_disks_ourselves()
sync();
if (!(mtab = setmntent(_PATH_MTAB, "r"))) {
- printf("shutdown: Cannot open %s.\n", _PATH_MTAB);
+ my_puts("shutdown: Cannot open " _PATH_MTAB ".");
return;
}
n = 0;