Ultrix-3.1/src/cmd/oper/shutdown.c
/**********************************************************************
* Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. *
* All Rights Reserved. *
* Reference "/usr/src/COPYRIGHT" for applicable restrictions. *
**********************************************************************/
static char Sccsid[] = "@(#)shutdown.c 3.1 8/25/87";
/*
Program to shutdown the system gracefully
July 9, 1980
This program should reside in the /opr directory
*/
#include <stdio.h>
#include <a.out.h>
#include <core.h>
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/tty.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <sys/stat.h>
#include <sys/inode.h>
#include <sys/mount.h>
#include <utmp.h>
#include <ctype.h>
#define HOURS *3600
#define MINUTES *60
#define SECONDS *1
#define NOLOGTIME 5 MINUTES /* Time to turn off logins */
#define HUPWAIT 30 SECONDS /* Time between sending HUP and KILL */
char hostname[32];
int slptime=5; /* time to sleep between HUP and KILL passes */
struct nlist nl[] = {
{ "_proc" },
{ "_swapdev" },
{ "_swplo" },
{ "_nproc" },
{ "_rootdev" },
{ "_nmount" },
{ "_sepid" },
{ "_mount" },
{ "_acctp" },
#define X_ACCTP 8
{ "" },
};
struct mount mnt;
struct mdev {
dev_t mntdev;
dev_t mnton;
char mntnam[32];
char mntonnam[32];
}mdev[20];
struct ino {
unsigned i_flag;
unsigned i_count;
dev_t i_dev;
ino_t i_number;
}ino;
#include <mtab.h>
struct mtab mtab[20];
/* m_path m_dname */
struct proc mproc;
struct utmp utmp[101];
FILE *tin;
FILE *tout;
char ttys[132]; /* originally 20, is now bigger to allow for comments in /etc/ttys */
int nproc;
long lseek();
char *strcat();
char *strcpy();
char *strcmp();
char *strncmp();
char *ttynam;
char *ttyname();
int mem;
int swmem;
int swap;
daddr_t swplo;
int rootdev, nmount, nmntdev, sepid, mf;
int fwflag=0;
int acctp;
int ndev;
struct devl {
char dname[DIRSIZ];
dev_t dev;
} devl[256];
char *coref;
int deltim;
char cnsle[] = {"/dev/console"};
char lokfil[] = {"/etc/loglock"};
char TTYS[] = "/etc/ttys";
char UTTYS[] = "/etc/uttys";
char TTTYS[] = "/etc/tttys";
FILE *df;
int nlflag = 1; /* Flag for nologins, 0 = nologins, 1 = logins */
int stogo;
int sint;
struct interval {
int stogo;
int sint;
} interval[] = {
4 HOURS, 1 HOURS,
2 HOURS, 30 MINUTES,
1 HOURS, 15 MINUTES,
30 MINUTES, 10 MINUTES,
15 MINUTES, 5 MINUTES,
9 MINUTES, 4 MINUTES,
8 MINUTES, 4 MINUTES,
7 MINUTES, 4 MINUTES,
6 MINUTES, 3 MINUTES,
5 MINUTES, 3 MINUTES,
4 MINUTES, 2 MINUTES,
3 MINUTES, 2 MINUTES,
2 MINUTES, 1 MINUTES,
1 MINUTES, 30 SECONDS,
0 SECONDS, 0 SECONDS
};
char *shutter;
main(argc, argv)
char **argv;
{
int onintr(), earlyintr();
int i;
char *ap, c;
int puid, pid, pppid, ppid;
int incnt;
char inbuf[80];
extern int deltim;
int notdone;
signal(SIGINT, earlyintr);
shutter = getlogin();
gethostname(hostname, sizeof (hostname));
printf("\nULTRIX-11 Shutdown\n");
ttynam = ttyname(0);
if (strcmp(cnsle, ttynam))
{
printf("\nShutdown should only be run from the console device\n");
printf("Do you want to run from this terminal <y or n> ? ");
gets(inbuf);
if(inbuf[0] != 'y')
exit(1);
}
printf("The following users are logged into the System\n\n");
system("who");
for(;;)
{
int bad = 0;
printf("\nHow many minutes until shutdown [1-99] ? ");
for (incnt = 0; (c = getchar()) != '\n' ; ++incnt) {
if ( isdigit(c) )
inbuf[incnt] = c;
else if (! isdigit(c) )
bad++, incnt--;
}
inbuf[incnt] = '\0';
deltim = atoi(inbuf);
if (bad)
deltim = -1;
if (incnt == 0 || deltim > 99 || deltim < 0)
{
printf("\nImproper time specified\n");
continue;
}
else
break;
}
signal(SIGINT, onintr);
pid = getpid();
if(chdir("/dev") < 0) {
fprintf(stderr, "Can't change to /dev\n");
errxit:
unlink(&lokfil);
exit(1);
}
nlist(argc>2? argv[2]:"/unix", nl);
if (nl[0].n_type==0) {
fprintf(stderr, "No namelist\n");
goto errxit;
}
coref = "/dev/mem";
if ((mem = open(coref, 0)) < 0) {
fprintf(stderr, "No mem\n");
goto errxit;
}
printf("\nWarning Phase\n\n");
stogo = deltim * 60;
for (;;)
{
deltim = stogo;
if (stogo <= NOLOGTIME && nlflag ) {
nlflag = 0;
creat(&lokfil, 0); /* Turn off Logins */
}
sndall();
/*new*/
for ( i = 0; stogo <= interval[i].stogo && interval[i].sint; i++) {
sint = interval[i].sint;
}
if (stogo <= 0) break;
if (stogo > 0 && sint > 0) sleep(sint<stogo ? sint : stogo);
stogo -= sint;
}
fwflag++;
swmem = open(coref, 0);
/*
* read mem to find swap dev.
*/
lseek(mem, (long)nl[1].n_value, 0);
read(mem, (char *)&nl[1].n_value, sizeof(nl[1].n_value));
/*
* Find base of swap
*/
lseek(mem, (long)nl[2].n_value, 0);
read(mem, (char *)&swplo, sizeof(swplo));
/*
* Locate proc table
*/
lseek(mem, (long)nl[0].n_value, 0);
getdev();
printf("\nKill Process Phase\n\n");
while(mproc.p_pid != pid) /* find this process id */
{
read(mem, (char *)&mproc, sizeof mproc);
}
ppid = mproc.p_ppid; /* get parent pid */
lseek(mem, (long)nl[0].n_value, 0);
while(mproc.p_pid != ppid) /* find this process id */
{
read(mem, (char *)&mproc, sizeof mproc);
}
pppid = mproc.p_ppid;
/* turn off all terminals and kill all user processes */
printf("\tKilling User Processes\n");
if ((tin = fopen(TTYS, "r")) == NULL) {
printf("cannot open %s for reading!\n", TTYS);
} else if ((tout = fopen(TTTYS, "w")) == NULL) {
printf("cannot open %s for writing!\n", TTTYS);
} else {
while(fscanf(tin, "%s", &ttys[0]) != EOF) {
if(strcmp(&ttys[2], cnsle+5)
&& strcmp(&ttys[2], ttynam+5))
ttys[0] = '0';
fprintf(tout, "%s\n", &ttys[0]);
}
fclose(tin);
fclose(tout);
unlink(UTTYS);
if (link(TTYS, UTTYS) == -1)
printf("Can't link %s to %s\n", TTYS, UTTYS);
else if (unlink(TTYS) == -1)
printf("Can't unlink %s\n", TTYS);
else if (link(TTTYS, TTYS) == -1) {
printf("Can't link %s to %s\n", TTTYS, TTYS);
if (link(UTTYS, TTYS) == -1)
printf("Can't link %s back to %s!\n",UTTYS, TTYS);
} else if (unlink(TTTYS) == -1)
printf("Can't unlink %s\n", TTTYS);
}
kill(1, 1); /* signal init to re-read the /etc/ttys file */
/*
* Make two passes through the table,
* send HUP first, wait 5 seconds, then send KILL.
*/
printf("\tKilling System Processes\n");
notdone = SIGHUP;
lseek(mem, (long)nl[3].n_value, 0);
read(mem, &nproc, sizeof(nproc));
while (notdone) { /* make two passes through the table */
lseek(mem, (long)nl[0].n_value, 0);
for (i=0; i<nproc; i++)
{
read(mem, (char *)&mproc, sizeof mproc);
if (mproc.p_stat==0 || mproc.p_pid <= 2)
continue;
if (mproc.p_pgrp==0 && mproc.p_uid==0 && mproc.p_ppid==0)
continue;
if(mproc.p_pid==ppid || mproc.p_pid==pid || mproc.p_pid==pppid)
continue;
puid = mproc.p_pid;
kill(puid, notdone); /* notdone = SIGHUP or SIGKILL */
}
if (notdone == SIGHUP) { /* just did HUP pass */
sleep(slptime);
notdone = SIGKILL;
}
else if (notdone == SIGKILL)/* just did last pass (SIGKILL) */
notdone = 0; /* quit */
else
notdone = SIGKILL; /* shouldn't happen */
}
printf("\tDisabling Error Logging\n");
system("/etc/eli -d");
/* Turn off accounting if it is configured and enabled. */
if (nl[X_ACCTP].n_value) {
lseek(mem, (long)nl[X_ACCTP].n_value, 0);
read(mem, &acctp, sizeof(acctp));
if (acctp) {
printf("\nTurning off System Accounting\n\n");
acct(0);
}
}
/* Dismount mounted filesystems */
printf("\nDismounting Mounted File Systems\n\n");
dodismount();
/* shut it down */
if (unlink(TTYS) == -1)
printf("Can't unlink temporary %s\n", TTYS);
else if (link(UTTYS, TTYS) == -1)
printf("Can't link %s to %s\n", UTTYS, TTYS);
else if (unlink(UTTYS) == -1)
printf("Can't unlink %s\n", UTTYS);
printf("\nSystem Time-sharing Stopped\n");
sync();
exit(0);
}
getdev()
{
struct stat sbuf;
struct direct dbuf;
if ((df = fopen("/dev", "r")) == NULL) {
fprintf(stderr, "Can't open /dev\n");
unlink(&lokfil);
exit(1);
}
ndev = 0;
while (fread((char *)&dbuf, sizeof(dbuf), 1, df) == 1) {
if(dbuf.d_ino == 0)
continue;
if(stat(dbuf.d_name, &sbuf) < 0)
continue;
if ((sbuf.st_mode&S_IFMT) != S_IFCHR)
continue;
strcpy(devl[ndev].dname, dbuf.d_name);
devl[ndev].dev = sbuf.st_rdev;
ndev++;
}
fclose(df);
if ((swap = open("/dev/swap", 0)) < 0) {
fprintf(stderr, "Can't open /dev/swap\n");
unlink(&lokfil);
exit(1);
}
}
getdevnam(dev, pnt)
dev_t dev;
int pnt;
{
struct stat sbuf;
struct direct dbuf;
char *npnt;
int cnt;
fseek(df, 0L, 0);
npnt = &mdev[pnt].mntnam;
while (fread((char *)&dbuf, sizeof(dbuf), 1, df) == 1) {
if(dbuf.d_ino == 0)
continue;
if(stat(dbuf.d_name, &sbuf) < 0)
continue;
if(sbuf.st_rdev != dev)
continue;
if((sbuf.st_mode & S_IFMT) != S_IFBLK)
continue; /* don't unmount non-block devices */
strcpy(npnt, "/dev/");
strcat(npnt, dbuf.d_name);
for(cnt = 0; cnt < 20; cnt++){
if(strcmp(dbuf.d_name, mtab[cnt].m_dname) == 0){
strcpy(mdev[pnt].mntonnam, mtab[cnt].m_path);
break;
}
}
}
}
sndall()
{
register i;
register struct utmp *p;
int hour, min;
FILE *f;
extern int deltim;
if((f = fopen(UTMP_FILE, "r")) == NULL) {
fprintf(stderr, "Cannot open %s\n",UTMP_FILE);
unlink(&lokfil);
exit(1);
}
fread((char *)utmp, sizeof(struct utmp), 101, f);
fclose(f);
for(i=0; i<101; i++) {
p = &utmp[i];
if(p->ut_name[0] == 0)
continue;
sleep(1);
if(strcmp(ttynam+5, p->ut_line))
sendmes(p->ut_line);
else if(deltim == 0)
printf("\tFINAL WARNING SENT\n");
else if (deltim >=1 HOURS )
{
hour = ((deltim +20)/60)/60;
min = (deltim / 60) - (hour * 60);
if (min > 0)
printf("\t%d hour %d minute warning sent\n",hour,min);
else
printf("\t%d hour warning sent\n",hour);
}
else if(deltim >= 1 MINUTES)
printf("\t%d minute warning sent\n", deltim/60);
else if (deltim > 0 SECONDS )
printf("\t%d second warning sent\n",deltim);
else
printf("\n\7\7\7SHUTDOWN CANCELED\n");
}
}
sendmes(tty)
char *tty;
{
register i;
char t[50], buf[BUFSIZ];
FILE *f;
char *ts;
time_t sdt;
extern int deltim;
i = fork();
if(i == -1) {
fprintf(stderr, "Try again\n");
return;
}
if(i)
return;
strcpy(t, "/dev/");
strcat(t, tty);
if((f = fopen(t, "w")) == NULL) {
fprintf(stderr,"cannot open %s\n", t);
exit(1);
}
setbuf(f, buf);
fprintf(f, "Broadcast Message ...\n\n");
fprintf(f,
"\007\007\t*** System shutdown message ");
if (shutter) /*specifies who is doing the shutdown*/
fprintf(f,"from %s@%s ***\r\n\n", shutter, hostname);
else /*regular shutdown*/
fprintf(f,"(%s) ***\r\n\n", hostname);
time(&sdt);
sdt = sdt + deltim;
ts = ctime(&sdt); /*convert time to ascii string*/
if (deltim > 10 MINUTES) /*shutdown at xx:xx*/
fprintf(f, "System going down at %5.5s\r\n", ts+11);
else if (deltim > 95 SECONDS) { /*shutdown in xx minutes*/
fprintf(f, "System going down in %d minute%s\r\n",
(deltim+30)/60, (deltim+30)/60 != 1 ? "s" : "");
}
else if (deltim > 0) { /*shutdown in xx seconds*/
fprintf(f, "System going down in %d second%s\r\n",
deltim, deltim != 1 ? "s" : "");
}
else if (deltim == 0) /*shutdown NOW*/
fprintf(f, "System going down IMMEDIATELY\r\n");
else /*shutdown Canceled*/
fprintf(f, "System Shutdown CANCELED\007\007\r\n");
fprintf(f, "\r\n");
exit(0);
}
dismount(pnt)
{
short dev, cnt;
if(mdev[pnt].mnton == -1)
return;
dev = mdev[pnt].mntdev;
for(cnt = 0; cnt < nmntdev; cnt++){
if(cnt == pnt)
continue;
if(mdev[cnt].mnton == dev)
dismount(cnt);
}
printf("Dismounting %s", mdev[pnt].mntnam);
if(mdev[pnt].mntonnam[0])
printf("\tfrom %s", mdev[pnt].mntonnam);
printf("\n");
if(umount(mdev[pnt].mntnam) != 0){
printf("\07\07Dismount failed for %s\n", mdev[pnt].mntnam);
return;
}
mdev[pnt].mnton = -1;
return;
}
dodismount()
{
int i;
if ((df = fopen("/dev", "r")) == NULL) {
fprintf(stderr, "Can't open /dev\n");
exit(1);
}
lseek(mem, (long)nl[4].n_value, 0);
read(mem, &rootdev, sizeof(rootdev));
lseek(mem, (long)nl[5].n_value, 0);
read(mem, &nmount, sizeof(nmount));
lseek(mem, (long)nl[6].n_value, 0);
read(mem, &sepid, sizeof(sepid));
if((mf = open("/etc/mtab", 0)) > 0){
read(mf, &mtab, sizeof mtab);
close(mf);
}
else
mf = 0;
for(nmntdev = i = 0; i < nmount; i++){
lseek(mem,(long)nl[7].n_value+(i*sizeof(struct mount)),0);
read(mem, &mnt, sizeof(struct mount));
if(mnt.m_bufp == 0 || mnt.m_dev == rootdev)
continue;
lseek(mem, (long)mnt.m_inodp, 0);
read(mem, &ino, sizeof(struct ino));
mdev[nmntdev].mntdev = mnt.m_dev;
mdev[nmntdev].mnton = ino.i_dev;
getdevnam(mnt.m_dev, nmntdev);
nmntdev++;
}
fclose(df);
sync();
for(i = 0; i < nmntdev; i++)
dismount(i);
close(creat("/etc/mtab", 644));
sync();
}
earlyintr()
{
printf("\n\nSHUTDOWN CANCELED\n");
exit(1);
}
onintr()
{
if(fwflag) {
signal(SIGINT, onintr);
return;
} else {
signal(SIGINT, SIG_IGN); /* ignore any subsequent ^C's */
unlink(&lokfil);
deltim = -100;
sndall();
exit(0);
}
}