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