|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T w
Length: 14374 (0x3826)
Types: TextFile
Names: »warnusers.c«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
└─⟦653021b30⟧ »EurOpenD3/utils/downtime.tar.Z«
└─⟦946c717da⟧
└─⟦this⟧ »warnusers.c«
/*
* Copyright (c) 1988 Michael A. Cooper, University of Southern California.
* This program may be used, copied, modified, and redistributed freely
* for noncommercial purposes, so long as this notice remains intact.
*/
#ifndef lint
static char *RCSid = "$Header: warnusers.c,v 4.11 88/07/05 16:00:54 mcooper Exp $";
#endif
/*
*------------------------------------------------------------------
*
* $Source: /usr/skat3/src/common/usc/etc/downtime/RCS/warnusers.c,v $
* $Revision: 4.11 $
* $Date: 88/07/05 16:00:54 $
* $State: Exp $
*
*------------------------------------------------------------------
*
* Michael A. Cooper
* Research and Development Group
* University Computing Services
* University of Southern California
* (mcooper@oberon.USC.EDU)
*
*------------------------------------------------------------------
*
* $Log: warnusers.c,v $
* Revision 4.11 88/07/05 16:00:54 mcooper
* Added copyright notice.
*
* Revision 4.10 88/07/01 16:45:01 mcooper
* Moved most RPCWALL stuff to rpc.c.
*
* Revision 4.9 88/06/10 19:43:46 mcooper
* Don't send remote msgs to the localhost.
*
* Revision 4.8 88/06/01 16:22:02 mcooper
* Cleanup getsleep().
*
* Revision 4.7 88/06/01 14:37:55 mcooper
* Only print initial \n\r\7 in
* localtell() since remote wall
* does it for us.
*
* Revision 4.6 88/05/24 13:27:29 mcooper
* Fixed bug in mkmsg() that caused the
* down for N minutes to be wrong. Should
* let getdelta() figure difference to account
* for tm_isdst.
*
* Revision 4.5 88/05/23 15:40:34 mcooper
* All tm tm_mon members are now 0-11
* instead of 1-12 for compat. with
* the normal BSD time routines.
*
* Revision 4.4 88/05/19 12:41:29 mcooper
* Removed leftover debug message.
*
* Revision 4.3 88/05/19 10:17:23 mcooper
* In localtell() we now fork to insure
* the entire downtime doesn't hang.
*
*
* Revision 4.2 88/05/18 14:34:39 mcooper
* Added checkterm() to check terminal
* to see if it's ok to write to.
*
* Revision 4.1 88/04/20 18:55:40 mcooper
* Cleaned up main loop. Added localtell()
* and remotetell().
*
* Revision 4.0 88/04/20 15:43:10 mcooper
* Version 4.
*
* Revision 3.8 88/04/20 13:36:46 mcooper
* Replace F_BROADCAST with F_MSG_REMOTE.
* Added F_MSG_LOCAL.
*
* Revision 3.7 88/04/19 18:41:50 mcooper
* Many changes too numerous to remember.
*
* Revision 3.6 88/04/11 19:45:52 mcooper
* - Added a "short" shutdown message.
* - Converted all dt_flags to bits.
*
* Revision 3.5 88/03/02 16:11:01 mcooper
* Cleanup time.
*
* Revision 3.4 88/03/01 15:47:15 mcooper
* Cleaned up header files.
*
* Revision 3.3 88/02/04 15:20:45 mcooper
* - We no longer have duplicate hosts
* in our list of hosts to broadcast to.
* - We only do a cancelmsg() if that downtime
* is locked since that means people have
* seen a broadcast message.
*
* Revision 3.2 88/02/04 12:54:25 mcooper
* - New version of gethostlist() which no
* longer uses RPC calls. Instead we read
* the host list from /etc/rmtab (ala
* rpc.mountd). This eliminates RPC timeouts
* on NFS servers with large client lists.
* - Minor cleanups.
*
* Revision 3.1 88/01/21 20:29:09 mcooper
* Port to Alliant (Concentrix 3.0).
*
* Revision 3.0 87/07/24 14:21:37 mcooper
* Version 3.
*
*------------------------------------------------------------------
*/
#define NO_CCMD /* Don't include ccmd header files */
#include <stdio.h>
#include <utmp.h>
#include <signal.h>
#include <setjmp.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include "defs.h"
#include <syslog.h>
struct msgtable {
int time; /* number of seconds */
char *msg; /* the message */
int been_used; /* has this entry been used before? */
} msgtable[] = {
8 HOURS, "8 hours", FALSE,
7 HOURS, "7 hours", FALSE,
6 HOURS, "6 hours", FALSE,
5 HOURS, "5 hours", FALSE,
4 HOURS, "4 hours", FALSE,
3 HOURS, "3 hours", FALSE,
2 HOURS, "2 hours", FALSE,
1 HOUR, "1 hour", FALSE,
30 MINUTES, "30 minutes", FALSE,
15 MINUTES, "15 minutes", FALSE,
10 MINUTES, "10 minutes", FALSE,
5 MINUTES, "5 minutes", FALSE,
2 MINUTES, "2 minutes", FALSE,
1 MINUTE, "1 minute", FALSE,
30 SECONDS, "30 seconds", FALSE,
1 SECOND, NOW, FALSE,
0, NULL, FALSE,
};
jmp_buf env;
int finish();
char *mkmsg();
/*
* warnusers - Warn users about a downtime and then bring down UNIX by
* calling bringdown().
*/
warnusers(dt, flags)
struct downtime *dt;
int flags;
{
char *when;
static int firsttime = TRUE;
int found_time = FALSE, time_remaining = -1, stime = 0;
int sigcatch();
long nw;
when = NULL;
if (dt->dt_islocked) {
return(-1);
}
if ((flags & ISNOW) == 0) {
time(&nw);
time_remaining = getdelta(localtime(&nw), dt->dt_down);
if (time_remaining > warntime) {
return(-1);
}
}
signal(SIGTERM, finish);
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal(SIGTTOU, SIG_IGN);
fflush(stdout);
if (!debug) {
int pid;
pid = fork();
if (pid) {
return(pid);
} else if (pid < 0) {
perror("fork");
return(pid);
}
fprintf(stderr, "\n%s Process spawned [%d].\n", prog, getpid());
}
if (dtlock(dt, L_LOCK) < 0) {
fprintf(stderr, "%s: warnusers: Cannot lock entry for %s.\n",
prog, mkdate(dt->dt_down, D_VERBOSE));
exit(1);
}
dtlog("WARNUSERS: Forked: Down at %s.", mkdate(dt->dt_down, D_LOGFILE));
while (((flags & ISNOW) && firsttime) || firsttime || (time_remaining > 1)) {
if (time_remaining < 6 MINUTES) {
donologin(dt);
}
if ((flags & ISNOW) == 0) {
time(&nw);
time_remaining = getdelta(localtime(&nw), dt->dt_down);
} else {
time_remaining = 1;
}
if (flags & ISNOW) {
when = NOW;
} else if (firsttime) {
firsttime = FALSE;
when = timeleft(time_remaining);
if (time_remaining > 20)
stime = 10;
} else {
register int z;
for (z = 0; msgtable[z].time > 0 && msgtable[z].msg != NULL &&
!found_time; ++z) {
if (((time_remaining >= msgtable[z].time - 2) &&
(time_remaining <= msgtable[z].time + 2)) &&
msgtable[z].been_used == FALSE) {
when = msgtable[z].msg;
msgtable[z].been_used = TRUE;
found_time = TRUE;
if (time_remaining < (2 SECONDS)) {
flags |= ISNOW;
}
}
}
if (!found_time) {
sleep(getsleep(time_remaining));
continue;
}
}
found_time = FALSE;
firsttime = FALSE;
if (dt->dt_flags & F_MSG_LOCAL) {
localtell(mkmsg(dt, flags, time_remaining, when));
}
#ifdef RPCWALL
if (dt->dt_flags & F_MSG_REMOTE) {
remotetell(mkmsg(dt, flags, time_remaining, NULL));
}
#endif RPCWALL
if (stime) {
sleep(stime);
stime = 0;
}
}
bringdown(dt);
/*NOTREACHED*/
}
char tpath[] = "/dev/";
/*
* Tell all locally logged in people about "msg".
* We fork ourself to insure that we don't hang
* the entire downtime due to one terminal.
*/
localtell(msg)
char *msg;
{
struct utmp utmp;
register int ufd;
int pid;
char term[20], *mp;
if (!msg)
return(0);
if (!debug) {
pid = fork();
if (pid < 0) {
perror("Cannot fork localtell downtime process");
return(-1);
} else if (pid > 0) {
return(0);
}
}
if ((ufd = open(UTMP, 0)) < 0) {
perror(UTMP);
return(-1);
}
mp = xmalloc(strlen(msg)+8);
strcpy(mp, "\n\r\7");
strcat(mp, msg);
lseek(ufd, 0L, 0);
while (read(ufd, &utmp, sizeof utmp) == sizeof utmp) {
if (utmp.ut_name[0]) {
strcpy(term, tpath);
strcat(term, utmp.ut_line);
tprintf(term, mp);
}
}
close(ufd);
if (!debug) {
exit(0);
} else {
return(0);
}
}
/*
* donologin - Turn off login's via NOLOGIN.
*/
donologin(dt)
struct downtime *dt;
{
FILE *f;
if (access(NOLOGIN, R_OK) == 0) {
return(-1);
}
if ((f = fopen(NOLOGIN, "w")) == NULL) {
fprintf(stderr, "%s: warnusers: ", prog);
perror(NOLOGIN);
}
fprintf(f, "\n\n\nLogins are NOT permitted at this time.\n");
fprintf(f, "The system will be going down ");
fprintf(f, "at %.2d:%.2d",
dt->dt_down->tm_hour, dt->dt_down->tm_min);
if ((strlen(dt->dt_reason) > 0) &&
(strcmp(dt->dt_reason, EMPTY) != 0)) {
fprintf(f, " for:\n\t%s\n", dt->dt_reason);
} else
fprintf(f, ".\n");
fprintf(f, "Expected up %s.\n\n\n",
mkdate(dt->dt_up, D_VERBOSE));
fclose(f);
return(0);
}
/*
* Make sure we standout on the user's terminal by using spaces.
*/
#define TAB " "
#define SPACE \
" "
#define BSIZE 200
char *
mkhdrmsg(dt, flags)
struct downtime *dt;
int flags;
{
long now;
char myhost[MAXHOSTNAMELEN];
char dobuf[BUFSIZ];
char b1[BSIZE], b2[BSIZE], b3[BSIZE], n[20];
int len;
char *p;
gethostname(myhost, sizeof(myhost));
upstr(myhost);
if (dt->dt_flags & F_SHUTMSG_ONE) {
p = index(myhost, '.');
if (p != NULL) {
*p = NULL;
}
}
time(&now);
if (dt->dt_flags & F_SHUTMSG_ONE) {
sprintf(dobuf, myhost);
} else {
strcpy(dobuf, "\n\r");
strcat(dobuf, SPACE);
strcat(dobuf, "\n\r");
sprintf(n, "%16.16s", ctime(&now));
sprintf(b1, "%sSystem Shutdown Message for %s",
(flags & ISNOW) ? "FINAL " : "", myhost);
sprintf(b2, "from %s@%s (%s)", dt->dt_shutter, dt->dt_host, n);
len = strlen(b1);
if (len < strlen(b2))
len = strlen(b2);
sprintf(b3,"*******\7 %-*s *******\n\r******* %-*s *******\n\r",
len, b1, len, b2);
strcat(dobuf, b3);
strcat(dobuf, SPACE);
strcat(dobuf, "\n\r");
}
return(newstr(dobuf));
}
/*
* mkmsg - Make a shutdown message.
*/
char *
mkmsg(dt, flags, time_remaining, when)
struct downtime *dt;
int flags;
int time_remaining;
char *when;
{
long now;
char b1[BSIZE];
char dobuf[BUFSIZ];
static char *lastwhen = NULL;
time(&now);
if (when == NULL) {
if (flags & ISNOW || time_remaining < 10)
when = NOW;
else
when = timeleft(ttol(dt->dt_down) - now);
}
if (when != NULL && strncmp(when, NOW, strlen(NOW)) == 0)
flags |= ISNOW;
if (((flags & ISNOW) == 0) && lastwhen && strcmp(lastwhen, when) == 0)
return(NULL);
strcpy(dobuf, mkhdrmsg(dt, flags));
if (flags & ISNOW || time_remaining < 5 || (strcmp(when, NOW) == 0)) {
if (dt->dt_flags & F_SHUTMSG_ONE) {
sprintf(b1, " down %s", NOW);
} else {
sprintf(b1, "%sSystem going down %s", TAB, NOW);
}
} else {
if (dt->dt_flags & F_SHUTMSG_ONE) {
sprintf(b1, " down in %s", when);
} else {
sprintf(b1, "%sSystem going down in %s (at %d:%.2d)",
TAB, when, dt->dt_down->tm_hour, dt->dt_down->tm_min);
}
}
strcat(dobuf, b1);
if (dt->dt_flags & F_SHUTMSG_ONE) {
sprintf(b1, " for %s", timeleft(getdelta(dt->dt_down, dt->dt_up)));
if (strcmp(dt->dt_reason, EMPTY) != 0) {
strcat(b1, " for ");
strcat(b1, dt->dt_reason);
}
} else {
if (strcmp(dt->dt_reason, EMPTY) != 0) {
sprintf(b1, "%s\n\r%s...for %s.%s\n\r", TAB, TAB, dt->dt_reason, TAB);
} else {
sprintf(b1, ".%s\n\r", TAB);
}
}
strcat(dobuf, b1);
if (dt->dt_flags & F_SHUTMSG_ONE) {
if (strlen(dobuf) > 81) /* 81 = 78 + "\n\r" + "." */
dobuf[81] = NULL;
sprintf(b1, ".\n\r");
} else {
sprintf(b1, "%sExpected up %s.%s\n\r%s\n\r\n\r",
TAB, mkdate(dt->dt_up, D_VERBOSE), TAB, SPACE);
}
strcat(dobuf, b1);
return(newstr(dobuf));
}
/*
* tprintf - Send "msg" to terminal "term".
*/
tprintf(term, msg)
char *term, *msg;
{
FILE *termf;
int tellcatch();
if (!msg)
return(0);
/*
* Is the terminal okay to write to?
*/
if (checkterm(term)) {
return(0);
}
if (setjmp(env)) {
return(-1);
}
signal(SIGALRM, tellcatch);
alarm(3);
#ifdef DEBUG
if ((termf = stdout) != NULL)
#else
if ((termf = fopen(term, "w")) != NULL)
#endif
{
fprintf(termf, msg);
#ifdef DEBUG
fflush(termf);
#else
fclose(termf);
#endif
}
alarm(0);
return(0);
}
tellcatch()
{
longjmp(env, 1);
}
#define MAXTRIES 3
/*
* Check a terminal to see if it is okay to write to it.
* Currently the best thing to do is just to see if there
* is output queued for the terminal.
*/
checkterm(term)
char *term;
{
int d, outn, c;
if ((d = open(term, O_RDONLY)) == 0) {
perror(term);
return(1);
}
for (c = 0; c < MAXTRIES; ++c) {
if (ioctl(d, TIOCOUTQ, &outn) != 0) {
perror(term);
return(1);
}
if (outn <= 0) {
break;
}
sleep(1);
}
close(d);
if (outn > 0) {
return(1);
} else {
return(0);
}
}
/*
* getsleep - Given the time remaining (tr) compute how long we
* should go to sleep.
*/
getsleep(tr)
int tr;
{
register int z;
int slp = 0;
for (z = 0; msgtable[z].time && msgtable[z].time > 1; ++z) {
if ((tr < (msgtable[z].time)) && (tr >= (msgtable[z+1].time + 5))) {
slp = tr - msgtable[z+1].time;
return(slp);
}
}
return(slp);
}
/*
* cancelmsg - Send cancel messages to everyone
*/
cancelmsg(dt)
struct downtime *dt;
{
char buf[BUFSIZ];
/*
* If it is not locked, no one has been notified, so we don't bother
*/
if (!dt->dt_islocked) {
return(-1);
}
if (dt->dt_flags & F_SHUTMSG_ONE) {
sprintf(buf, "%s downtime for %s is CANCELLED.\n\r",
mkhdrmsg(dt, 0), mkdate(dt->dt_down, D_VERBOSE));
} else {
sprintf(buf, "%s%sDowntime for %s is CANCELLED.\n\r%s\n\r\n\r",
mkhdrmsg(dt, 0), TAB, mkdate(dt->dt_down, D_VERBOSE), SPACE);
}
if (dt->dt_flags & F_MSG_LOCAL) {
localtell(buf);
}
#ifdef RPCWALL
if (dt->dt_flags & F_MSG_REMOTE) {
remotetell(buf);
}
#endif RPCWALL
return(0);
}