1: /*
   2:  * Copyright (c) 1980 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  */
   6: 
   7: #ifndef lint
   8: static char sccsid[] = "@(#)dumpoptr.c	5.1 (Berkeley) 6/5/85";
   9: #endif not lint
  10: 
  11: #include "dump.h"
  12: 
  13: /*
  14:  *	This is from /usr/include/grp.h
  15:  *	That defined struct group, which conflicts
  16:  *	with the struct group defined in param.h
  17:  */
  18: struct  Group { /* see getgrent(3) */
  19:     char    *gr_name;
  20:     char    *gr_passwd;
  21:     int gr_gid;
  22:     char    **gr_mem;
  23: };
  24: struct  Group *getgrnam();
  25: /*
  26:  *	Query the operator; This fascist piece of code requires
  27:  *	an exact response.
  28:  *	It is intended to protect dump aborting by inquisitive
  29:  *	people banging on the console terminal to see what is
  30:  *	happening which might cause dump to croak, destroying
  31:  *	a large number of hours of work.
  32:  *
  33:  *	Every 2 minutes we reprint the message, alerting others
  34:  *	that dump needs attention.
  35:  */
  36: int timeout;
  37: char    *attnmessage;       /* attemtion message */
  38: query(question)
  39:     char    *question;
  40: {
  41:     char    replybuffer[64];
  42:     int back;
  43:     FILE    *mytty;
  44: 
  45:     if ( (mytty = fopen("/dev/tty", "r")) == NULL){
  46:         msg("fopen on /dev/tty fails\n");
  47:         abort();
  48:     }
  49:     attnmessage = question;
  50:     timeout = 0;
  51:     alarmcatch();
  52:     for(;;){
  53:         if ( fgets(replybuffer, 63, mytty) == NULL){
  54:             if (ferror(mytty)){
  55:                 clearerr(mytty);
  56:                 continue;
  57:             }
  58:         } else if ( (strcmp(replybuffer, "yes\n") == 0) ||
  59:                 (strcmp(replybuffer, "Yes\n") == 0)){
  60:                 back = 1;
  61:                 goto done;
  62:         } else if ( (strcmp(replybuffer, "no\n") == 0) ||
  63:                 (strcmp(replybuffer, "No\n") == 0)){
  64:                 back = 0;
  65:                 goto done;
  66:         } else {
  67:             msg("\"Yes\" or \"No\" ONLY!\n");
  68:             alarmcatch();
  69:         }
  70:     }
  71:     done:
  72:     /*
  73: 	 *	Turn off the alarm, and reset the signal to trap out..
  74: 	 */
  75:     alarm(0);
  76:     if (signal(SIGALRM, sigalrm) == SIG_IGN)
  77:         signal(SIGALRM, SIG_IGN);
  78:     fclose(mytty);
  79:     return(back);
  80: }
  81: /*
  82:  *	Alert the console operator, and enable the alarm clock to
  83:  *	sleep for 2 minutes in case nobody comes to satisfy dump
  84:  */
  85: alarmcatch()
  86: {
  87:     if (timeout)
  88:         msgtail("\n");
  89:     msg("NEEDS ATTENTION: %s: (\"yes\" or \"no\") ",
  90:         attnmessage);
  91:     signal(SIGALRM, alarmcatch);
  92:     alarm(120);
  93:     timeout = 1;
  94: }
  95: /*
  96:  *	Here if an inquisitive operator interrupts the dump program
  97:  */
  98: interrupt()
  99: {
 100:     msg("Interrupt received. Do >>>YOU<<< know what are you doing?\n");
 101:     if (query("Do you really want to abort dump?"))
 102:         dumpabort();
 103:     signal(SIGINT, interrupt);
 104: }
 105: 
 106: /*
 107:  *	The following variables and routines manage alerting
 108:  *	operators to the status of dump.
 109:  *	This works much like wall(1) does.
 110:  */
 111: struct  Group *gp;
 112: 
 113: /*
 114:  *	Get the names from the group entry "operator" to notify.
 115:  */
 116: set_operators()
 117: {
 118:     if (!notify)        /*not going to notify*/
 119:         return;
 120:     gp = getgrnam(OPGRENT);
 121:     endgrent();
 122:     if (gp == (struct Group *)0){
 123:         msg("No entry in /etc/group for %s.\n",
 124:             OPGRENT);
 125:         notify = 0;
 126:         return;
 127:     }
 128: }
 129: 
 130: struct tm *localtime();
 131: struct tm *localclock;
 132: 
 133: /*
 134:  *	We fork a child to do the actual broadcasting, so
 135:  *	that the process control groups are not messed up
 136:  */
 137: broadcast(message)
 138:     char    *message;
 139: {
 140:     time_t      clock;
 141:     FILE    *f_utmp;
 142:     struct  utmp    utmp;
 143:     int nusers;
 144:     char    **np;
 145:     int pid, s;
 146: 
 147:     switch (pid = fork()) {
 148:     case -1:
 149:         return;
 150:     case 0:
 151:         break;
 152:     default:
 153:         while (wait(&s) != pid)
 154:             continue;
 155:         return;
 156:     }
 157: 
 158:     if (!notify || gp == 0)
 159:         exit(0);
 160:     clock = time(0);
 161:     localclock = localtime(&clock);
 162: 
 163:     if((f_utmp = fopen("/etc/utmp", "r")) == NULL) {
 164:         msg("Cannot open /etc/utmp\n");
 165:         return;
 166:     }
 167: 
 168:     nusers = 0;
 169:     while (!feof(f_utmp)){
 170:         if (fread(&utmp, sizeof (struct utmp), 1, f_utmp) != 1)
 171:             break;
 172:         if (utmp.ut_name[0] == 0)
 173:             continue;
 174:         nusers++;
 175:         for (np = gp->gr_mem; *np; np++){
 176:             if (strncmp(*np, utmp.ut_name, sizeof(utmp.ut_name)) != 0)
 177:                 continue;
 178:             /*
 179: 			 *	Do not send messages to operators on dialups
 180: 			 */
 181:             if (strncmp(utmp.ut_line, DIALUP, strlen(DIALUP)) == 0)
 182:                 continue;
 183: #ifdef DEBUG
 184:             msg("Message to %s at %s\n",
 185:                 utmp.ut_name, utmp.ut_line);
 186: #endif DEBUG
 187:             sendmes(utmp.ut_line, message);
 188:         }
 189:     }
 190:     fclose(f_utmp);
 191:     Exit(0);    /* the wait in this same routine will catch this */
 192:     /* NOTREACHED */
 193: }
 194: 
 195: sendmes(tty, message)
 196: char *tty, *message;
 197: {
 198:     char t[50], buf[BUFSIZ];
 199:     register char *cp;
 200:     register int c, ch;
 201:     int msize;
 202:     FILE *f_tty;
 203: 
 204:     msize = strlen(message);
 205:     strcpy(t, "/dev/");
 206:     strcat(t, tty);
 207: 
 208:     if((f_tty = fopen(t, "w")) != NULL) {
 209:         setbuf(f_tty, buf);
 210:         fprintf(f_tty, "\nMessage from the dump program to all operators at %d:%02d ...\r\n\n"
 211:                ,localclock->tm_hour
 212:                ,localclock->tm_min);
 213:         for (cp = message, c = msize; c-- > 0; cp++) {
 214:             ch = *cp;
 215:             if (ch == '\n')
 216:                 putc('\r', f_tty);
 217:             putc(ch, f_tty);
 218:         }
 219:         fclose(f_tty);
 220:     }
 221: }
 222: 
 223: /*
 224:  *	print out an estimate of the amount of time left to do the dump
 225:  */
 226: 
 227: time_t  tschedule = 0;
 228: 
 229: timeest()
 230: {
 231:     time_t  tnow, deltat;
 232: 
 233:     time (&tnow);
 234:     if (tnow >= tschedule){
 235:         tschedule = tnow + 300;
 236:         if (blockswritten < 500)
 237:             return;
 238:         deltat = tstart_writing - tnow +
 239:             (((1.0*(tnow - tstart_writing))/blockswritten) * esize);
 240:         msg("%3.2f%% done, finished in %d:%02d\n",
 241:             (blockswritten*100.0)/esize,
 242:             deltat/3600, (deltat%3600)/60);
 243:     }
 244: }
 245: 
 246: int blocksontape()
 247: {
 248:     /*
 249: 	 *	esize: total number of blocks estimated over all reels
 250: 	 *	blockswritten:	blocks actually written, over all reels
 251: 	 *	etapes:	estimated number of tapes to write
 252: 	 *
 253: 	 *	tsize:	blocks can write on this reel
 254: 	 *	asize:	blocks written on this reel
 255: 	 *	tapeno:	number of tapes written so far
 256: 	 */
 257:     if (tapeno == etapes)
 258:         return(esize - (etapes - 1)*tsize);
 259:     return(tsize);
 260: }
 261: 
 262:     /* VARARGS1 */
 263:     /* ARGSUSED */
 264: msg(fmt, a1, a2, a3, a4, a5)
 265:     char    *fmt;
 266: {
 267:     fprintf(stderr,"  DUMP: ");
 268: #ifdef TDEBUG
 269:     fprintf(stderr,"pid=%d ", getpid());
 270: #endif
 271:     fprintf(stderr, fmt, a1, a2, a3, a4, a5);
 272:     fflush(stdout);
 273:     fflush(stderr);
 274: }
 275: 
 276:     /* VARARGS1 */
 277:     /* ARGSUSED */
 278: msgtail(fmt, a1, a2, a3, a4, a5)
 279:     char    *fmt;
 280: {
 281:     fprintf(stderr, fmt, a1, a2, a3, a4, a5);
 282: }
 283: /*
 284:  *	Tell the operator what has to be done;
 285:  *	we don't actually do it
 286:  */
 287: 
 288: struct fstab *
 289: allocfsent(fs)
 290:     register struct fstab *fs;
 291: {
 292:     register struct fstab *new;
 293:     register char *cp;
 294:     char *malloc();
 295: 
 296:     new = (struct fstab *)malloc(sizeof (*fs));
 297:     cp = malloc(strlen(fs->fs_file) + 1);
 298:     strcpy(cp, fs->fs_file);
 299:     new->fs_file = cp;
 300:     cp = malloc(strlen(fs->fs_type) + 1);
 301:     strcpy(cp, fs->fs_type);
 302:     new->fs_type = cp;
 303:     cp = malloc(strlen(fs->fs_spec) + 1);
 304:     strcpy(cp, fs->fs_spec);
 305:     new->fs_spec = cp;
 306:     new->fs_passno = fs->fs_passno;
 307:     new->fs_freq = fs->fs_freq;
 308:     return (new);
 309: }
 310: 
 311: struct  pfstab {
 312:     struct  pfstab *pf_next;
 313:     struct  fstab *pf_fstab;
 314: };
 315: 
 316: static  struct pfstab *table = NULL;
 317: 
 318: getfstab()
 319: {
 320:     register struct fstab *fs;
 321:     register struct pfstab *pf;
 322: 
 323:     if (setfsent() == 0) {
 324:         msg("Can't open %s for dump table information.\n", FSTAB);
 325:         return;
 326:     }
 327:     while (fs = getfsent()) {
 328:         if (strcmp(fs->fs_type, FSTAB_RW) &&
 329:             strcmp(fs->fs_type, FSTAB_RO) &&
 330:             strcmp(fs->fs_type, FSTAB_RQ))
 331:             continue;
 332:         fs = allocfsent(fs);
 333:         pf = (struct pfstab *)malloc(sizeof (*pf));
 334:         pf->pf_fstab = fs;
 335:         pf->pf_next = table;
 336:         table = pf;
 337:     }
 338:     endfsent();
 339: }
 340: 
 341: /*
 342:  * Search in the fstab for a file name.
 343:  * This file name can be either the special or the path file name.
 344:  *
 345:  * The entries in the fstab are the BLOCK special names, not the
 346:  * character special names.
 347:  * The caller of fstabsearch assures that the character device
 348:  * is dumped (that is much faster)
 349:  *
 350:  * The file name can omit the leading '/'.
 351:  */
 352: struct fstab *
 353: fstabsearch(key)
 354:     char *key;
 355: {
 356:     register struct pfstab *pf;
 357:     register struct fstab *fs;
 358:     char *rawname();
 359: 
 360:     if (table == NULL)
 361:         return ((struct fstab *)0);
 362:     for (pf = table; pf; pf = pf->pf_next) {
 363:         fs = pf->pf_fstab;
 364:         if (strcmp(fs->fs_file, key) == 0)
 365:             return (fs);
 366:         if (strcmp(fs->fs_spec, key) == 0)
 367:             return (fs);
 368:         if (strcmp(rawname(fs->fs_spec), key) == 0)
 369:             return (fs);
 370:         if (key[0] != '/'){
 371:             if (*fs->fs_spec == '/' &&
 372:                 strcmp(fs->fs_spec + 1, key) == 0)
 373:                 return (fs);
 374:             if (*fs->fs_file == '/' &&
 375:                 strcmp(fs->fs_file + 1, key) == 0)
 376:                 return (fs);
 377:         }
 378:     }
 379:     return (0);
 380: }
 381: 
 382: /*
 383:  *	Tell the operator what to do
 384:  */
 385: lastdump(arg)
 386:     char    arg;        /* w ==> just what to do; W ==> most recent dumps */
 387: {
 388:             char    *lastname;
 389:             char    *date;
 390:     register    int i;
 391:             time_t  tnow;
 392:     register    struct  fstab   *dt;
 393:             int dumpme;
 394:     register    struct  idates  *itwalk;
 395: 
 396:     int idatesort();
 397: 
 398:     time(&tnow);
 399:     getfstab();     /* /etc/fstab input */
 400:     inititimes();       /* /etc/dumpdates input */
 401:     qsort(idatev, nidates, sizeof(struct idates *), idatesort);
 402: 
 403:     if (arg == 'w')
 404:         fprintf(stdout, "Dump these file systems:\n");
 405:     else
 406:         fprintf(stdout, "Last dump(s) done (Dump '>' file systems):\n");
 407:     lastname = "??";
 408:     ITITERATE(i, itwalk){
 409:         if (strncmp(lastname, itwalk->id_name, sizeof(itwalk->id_name)) == 0)
 410:             continue;
 411:         date = (char *)ctime(&itwalk->id_ddate);
 412:         date[16] = '\0';        /* blast away seconds and year */
 413:         lastname = itwalk->id_name;
 414:         dt = fstabsearch(itwalk->id_name);
 415:         dumpme = (  (dt != 0)
 416:              && (dt->fs_freq != 0)
 417:              && (itwalk->id_ddate < tnow - (dt->fs_freq*DAY)));
 418:         if ( (arg != 'w') || dumpme)
 419:           fprintf(stdout,"%c %8s\t(%6s) Last dump: Level %c, Date %s\n",
 420:             dumpme && (arg != 'w') ? '>' : ' ',
 421:             itwalk->id_name,
 422:             dt ? dt->fs_file : 0,
 423:             itwalk->id_incno,
 424:             date
 425:             );
 426:     }
 427: }
 428: 
 429: int idatesort(p1, p2)
 430:     struct  idates  **p1, **p2;
 431: {
 432:     int diff;
 433: 
 434:     diff = strncmp((*p1)->id_name, (*p2)->id_name, sizeof((*p1)->id_name));
 435:     if (diff == 0)
 436:         return ((*p2)->id_ddate - (*p1)->id_ddate);
 437:     else
 438:         return (diff);
 439: }
 440: 
 441: int max(a,b)
 442: {
 443:     return(a>b?a:b);
 444: }
 445: int min(a,b)
 446: {
 447:     return(a<b?a:b);
 448: }

Defined functions

alarmcatch defined in line 85; used 3 times
allocfsent defined in line 288; used 1 times
blocksontape defined in line 246; never used
fstabsearch defined in line 352; used 3 times
getfstab defined in line 318; used 2 times
idatesort defined in line 429; used 2 times
interrupt defined in line 98; used 4 times
lastdump defined in line 385; used 2 times
max defined in line 441; never used
min defined in line 445; never used
msg defined in line 264; used 62 times
msgtail defined in line 278; used 3 times
query defined in line 38; used 6 times
sendmes defined in line 195; used 1 times
set_operators defined in line 116; used 1 times
timeest defined in line 229; used 1 times

Defined variables

attnmessage defined in line 37; used 2 times
gp defined in line 111; used 4 times
localclock defined in line 131; used 3 times
sccsid defined in line 8; never used
table defined in line 316; used 4 times
timeout defined in line 36; used 3 times
tschedule defined in line 227; used 2 times

Defined struct's

Group defined in line 18; used 6 times
pfstab defined in line 311; used 10 times
Last modified: 1985-06-05
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2290
Valid CSS Valid XHTML 1.0 Strict