1: static char *sccsid = "@(#)dumpoptr.c 1.4.1 (2.11BSD) 1996/11/17"; 2: #include "dump.h" 3: 4: struct group *getgrnam(); 5: /* 6: * Query the operator; This fascist piece of code requires 7: * an exact response. 8: * It is intended to protect dump aborting by inquisitive 9: * people banging on the console terminal to see what is 10: * happening which might cause dump to croak, destroying 11: * a large number of hours of work. 12: * 13: * Every 2 minutes we reprint the message, alerting others 14: * that dump needs attention. 15: */ 16: int timeout; 17: char *attnmessage; /* attemtion message */ 18: query(question) 19: char *question; 20: { 21: char replybuffer[64]; 22: int back; 23: FILE *mytty; 24: 25: if ( (mytty = fopen("/dev/tty", "r")) == NULL){ 26: msg("fopen on /dev/tty fails\n"); 27: abort(); 28: } 29: attnmessage = question; 30: timeout = 0; 31: alarmcatch(); 32: for(;;){ 33: if ( fgets(replybuffer, 63, mytty) == NULL){ 34: if (ferror(mytty)){ 35: clearerr(mytty); 36: continue; 37: } 38: } else if ( (strcmp(replybuffer, "yes\n") == 0) || 39: (strcmp(replybuffer, "Yes\n") == 0)){ 40: back = 1; 41: goto done; 42: } else if ( (strcmp(replybuffer, "no\n") == 0) || 43: (strcmp(replybuffer, "No\n") == 0)){ 44: back = 0; 45: goto done; 46: } else { 47: msg("\"Yes\" or \"No\"?\n"); 48: alarmcatch(); 49: } 50: } 51: done: 52: /* 53: * Turn off the alarm, and reset the signal to trap out.. 54: */ 55: alarm(0); 56: if (signal(SIGALRM, sigalrm) == SIG_IGN) 57: signal(SIGALRM, SIG_IGN); 58: fclose(mytty); 59: return(back); 60: } 61: /* 62: * Alert the console operator, and enable the alarm clock to 63: * sleep for 2 minutes in case nobody comes to satisfy dump 64: */ 65: alarmcatch() 66: { 67: if (timeout) 68: msgtail("\n"); 69: msg("NEEDS ATTENTION: %s: (\"yes\" or \"no\") ", 70: attnmessage); 71: signal(SIGALRM, alarmcatch); 72: alarm(120); 73: timeout = 1; 74: } 75: /* 76: * Here if an inquisitive operator interrupts the dump program 77: */ 78: interrupt() 79: { 80: msg("Interrupt received.\n"); 81: if (query("Do you want to abort dump?")) 82: dumpabort(); 83: signal(SIGINT, interrupt); 84: } 85: 86: /* 87: * The following variables and routines manage alerting 88: * operators to the status of dump. 89: * This works much like wall(1) does. 90: */ 91: struct group *gp; 92: 93: /* 94: * Get the names from the group entry "operator" to notify. 95: */ 96: set_operators() 97: { 98: if (!notify) /*not going to notify*/ 99: return; 100: gp = getgrnam(OPGRENT); 101: endgrent(); 102: if (gp == (struct group *)0){ 103: msg("No entry in /etc/group for %s.\n", 104: OPGRENT); 105: notify = 0; 106: return; 107: } 108: } 109: 110: struct tm *localtime(); 111: struct tm *localclock; 112: 113: /* 114: * We fork a child to do the actual broadcasting, so 115: * that the process control groups are not messed up 116: */ 117: broadcast(message) 118: char *message; 119: { 120: time_t clock; 121: FILE *f_utmp; 122: struct utmp utmp; 123: char **np; 124: int pid, s; 125: 126: switch (pid = fork()) { 127: case -1: 128: return; 129: case 0: 130: break; 131: default: 132: while (wait(&s) != pid) 133: continue; 134: return; 135: } 136: 137: if (!notify || gp == 0) 138: exit(0); 139: clock = time((time_t *)0); 140: localclock = localtime(&clock); 141: 142: if((f_utmp = fopen(_PATH_UTMP, "r")) == NULL) { 143: msg("Cannot open 'utmp'\n"); 144: return; 145: } 146: 147: while (!feof(f_utmp)){ 148: if (fread((char *)&utmp, sizeof (struct utmp), 1, f_utmp) != 1) 149: break; 150: if (utmp.ut_name[0] == 0) 151: continue; 152: for (np = gp->gr_mem; *np; np++){ 153: if (strncmp(*np, utmp.ut_name, sizeof(utmp.ut_name)) != 0) 154: continue; 155: /* 156: * Do not send messages to operators on dialups 157: */ 158: if (strncmp(utmp.ut_line, DIALUP, strlen(DIALUP)) == 0) 159: continue; 160: #ifdef DEBUG 161: msg("Message to %s at %s\n", 162: utmp.ut_name, utmp.ut_line); 163: #endif DEBUG 164: sendmes(utmp.ut_line, message); 165: } 166: } 167: fclose(f_utmp); 168: Exit(0); /* the wait in this same routine will catch this */ 169: /* NOTREACHED */ 170: } 171: 172: sendmes(tty, message) 173: char *tty, *message; 174: { 175: char t[50], buf[BUFSIZ]; 176: register char *cp; 177: register int c, ch; 178: int msize; 179: FILE *f_tty; 180: 181: msize = strlen(message); 182: strcpy(t, "/dev/"); 183: strcat(t, tty); 184: 185: if((f_tty = fopen(t, "w")) != NULL) { 186: setbuf(f_tty, buf); 187: fprintf(f_tty, "\n\007\007\007Message from the dump program to all operators at %d:%02d ...\r\n\n" 188: ,localclock->tm_hour 189: ,localclock->tm_min); 190: for (cp = message, c = msize; c-- > 0; cp++) { 191: ch = *cp; 192: if (ch == '\n') 193: putc('\r', f_tty); 194: putc(ch, f_tty); 195: } 196: fclose(f_tty); 197: } 198: } 199: 200: /* 201: * print out an estimate of the amount of time left to do the dump 202: */ 203: 204: time_t tschedule = 0; 205: 206: timeest() 207: { 208: time_t tnow, deltat; 209: long pleft; 210: char buf[BUFSIZ]; 211: 212: time (&tnow); 213: if (tnow >= tschedule){ 214: tschedule = tnow + 300; 215: if (blockswritten < 500L) 216: return; 217: /* 218: / \ 219: |/ estimated blocks \ | 220: delta time = ||---------------- | X time so far | - time so far 221: |\ blocks thus far / | 222: \ / 223: */ 224: pleft = ((100 * esize)/blockswritten) - 100; 225: deltat = (time_t) (tnow - tstart_writing) * pleft; 226: deltat = deltat/100; /* scale back down */ 227: sprintf(buf,"%3.2f%%%% done, finished in %d:%02d\n", 228: (float) (blockswritten*100.0)/esize, 229: (int)(deltat/3600L), (int)((deltat%3600L)/60L)); 230: msg(buf); 231: } 232: } 233: 234: int blocksontape() 235: { 236: /* 237: * esize: total number of blocks estimated over all reels 238: * blockswritten: blocks actually written, over all reels 239: * etapes: estimated number of tapes to write 240: * 241: * tsize: blocks can write on this reel 242: * asize: blocks written on this reel 243: * tapeno: number of tapes written so far 244: */ 245: if (tapeno == etapes) 246: return(esize - (etapes - 1)*tsize); 247: return(tsize); 248: } 249: 250: /* VARARGS1 */ 251: /* ARGSUSED */ 252: msg(fmt, a1, a2, a3, a4, a5) 253: char *fmt; 254: { 255: fprintf(stderr," DUMP: "); 256: #ifdef TDEBUG 257: fprintf(stderr,"pid=%d ", getpid()); 258: #endif 259: fprintf(stderr, fmt, a1, a2, a3, a4, a5); 260: fflush(stdout); 261: fflush(stderr); 262: } 263: 264: /* VARARGS1 */ 265: /* ARGSUSED */ 266: msgtail(fmt, a1, a2, a3, a4, a5) 267: char *fmt; 268: { 269: fprintf(stderr, fmt, a1, a2, a3, a4, a5); 270: } 271: 272: /* 273: * Tell the operator what has to be done. 274: */ 275: lastdump(arg) 276: char arg; /* w ==> just what to do; W ==> most recent dumps */ 277: { 278: char *lastname; 279: char *date; 280: register int i; 281: time_t tnow; 282: register struct fstab *dt; 283: int dumpme; 284: register struct idates *itwalk; 285: 286: int idatesort(); 287: 288: time(&tnow); 289: inititimes(); /* /etc/dumpdates input */ 290: qsort(idatev, nidates, sizeof(struct idates *), idatesort); 291: 292: if (arg == 'w') 293: fprintf(stdout, "Dump these file systems:\n"); 294: else 295: fprintf(stdout, "Last dump(s) done (Dump '>' file systems):\n"); 296: lastname = "??"; 297: ITITERATE(i, itwalk){ 298: if (strncmp(lastname, itwalk->id_name, sizeof(itwalk->id_name)) == 0) 299: continue; 300: date = (char *)ctime(&itwalk->id_ddate); 301: date[16] = '\0'; /* blast away seconds and year */ 302: lastname = itwalk->id_name; 303: dt = getfsspec(deraw(itwalk->id_name)); 304: dumpme = ( (dt != 0) 305: && (dt->fs_freq != 0) 306: && (itwalk->id_ddate < tnow - (dt->fs_freq*DAY))); 307: if ( (arg != 'w') || dumpme) 308: fprintf(stdout,"%c %8s\t(%6s) Last dump: Level %c, Date %s\n", 309: dumpme && (arg != 'w') ? '>' : ' ', 310: itwalk->id_name, 311: dt ? dt->fs_file : 0, 312: itwalk->id_incno, 313: date 314: ); 315: } 316: } 317: 318: int idatesort(p1, p2) 319: struct idates **p1, **p2; 320: { 321: int diff; 322: 323: diff = strncmp((*p1)->id_name, (*p2)->id_name, sizeof((*p1)->id_name)); 324: if (diff == 0) 325: if ((*p2)->id_ddate > (*p1)->id_ddate) 326: return (1); 327: else 328: if ((*p2)->id_ddate == (*p1)->id_ddate) 329: return (0); 330: else 331: return (-1); 332: else 333: return (diff); 334: } 335: 336: int max(a,b) 337: { 338: return(a>b?a:b); 339: } 340: int min(a,b) 341: { 342: return(a<b?a:b); 343: }