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; /* attention 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\"?\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.\n"); 101: if (query("Do you 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: int a1, a2, a3, a4, a5; 267: { 268: fprintf(stderr," DUMP: "); 269: #ifdef TDEBUG 270: fprintf(stderr,"pid=%d ", getpid()); 271: #endif 272: fprintf(stderr, fmt, a1, a2, a3, a4, a5); 273: fflush(stdout); 274: fflush(stderr); 275: } 276: 277: /* VARARGS1 */ 278: /* ARGSUSED */ 279: msgtail(fmt, a1, a2, a3, a4, a5) 280: char *fmt; 281: int a1, a2, a3, a4, a5; 282: { 283: fprintf(stderr, fmt, a1, a2, a3, a4, a5); 284: } 285: /* 286: * Tell the operator what has to be done; 287: * we don't actually do it 288: */ 289: 290: struct fstab * 291: allocfsent(fs) 292: register struct fstab *fs; 293: { 294: register struct fstab *new; 295: register char *cp; 296: char *malloc(); 297: 298: new = (struct fstab *)malloc(sizeof (*fs)); 299: cp = malloc(strlen(fs->fs_file) + 1); 300: strcpy(cp, fs->fs_file); 301: new->fs_file = cp; 302: cp = malloc(strlen(fs->fs_type) + 1); 303: strcpy(cp, fs->fs_type); 304: new->fs_type = cp; 305: cp = malloc(strlen(fs->fs_spec) + 1); 306: strcpy(cp, fs->fs_spec); 307: new->fs_spec = cp; 308: new->fs_passno = fs->fs_passno; 309: new->fs_freq = fs->fs_freq; 310: return (new); 311: } 312: 313: struct pfstab { 314: struct pfstab *pf_next; 315: struct fstab *pf_fstab; 316: }; 317: 318: static struct pfstab *table = NULL; 319: 320: getfstab() 321: { 322: register struct fstab *fs; 323: register struct pfstab *pf; 324: 325: if (setfsent() == 0) { 326: msg("Can't open %s for dump table information.\n", FSTAB); 327: return; 328: } 329: while (fs = getfsent()) { 330: if (strcmp(fs->fs_type, FSTAB_RW) && 331: strcmp(fs->fs_type, FSTAB_RO) && 332: strcmp(fs->fs_type, FSTAB_RQ)) 333: continue; 334: fs = allocfsent(fs); 335: pf = (struct pfstab *)malloc(sizeof (*pf)); 336: pf->pf_fstab = fs; 337: pf->pf_next = table; 338: table = pf; 339: } 340: endfsent(); 341: } 342: 343: /* 344: * Search in the fstab for a file name. 345: * This file name can be either the special or the path file name. 346: * 347: * The entries in the fstab are the BLOCK special names, not the 348: * character special names. 349: * The caller of fstabsearch assures that the character device 350: * is dumped (that is much faster) 351: * 352: * The file name can omit the leading '/'. 353: */ 354: struct fstab * 355: fstabsearch(key) 356: char *key; 357: { 358: register struct pfstab *pf; 359: register struct fstab *fs; 360: char *rawname(); 361: 362: if (table == NULL) 363: return ((struct fstab *)0); 364: for (pf = table; pf; pf = pf->pf_next) { 365: fs = pf->pf_fstab; 366: if (strcmp(fs->fs_file, key) == 0) 367: return (fs); 368: if (strcmp(fs->fs_spec, key) == 0) 369: return (fs); 370: if (strcmp(rawname(fs->fs_spec), key) == 0) 371: return (fs); 372: if (key[0] != '/'){ 373: if (*fs->fs_spec == '/' && 374: strcmp(fs->fs_spec + 1, key) == 0) 375: return (fs); 376: if (*fs->fs_file == '/' && 377: strcmp(fs->fs_file + 1, key) == 0) 378: return (fs); 379: } 380: } 381: return (0); 382: } 383: 384: /* 385: * Tell the operator what to do 386: */ 387: lastdump(arg) 388: char arg; /* w ==> just what to do; W ==> most recent dumps */ 389: { 390: char *lastname; 391: char *date; 392: register int i; 393: time_t tnow; 394: register struct fstab *dt; 395: int dumpme; 396: register struct idates *itwalk; 397: 398: int idatesort(); 399: 400: time(&tnow); 401: getfstab(); /* /etc/fstab input */ 402: inititimes(); /* /etc/dumpdates input */ 403: qsort(idatev, nidates, sizeof(struct idates *), idatesort); 404: 405: if (arg == 'w') 406: fprintf(stdout, "Dump these file systems:\n"); 407: else 408: fprintf(stdout, "Last dump(s) done (Dump '>' file systems):\n"); 409: lastname = "??"; 410: ITITERATE(i, itwalk){ 411: if (strncmp(lastname, itwalk->id_name, sizeof(itwalk->id_name)) == 0) 412: continue; 413: date = (char *)ctime(&itwalk->id_ddate); 414: date[16] = '\0'; /* blast away seconds and year */ 415: lastname = itwalk->id_name; 416: dt = fstabsearch(itwalk->id_name); 417: dumpme = ( (dt != 0) 418: && (dt->fs_freq != 0) 419: && (itwalk->id_ddate < tnow - (dt->fs_freq*DAY))); 420: if ( (arg != 'w') || dumpme) 421: fprintf(stdout,"%c %8s\t(%6s) Last dump: Level %c, Date %s\n", 422: dumpme && (arg != 'w') ? '>' : ' ', 423: itwalk->id_name, 424: dt ? dt->fs_file : "", 425: itwalk->id_incno, 426: date 427: ); 428: } 429: } 430: 431: int idatesort(p1, p2) 432: struct idates **p1, **p2; 433: { 434: int diff; 435: 436: diff = strncmp((*p1)->id_name, (*p2)->id_name, sizeof((*p1)->id_name)); 437: if (diff == 0) 438: return ((*p2)->id_ddate - (*p1)->id_ddate); 439: else 440: return (diff); 441: } 442: 443: int max(a,b) 444: int a, b; 445: { 446: return(a>b?a:b); 447: } 448: int min(a,b) 449: int a, b; 450: { 451: return(a<b?a:b); 452: }