1*13205Ssam static char *sccsid = "@(#)dumpoptr.c 1.6 (Berkeley) 06/19/83"; 21424Sroot #include "dump.h" 31424Sroot 41424Sroot /* 51424Sroot * This is from /usr/include/grp.h 61424Sroot * That defined struct group, which conflicts 71424Sroot * with the struct group defined in param.h 81424Sroot */ 91424Sroot struct Group { /* see getgrent(3) */ 101424Sroot char *gr_name; 111424Sroot char *gr_passwd; 121424Sroot int gr_gid; 131424Sroot char **gr_mem; 141424Sroot }; 151424Sroot struct Group *getgrnam(); 161424Sroot /* 171424Sroot * Query the operator; This fascist piece of code requires 181424Sroot * an exact response. 191424Sroot * It is intended to protect dump aborting by inquisitive 201424Sroot * people banging on the console terminal to see what is 211424Sroot * happening which might cause dump to croak, destroying 221424Sroot * a large number of hours of work. 231424Sroot * 241424Sroot * Every 2 minutes we reprint the message, alerting others 251424Sroot * that dump needs attention. 261424Sroot */ 271424Sroot int timeout; 281424Sroot char *attnmessage; /* attemtion message */ 291424Sroot query(question) 301424Sroot char *question; 311424Sroot { 321424Sroot char replybuffer[64]; 331424Sroot int back; 341424Sroot FILE *mytty; 351424Sroot 361424Sroot if ( (mytty = fopen("/dev/tty", "r")) == NULL){ 371424Sroot msg("fopen on /dev/tty fails\n"); 381424Sroot abort(); 391424Sroot } 401424Sroot attnmessage = question; 411424Sroot timeout = 0; 421424Sroot alarmcatch(); 431424Sroot for(;;){ 441424Sroot if ( fgets(replybuffer, 63, mytty) == NULL){ 451424Sroot if (ferror(mytty)){ 461424Sroot clearerr(mytty); 471424Sroot continue; 481424Sroot } 491424Sroot } else if ( (strcmp(replybuffer, "yes\n") == 0) || 501424Sroot (strcmp(replybuffer, "Yes\n") == 0)){ 511424Sroot back = 1; 521424Sroot goto done; 531424Sroot } else if ( (strcmp(replybuffer, "no\n") == 0) || 541424Sroot (strcmp(replybuffer, "No\n") == 0)){ 551424Sroot back = 0; 561424Sroot goto done; 571424Sroot } else { 581424Sroot msg("\"Yes\" or \"No\" ONLY!\n"); 591424Sroot alarmcatch(); 601424Sroot } 611424Sroot } 621424Sroot done: 631424Sroot /* 641424Sroot * Turn off the alarm, and reset the signal to trap out.. 651424Sroot */ 661424Sroot alarm(0); 671424Sroot if (signal(SIGALRM, sigalrm) == SIG_IGN) 681424Sroot signal(SIGALRM, SIG_IGN); 691424Sroot fclose(mytty); 701424Sroot return(back); 711424Sroot } 721424Sroot /* 731424Sroot * Alert the console operator, and enable the alarm clock to 741424Sroot * sleep for 2 minutes in case nobody comes to satisfy dump 751424Sroot */ 761424Sroot alarmcatch() 771424Sroot { 781424Sroot if (timeout) 791424Sroot msgtail("\n"); 801424Sroot msg("NEEDS ATTENTION: %s: (\"yes\" or \"no\") ", 811424Sroot attnmessage); 821424Sroot signal(SIGALRM, alarmcatch); 831424Sroot alarm(120); 841424Sroot timeout = 1; 851424Sroot } 861424Sroot /* 871424Sroot * Here if an inquisitive operator interrupts the dump program 881424Sroot */ 891424Sroot interrupt() 901424Sroot { 911424Sroot msg("Interrupt received. Do >>>YOU<<< know what are you doing?\n"); 921424Sroot if (query("Do you really want to abort dump?")) 931424Sroot dumpabort(); 941424Sroot signal(SIGINT, interrupt); 951424Sroot } 961424Sroot 971424Sroot /* 981424Sroot * The following variables and routines manage alerting 991424Sroot * operators to the status of dump. 1001424Sroot * This works much like wall(1) does. 1011424Sroot */ 1021424Sroot struct Group *gp; 1031424Sroot 1041424Sroot /* 1051424Sroot * Get the names from the group entry "operator" to notify. 1061424Sroot */ 1071424Sroot set_operators() 1081424Sroot { 1091424Sroot if (!notify) /*not going to notify*/ 1101424Sroot return; 1111424Sroot gp = getgrnam(OPGRENT); 1121424Sroot endgrent(); 1131424Sroot if (gp == (struct Group *)0){ 1141424Sroot msg("No entry in /etc/group for %s.\n", 1151424Sroot OPGRENT); 1161424Sroot notify = 0; 1171424Sroot return; 1181424Sroot } 1191424Sroot } 1201424Sroot 1211424Sroot struct tm *localtime(); 1221424Sroot struct tm *localclock; 1231424Sroot 1241424Sroot /* 1251424Sroot * We fork a child to do the actual broadcasting, so 1261424Sroot * that the process control groups are not messed up 1271424Sroot */ 1281424Sroot broadcast(message) 1291424Sroot char *message; 1301424Sroot { 1311424Sroot time_t clock; 1321424Sroot FILE *f_utmp; 1331424Sroot struct utmp utmp; 1341424Sroot int nusers; 1351424Sroot char **np; 1361424Sroot int pid, s; 1371424Sroot 1381424Sroot switch (pid = fork()) { 1391424Sroot case -1: 1401424Sroot return; 1411424Sroot case 0: 1421424Sroot break; 1431424Sroot default: 1441424Sroot while (wait(&s) != pid) 1451424Sroot continue; 1461424Sroot return; 1471424Sroot } 1481424Sroot 1491424Sroot if (!notify || gp == 0) 1501925Swnj exit(0); 1511424Sroot clock = time(0); 1521424Sroot localclock = localtime(&clock); 1531424Sroot 1541424Sroot if((f_utmp = fopen("/etc/utmp", "r")) == NULL) { 1551424Sroot msg("Cannot open /etc/utmp\n"); 1561424Sroot return; 1571424Sroot } 1581424Sroot 1591424Sroot nusers = 0; 1601424Sroot while (!feof(f_utmp)){ 1611424Sroot if (fread(&utmp, sizeof (struct utmp), 1, f_utmp) != 1) 1621424Sroot break; 1631424Sroot if (utmp.ut_name[0] == 0) 1641424Sroot continue; 1651424Sroot nusers++; 1661424Sroot for (np = gp->gr_mem; *np; np++){ 1671424Sroot if (strncmp(*np, utmp.ut_name, sizeof(utmp.ut_name)) != 0) 1681424Sroot continue; 1691424Sroot /* 1701424Sroot * Do not send messages to operators on dialups 1711424Sroot */ 1721424Sroot if (strncmp(utmp.ut_line, DIALUP, strlen(DIALUP)) == 0) 1731424Sroot continue; 1741424Sroot #ifdef DEBUG 1751424Sroot msg("Message to %s at %s\n", 1761424Sroot utmp.ut_name, utmp.ut_line); 1771424Sroot #endif DEBUG 1781424Sroot sendmes(utmp.ut_line, message); 1791424Sroot } 1801424Sroot } 1811424Sroot fclose(f_utmp); 1821424Sroot Exit(0); /* the wait in this same routine will catch this */ 1831424Sroot /* NOTREACHED */ 1841424Sroot } 1851424Sroot 1861424Sroot sendmes(tty, message) 1871424Sroot char *tty, *message; 1881424Sroot { 1891424Sroot char t[50], buf[BUFSIZ]; 1901424Sroot register char *cp; 1911424Sroot register int c, ch; 1921424Sroot int msize; 1931424Sroot FILE *f_tty; 1941424Sroot 1951424Sroot msize = strlen(message); 1961424Sroot strcpy(t, "/dev/"); 1971424Sroot strcat(t, tty); 1981424Sroot 1991424Sroot if((f_tty = fopen(t, "w")) != NULL) { 2001424Sroot setbuf(f_tty, buf); 2011424Sroot fprintf(f_tty, "\nMessage from the dump program to all operators at %d:%02d ...\r\n\n" 2021424Sroot ,localclock->tm_hour 2031424Sroot ,localclock->tm_min); 2041424Sroot for (cp = message, c = msize; c-- > 0; cp++) { 2051424Sroot ch = *cp; 2061424Sroot if (ch == '\n') 2071424Sroot putc('\r', f_tty); 2081424Sroot putc(ch, f_tty); 2091424Sroot } 2101424Sroot fclose(f_tty); 2111424Sroot } 2121424Sroot } 2131424Sroot 2141424Sroot /* 2151424Sroot * print out an estimate of the amount of time left to do the dump 2161424Sroot */ 2171424Sroot 2181424Sroot time_t tschedule = 0; 2191424Sroot 2201424Sroot timeest() 2211424Sroot { 2221424Sroot time_t tnow, deltat; 2231424Sroot 2241424Sroot time (&tnow); 2251424Sroot if (tnow >= tschedule){ 2261424Sroot tschedule = tnow + 300; 2271424Sroot if (blockswritten < 500) 2281424Sroot return; 2291424Sroot deltat = tstart_writing - tnow + 2301424Sroot (((1.0*(tnow - tstart_writing))/blockswritten) * esize); 2311424Sroot msg("%3.2f%% done, finished in %d:%02d\n", 2321424Sroot (blockswritten*100.0)/esize, 2331424Sroot deltat/3600, (deltat%3600)/60); 2341424Sroot } 2351424Sroot } 2361424Sroot 2371424Sroot int blocksontape() 2381424Sroot { 2391424Sroot /* 2401424Sroot * esize: total number of blocks estimated over all reels 2411424Sroot * blockswritten: blocks actually written, over all reels 2421424Sroot * etapes: estimated number of tapes to write 2431424Sroot * 2441424Sroot * tsize: blocks can write on this reel 2451424Sroot * asize: blocks written on this reel 2461424Sroot * tapeno: number of tapes written so far 2471424Sroot */ 2481424Sroot if (tapeno == etapes) 2491424Sroot return(esize - (etapes - 1)*tsize); 2501424Sroot return(tsize); 2511424Sroot } 2521424Sroot 2531424Sroot /* VARARGS1 */ 2541424Sroot /* ARGSUSED */ 2551424Sroot msg(fmt, a1, a2, a3, a4, a5) 2561424Sroot char *fmt; 2571424Sroot { 2581424Sroot fprintf(stderr," DUMP: "); 2591424Sroot #ifdef TDEBUG 2601424Sroot fprintf(stderr,"pid=%d ", getpid()); 2611424Sroot #endif 2621424Sroot fprintf(stderr, fmt, a1, a2, a3, a4, a5); 2631424Sroot fflush(stdout); 2641424Sroot fflush(stderr); 2651424Sroot } 2661424Sroot 2671424Sroot /* VARARGS1 */ 2681424Sroot /* ARGSUSED */ 2691424Sroot msgtail(fmt, a1, a2, a3, a4, a5) 2701424Sroot char *fmt; 2711424Sroot { 2721424Sroot fprintf(stderr, fmt, a1, a2, a3, a4, a5); 2731424Sroot } 2741424Sroot /* 2751424Sroot * Tell the operator what has to be done; 2761424Sroot * we don't actually do it 2771424Sroot */ 2781424Sroot 27913048Ssam struct fstab * 28013048Ssam allocfsent(fs) 28113048Ssam register struct fstab *fs; 28213048Ssam { 28313048Ssam register struct fstab *new; 28413048Ssam register char *cp; 28513048Ssam char *malloc(); 28613048Ssam 28713048Ssam new = (struct fstab *)malloc(sizeof (*fs)); 28813048Ssam cp = malloc(strlen(fs->fs_file) + 1); 28913048Ssam strcpy(cp, fs->fs_file); 29013048Ssam new->fs_file = cp; 29113048Ssam cp = malloc(strlen(fs->fs_type) + 1); 29213048Ssam strcpy(cp, fs->fs_type); 29313048Ssam new->fs_type = cp; 29413048Ssam cp = malloc(strlen(fs->fs_spec) + 1); 29513048Ssam strcpy(cp, fs->fs_spec); 29613048Ssam new->fs_spec = cp; 29713048Ssam new->fs_passno = fs->fs_passno; 29813048Ssam new->fs_freq = fs->fs_freq; 29913048Ssam return (new); 30013048Ssam } 30113048Ssam 30213048Ssam struct pfstab { 30313048Ssam struct pfstab *pf_next; 30413048Ssam struct fstab *pf_fstab; 30513048Ssam }; 30613048Ssam 30713048Ssam static struct pfstab *table = NULL; 30813048Ssam 3091424Sroot getfstab() 3101424Sroot { 31113048Ssam register struct fstab *fs; 31213048Ssam register struct pfstab *pf; 3131424Sroot 3141428Sroot if (setfsent() == 0) { 3151424Sroot msg("Can't open %s for dump table information.\n", FSTAB); 31613048Ssam return; 3171424Sroot } 31813048Ssam while (fs = getfsent()) { 31913048Ssam if (strcmp(fs->fs_type, FSTAB_RW) && 32013048Ssam strcmp(fs->fs_type, FSTAB_RO) && 32113048Ssam strcmp(fs->fs_type, FSTAB_RQ)) 32213048Ssam continue; 32313048Ssam fs = allocfsent(fs); 32413048Ssam pf = (struct pfstab *)malloc(sizeof (*pf)); 32513048Ssam pf->pf_fstab = fs; 32613048Ssam pf->pf_next = table; 32713048Ssam table = pf; 32813048Ssam } 32913048Ssam endfsent(); 3301424Sroot } 3311424Sroot 3321424Sroot /* 33313048Ssam * Search in the fstab for a file name. 33413048Ssam * This file name can be either the special or the path file name. 3351424Sroot * 33613048Ssam * The entries in the fstab are the BLOCK special names, not the 33713048Ssam * character special names. 33813048Ssam * The caller of fstabsearch assures that the character device 33913048Ssam * is dumped (that is much faster) 3401424Sroot * 34113048Ssam * The file name can omit the leading '/'. 3421424Sroot */ 34313048Ssam struct fstab * 34413048Ssam fstabsearch(key) 34513048Ssam char *key; 3461424Sroot { 34713048Ssam register struct pfstab *pf; 34813048Ssam register struct fstab *fs; 34913048Ssam char *rawname(); 3501424Sroot 35113048Ssam if (table == NULL) 35213048Ssam return ((struct fstab *)0); 35313048Ssam for (pf = table; pf; pf = pf->pf_next) { 35413048Ssam fs = pf->pf_fstab; 355*13205Ssam if (strcmp(fs->fs_file, key) == 0) 35613048Ssam return (fs); 357*13205Ssam if (strcmp(fs->fs_spec, key) == 0) 35813048Ssam return (fs); 359*13205Ssam if (strcmp(rawname(fs->fs_spec), key) == 0) 36013048Ssam return (fs); 3611424Sroot if (key[0] != '/'){ 36213048Ssam if (*fs->fs_spec == '/' && 363*13205Ssam strcmp(fs->fs_spec + 1, key) == 0) 36413048Ssam return (fs); 36513048Ssam if (*fs->fs_file == '/' && 366*13205Ssam strcmp(fs->fs_file + 1, key) == 0) 36713048Ssam return (fs); 3681424Sroot } 3691424Sroot } 37013048Ssam return (0); 3711424Sroot } 3721424Sroot 3731424Sroot /* 3741424Sroot * Tell the operator what to do 3751424Sroot */ 3761463Sroot lastdump(arg) 3771463Sroot char arg; /* w ==> just what to do; W ==> most recent dumps */ 3781424Sroot { 3791424Sroot char *lastname; 3801424Sroot char *date; 3811424Sroot register int i; 3821424Sroot time_t tnow; 3831424Sroot register struct fstab *dt; 3841424Sroot int dumpme; 3851424Sroot register struct idates *itwalk; 3861424Sroot 3871424Sroot int idatesort(); 3881424Sroot 3891424Sroot time(&tnow); 3901424Sroot getfstab(); /* /etc/fstab input */ 3911424Sroot inititimes(); /* /etc/dumpdates input */ 3921424Sroot qsort(idatev, nidates, sizeof(struct idates *), idatesort); 3931424Sroot 3941463Sroot if (arg == 'w') 3951463Sroot fprintf(stdout, "Dump these file systems:\n"); 3961463Sroot else 3971463Sroot fprintf(stdout, "Last dump(s) done (Dump '>' file systems):\n"); 3981424Sroot lastname = "??"; 3991424Sroot ITITERATE(i, itwalk){ 4001424Sroot if (strncmp(lastname, itwalk->id_name, sizeof(itwalk->id_name)) == 0) 4011424Sroot continue; 4021424Sroot date = (char *)ctime(&itwalk->id_ddate); 4031424Sroot date[16] = '\0'; /* blast away seconds and year */ 4041424Sroot lastname = itwalk->id_name; 4051424Sroot dt = fstabsearch(itwalk->id_name); 4061424Sroot dumpme = ( (dt != 0) 4071424Sroot && (dt->fs_freq != 0) 4081424Sroot && (itwalk->id_ddate < tnow - (dt->fs_freq*DAY))); 4091463Sroot if ( (arg != 'w') || dumpme) 4101463Sroot fprintf(stdout,"%c %8s\t(%6s) Last dump: Level %c, Date %s\n", 4111463Sroot dumpme && (arg != 'w') ? '>' : ' ', 4121424Sroot itwalk->id_name, 4131424Sroot dt ? dt->fs_file : 0, 4141424Sroot itwalk->id_incno, 4151424Sroot date 4161424Sroot ); 4171424Sroot } 4181424Sroot } 4191424Sroot 4201424Sroot int idatesort(p1, p2) 4211424Sroot struct idates **p1, **p2; 4221424Sroot { 4231424Sroot int diff; 4241424Sroot 4251424Sroot diff = strncmp((*p1)->id_name, (*p2)->id_name, sizeof((*p1)->id_name)); 4261424Sroot if (diff == 0) 4271424Sroot return ((*p2)->id_ddate - (*p1)->id_ddate); 4281424Sroot else 4291424Sroot return (diff); 4301424Sroot } 4311424Sroot 4321424Sroot int max(a,b) 4331424Sroot { 4341424Sroot return(a>b?a:b); 4351424Sroot } 4361424Sroot int min(a,b) 4371424Sroot { 4381424Sroot return(a<b?a:b); 4391424Sroot } 440