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