Ultrix-3.1/src/cmd/oper/shutdown.c

Compare this file to the similar file:
Show the results in this format:


/**********************************************************************
 *   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);
	}
}