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