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