AUSAM/source/S/warn.c
/*
* ian j sep 77
* additions by K.W.T.
* /etc/warn [minutes to shutdown [minutes between warnings [message ...]]]
*
* allow super users to tell users and remind users
* of iminent shutdown of unix
*/
/*
* Modified 14-11-78 to kill getty's and signal init
* thus preventing logging in after the message is sent.
*
* Greg R and Bryan P.
*/
#include <utmp.h>
#include <stat16.h>
#include <param.h>
#include <proc.h>
#include <text.h>
#include <inode.h>
struct {char d_minor; char d_major;}; /* for major and minor device numbers */
char etcgetty[] "/etc/getty";
struct utmp buf;
struct statbuf sbuf;
struct inode ibuf;
struct text tbuf;
int kmemfd;
int mint 5; /* assume five minutes between messages */
int mtogo 20; /* assume twenty minutes to shutdown */
char term[] "/dev/tty?";
char *message "";
main(argc,argv)
int argc;
char **argv;
{
register mtty,ufd;
extern fout;
struct proc *p;
int maxprocs;
char **ap, *cp;
if( argc > 1 ) mtogo = number(argv[1]);
if( argc > 2 ) mint = number(argv[2]);
/*
* Coalesce the last arguments into one string
* by replacing the nulls with blanks.
* This is a fudge, and I'm slightly ashamed...
* So much so that I won't put my name to it.
*/
if( argc > 3 )
{
message = argv[3];
for(ap = &argv[3]; ap < &argv[argc-1]; ap++)
{
for(cp = *ap; *cp; cp++) ;
*cp = ' ';
}
}
if( mint >= mtogo )
{
printf("minutes to go(%d) <= minutes twixt(%d)\n",mtogo,mint);
exit(1);
}
printf("\n %l minutes to system shut down\n",mtogo);
printf(" %l minutes twixt user warnings\n",mint);
/*
* find all gettys, and signal them with "14"s.
* also tell init.
*
* The way to find gettys is look up its inode structure,
* then hunt through kmem for a text structure matching
* this inode number. This works only if getty is compiled
* with "-n" or "-i" to be shareable.
*/
if(kill(1, 14) == -1)
{
perror("where is init?");
exit(1);
}
/* open kmem, stat /etc/getty */
if((kmemfd = open("/dev/kmem",0)) == -1)
{
perror("kmem");
exit(1);
}
if(newstat(etcgetty, &sbuf) == -1)
{
perror(etcgetty);
exit(1);
}
/* get proc table */
if((maxprocs = gprocs(proc)) >= NPROC)
{
printf("%d procs in system - recompile warn!\n", maxprocs);
exit(1);
}
/*
* Now find the gettys and cause them to assume a state
* of nonexistence.
*/
for(p = &proc[2]; p < &proc[maxprocs]; p++) /* ignore unix and init */
{
if(p->p_stat && isgetty(p))
if(kill(p->p_pid, 14) == -1)
{
printf("%d:",p->p_pid);
perror("cannot kill");
}
}
clktim(mtogo*60 + 119);
signal(15, 0);
signal(14, 0);
signal(2, 1);
signal(3, 1);
if(mtty = fork())
{
if( mtty < 0)
{
perror();
exit(1);
}
exit(0);
}
mtty = ttyn(0); /* note my tty id */
for(;;)
{
ufd = open("/etc/utmp",0);
if(ufd < 0)
{
perror("/etc/utmp");
exit(1);
}
while( read(ufd,&buf,sizeof buf) == sizeof buf)
if(buf.u_u_name[0])
{
term[8] = buf.u_ttyid;
if( (fout = open(term,1)) > 0 )
{
printf("\007\007warning\n");
printf("\007\007warning\n");
if(mtogo > 0)
printf("Log off. System going down in %d minute%s %s\n",
mtogo, (mtogo > 1? "s": ""), message);
else
printf("LOG OFF. System going down NOW %s\n", message);
printf("\007\007warning\n");
printf("\007\007warning\n");
flush();
close(fout);
}
}
close(ufd);
sleep(mint*60);
mtogo =- mint;
}
}
number(s)
register char *s;
{
register n = 0;
while( (*s>='0')&&(*s<='9') ) n = n*10 + *s++ - '0';
return(n);
}
/*
* isgetty checks if the process pointer given it
* points to a getty.
* The algorithm used is to check the text pointer of each process
* until it finds a getty.
* kmem is read only twice for each unique text pointer until a getty
* is actually found.
*/
isgetty(p)
register struct proc *p;
{
register int **pp;
static int *gettyp, *notgp[NTEXT];
if(p->p_textp == 0)
return(0); /* not shareable -- assume not getty */
if(gettyp)
return(gettyp == p->p_textp);
for(pp = notgp; *pp; pp++)
if(p->p_textp == *pp)
return(0);
/* pp points to first unused slot in notgp table
** (note: overflow cannot happen)
** and the inode number of this text slot must be determined.
*/
if(pp >= ¬gp[NTEXT])
abort();
seek(kmemfd,p->p_textp,0);
if(read(kmemfd, &tbuf, sizeof tbuf) != sizeof tbuf)
{
perror("reading text structure");
exit(1);
}
seek(kmemfd, tbuf.x_iptr, 0);
if(read(kmemfd, &ibuf, sizeof ibuf) != sizeof ibuf)
{
perror("reading inode");
exit(1);
}
if(ibuf.i_dev.d_major == sbuf.sb_major
&& ibuf.i_dev.d_minor == sbuf.sb_minor
&& ibuf.i_number == sbuf.sb_inumber)
gettyp = p->p_textp;
else
*pp = p->p_textp;
return(isgetty(p));
}