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: }