DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T w

⟦44c06f876⟧ TextFile

    Length: 14374 (0x3826)
    Types: TextFile
    Names: »warnusers.c«

Derivation

└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
    └─⟦653021b30⟧ »EurOpenD3/utils/downtime.tar.Z« 
        └─⟦946c717da⟧ 
            └─⟦this⟧ »warnusers.c« 

TextFile

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