1*21124Smckusick static char *sccsid = "@(#)optr.c 1.9 (Berkeley) 05/28/85"; 25319Smckusic 31424Sroot #include "dump.h" 41424Sroot 51424Sroot /* 61424Sroot * This is from /usr/include/grp.h 71424Sroot * That defined struct group, which conflicts 81424Sroot * with the struct group defined in param.h 91424Sroot */ 101424Sroot struct Group { /* see getgrent(3) */ 111424Sroot char *gr_name; 121424Sroot char *gr_passwd; 131424Sroot int gr_gid; 141424Sroot char **gr_mem; 151424Sroot }; 161424Sroot struct Group *getgrnam(); 171424Sroot /* 181424Sroot * Query the operator; This fascist piece of code requires 191424Sroot * an exact response. 201424Sroot * It is intended to protect dump aborting by inquisitive 211424Sroot * people banging on the console terminal to see what is 221424Sroot * happening which might cause dump to croak, destroying 231424Sroot * a large number of hours of work. 241424Sroot * 251424Sroot * Every 2 minutes we reprint the message, alerting others 261424Sroot * that dump needs attention. 271424Sroot */ 281424Sroot int timeout; 29*21124Smckusick char *attnmessage; /* attention message */ 301424Sroot query(question) 311424Sroot char *question; 321424Sroot { 331424Sroot char replybuffer[64]; 341424Sroot int back; 351424Sroot FILE *mytty; 361424Sroot 371424Sroot if ( (mytty = fopen("/dev/tty", "r")) == NULL){ 381424Sroot msg("fopen on /dev/tty fails\n"); 391424Sroot abort(); 401424Sroot } 411424Sroot attnmessage = question; 421424Sroot timeout = 0; 431424Sroot alarmcatch(); 441424Sroot for(;;){ 451424Sroot if ( fgets(replybuffer, 63, mytty) == NULL){ 461424Sroot if (ferror(mytty)){ 471424Sroot clearerr(mytty); 481424Sroot continue; 491424Sroot } 501424Sroot } else if ( (strcmp(replybuffer, "yes\n") == 0) || 511424Sroot (strcmp(replybuffer, "Yes\n") == 0)){ 521424Sroot back = 1; 531424Sroot goto done; 541424Sroot } else if ( (strcmp(replybuffer, "no\n") == 0) || 551424Sroot (strcmp(replybuffer, "No\n") == 0)){ 561424Sroot back = 0; 571424Sroot goto done; 581424Sroot } else { 59*21124Smckusick msg("\"Yes\" or \"No\"?\n"); 601424Sroot alarmcatch(); 611424Sroot } 621424Sroot } 631424Sroot done: 641424Sroot /* 651424Sroot * Turn off the alarm, and reset the signal to trap out.. 661424Sroot */ 671424Sroot alarm(0); 681424Sroot if (signal(SIGALRM, sigalrm) == SIG_IGN) 691424Sroot signal(SIGALRM, SIG_IGN); 701424Sroot fclose(mytty); 711424Sroot return(back); 721424Sroot } 731424Sroot /* 741424Sroot * Alert the console operator, and enable the alarm clock to 751424Sroot * sleep for 2 minutes in case nobody comes to satisfy dump 761424Sroot */ 771424Sroot alarmcatch() 781424Sroot { 791424Sroot if (timeout) 801424Sroot msgtail("\n"); 811424Sroot msg("NEEDS ATTENTION: %s: (\"yes\" or \"no\") ", 821424Sroot attnmessage); 831424Sroot signal(SIGALRM, alarmcatch); 841424Sroot alarm(120); 851424Sroot timeout = 1; 861424Sroot } 871424Sroot /* 881424Sroot * Here if an inquisitive operator interrupts the dump program 891424Sroot */ 901424Sroot interrupt() 911424Sroot { 92*21124Smckusick msg("Interrupt received.\n"); 93*21124Smckusick if (query("Do you want to abort dump?")) 941424Sroot dumpabort(); 951424Sroot signal(SIGINT, interrupt); 961424Sroot } 971424Sroot 981424Sroot /* 991424Sroot * The following variables and routines manage alerting 1001424Sroot * operators to the status of dump. 1011424Sroot * This works much like wall(1) does. 1021424Sroot */ 1031424Sroot struct Group *gp; 1041424Sroot 1051424Sroot /* 1061424Sroot * Get the names from the group entry "operator" to notify. 1071424Sroot */ 1081424Sroot set_operators() 1091424Sroot { 1101424Sroot if (!notify) /*not going to notify*/ 1111424Sroot return; 1121424Sroot gp = getgrnam(OPGRENT); 1131424Sroot endgrent(); 1141424Sroot if (gp == (struct Group *)0){ 1151424Sroot msg("No entry in /etc/group for %s.\n", 1161424Sroot OPGRENT); 1171424Sroot notify = 0; 1181424Sroot return; 1191424Sroot } 1201424Sroot } 1211424Sroot 1221424Sroot struct tm *localtime(); 1231424Sroot struct tm *localclock; 1241424Sroot 1251424Sroot /* 1261424Sroot * We fork a child to do the actual broadcasting, so 1271424Sroot * that the process control groups are not messed up 1281424Sroot */ 1291424Sroot broadcast(message) 1301424Sroot char *message; 1311424Sroot { 1321424Sroot time_t clock; 1331424Sroot FILE *f_utmp; 1341424Sroot struct utmp utmp; 1351424Sroot int nusers; 1361424Sroot char **np; 1371424Sroot int pid, s; 1381424Sroot 1391424Sroot switch (pid = fork()) { 1401424Sroot case -1: 1411424Sroot return; 1421424Sroot case 0: 1431424Sroot break; 1441424Sroot default: 1451424Sroot while (wait(&s) != pid) 1461424Sroot continue; 1471424Sroot return; 1481424Sroot } 1491424Sroot 1501424Sroot if (!notify || gp == 0) 1511925Swnj exit(0); 1521424Sroot clock = time(0); 1531424Sroot localclock = localtime(&clock); 1541424Sroot 1551424Sroot if((f_utmp = fopen("/etc/utmp", "r")) == NULL) { 1561424Sroot msg("Cannot open /etc/utmp\n"); 1571424Sroot return; 1581424Sroot } 1591424Sroot 1601424Sroot nusers = 0; 1611424Sroot while (!feof(f_utmp)){ 1621424Sroot if (fread(&utmp, sizeof (struct utmp), 1, f_utmp) != 1) 1631424Sroot break; 1641424Sroot if (utmp.ut_name[0] == 0) 1651424Sroot continue; 1661424Sroot nusers++; 1671424Sroot for (np = gp->gr_mem; *np; np++){ 1681424Sroot if (strncmp(*np, utmp.ut_name, sizeof(utmp.ut_name)) != 0) 1691424Sroot continue; 1701424Sroot /* 1711424Sroot * Do not send messages to operators on dialups 1721424Sroot */ 1731424Sroot if (strncmp(utmp.ut_line, DIALUP, strlen(DIALUP)) == 0) 1741424Sroot continue; 1751424Sroot #ifdef DEBUG 1761424Sroot msg("Message to %s at %s\n", 1771424Sroot utmp.ut_name, utmp.ut_line); 1781424Sroot #endif DEBUG 1791424Sroot sendmes(utmp.ut_line, message); 1801424Sroot } 1811424Sroot } 1821424Sroot fclose(f_utmp); 1831424Sroot Exit(0); /* the wait in this same routine will catch this */ 1841424Sroot /* NOTREACHED */ 1851424Sroot } 1861424Sroot 1871424Sroot sendmes(tty, message) 1885319Smckusic char *tty, *message; 1891424Sroot { 1901424Sroot char t[50], buf[BUFSIZ]; 1911424Sroot register char *cp; 1921424Sroot register int c, ch; 1931424Sroot int msize; 1941424Sroot FILE *f_tty; 1951424Sroot 1961424Sroot msize = strlen(message); 1971424Sroot strcpy(t, "/dev/"); 1981424Sroot strcat(t, tty); 1991424Sroot 2001424Sroot if((f_tty = fopen(t, "w")) != NULL) { 2011424Sroot setbuf(f_tty, buf); 2021424Sroot fprintf(f_tty, "\nMessage from the dump program to all operators at %d:%02d ...\r\n\n" 2031424Sroot ,localclock->tm_hour 2041424Sroot ,localclock->tm_min); 2051424Sroot for (cp = message, c = msize; c-- > 0; cp++) { 2061424Sroot ch = *cp; 2071424Sroot if (ch == '\n') 2081424Sroot putc('\r', f_tty); 2091424Sroot putc(ch, f_tty); 2101424Sroot } 2111424Sroot fclose(f_tty); 2121424Sroot } 2131424Sroot } 2141424Sroot 2151424Sroot /* 2161424Sroot * print out an estimate of the amount of time left to do the dump 2171424Sroot */ 2181424Sroot 2191424Sroot time_t tschedule = 0; 2201424Sroot 2211424Sroot timeest() 2221424Sroot { 2231424Sroot time_t tnow, deltat; 2241424Sroot 2251424Sroot time (&tnow); 2261424Sroot if (tnow >= tschedule){ 2271424Sroot tschedule = tnow + 300; 2281424Sroot if (blockswritten < 500) 2291424Sroot return; 2301424Sroot deltat = tstart_writing - tnow + 2311424Sroot (((1.0*(tnow - tstart_writing))/blockswritten) * esize); 2321424Sroot msg("%3.2f%% done, finished in %d:%02d\n", 2331424Sroot (blockswritten*100.0)/esize, 2341424Sroot deltat/3600, (deltat%3600)/60); 2351424Sroot } 2361424Sroot } 2371424Sroot 2381424Sroot int blocksontape() 2391424Sroot { 2401424Sroot /* 2411424Sroot * esize: total number of blocks estimated over all reels 2421424Sroot * blockswritten: blocks actually written, over all reels 2431424Sroot * etapes: estimated number of tapes to write 2441424Sroot * 2451424Sroot * tsize: blocks can write on this reel 2461424Sroot * asize: blocks written on this reel 2471424Sroot * tapeno: number of tapes written so far 2481424Sroot */ 2491424Sroot if (tapeno == etapes) 2501424Sroot return(esize - (etapes - 1)*tsize); 2511424Sroot return(tsize); 2521424Sroot } 2531424Sroot 2541424Sroot /* VARARGS1 */ 2551424Sroot /* ARGSUSED */ 2561424Sroot msg(fmt, a1, a2, a3, a4, a5) 2571424Sroot char *fmt; 2585319Smckusic int a1, a2, a3, a4, a5; 2591424Sroot { 2601424Sroot fprintf(stderr," DUMP: "); 2611424Sroot #ifdef TDEBUG 2621424Sroot fprintf(stderr,"pid=%d ", getpid()); 2631424Sroot #endif 2641424Sroot fprintf(stderr, fmt, a1, a2, a3, a4, a5); 2651424Sroot fflush(stdout); 2661424Sroot fflush(stderr); 2671424Sroot } 2681424Sroot 2691424Sroot /* VARARGS1 */ 2701424Sroot /* ARGSUSED */ 2711424Sroot msgtail(fmt, a1, a2, a3, a4, a5) 2721424Sroot char *fmt; 2735319Smckusic int a1, a2, a3, a4, a5; 2741424Sroot { 2751424Sroot fprintf(stderr, fmt, a1, a2, a3, a4, a5); 2761424Sroot } 2771424Sroot /* 2781424Sroot * Tell the operator what has to be done; 2791424Sroot * we don't actually do it 2801424Sroot */ 2811424Sroot 28213047Ssam struct fstab * 28313047Ssam allocfsent(fs) 28413047Ssam register struct fstab *fs; 28513047Ssam { 28613047Ssam register struct fstab *new; 28713047Ssam register char *cp; 28813047Ssam char *malloc(); 28913047Ssam 29013047Ssam new = (struct fstab *)malloc(sizeof (*fs)); 29113047Ssam cp = malloc(strlen(fs->fs_file) + 1); 29213047Ssam strcpy(cp, fs->fs_file); 29313047Ssam new->fs_file = cp; 29413047Ssam cp = malloc(strlen(fs->fs_type) + 1); 29513047Ssam strcpy(cp, fs->fs_type); 29613047Ssam new->fs_type = cp; 29713047Ssam cp = malloc(strlen(fs->fs_spec) + 1); 29813047Ssam strcpy(cp, fs->fs_spec); 29913047Ssam new->fs_spec = cp; 30013047Ssam new->fs_passno = fs->fs_passno; 30113047Ssam new->fs_freq = fs->fs_freq; 30213047Ssam return (new); 30313047Ssam } 30413047Ssam 30513047Ssam struct pfstab { 30613047Ssam struct pfstab *pf_next; 30713047Ssam struct fstab *pf_fstab; 30813047Ssam }; 30913047Ssam 31013047Ssam static struct pfstab *table = NULL; 31113047Ssam 3121424Sroot getfstab() 3131424Sroot { 31413047Ssam register struct fstab *fs; 31513047Ssam register struct pfstab *pf; 3161424Sroot 3171428Sroot if (setfsent() == 0) { 3181424Sroot msg("Can't open %s for dump table information.\n", FSTAB); 31913047Ssam return; 3201424Sroot } 32113047Ssam while (fs = getfsent()) { 32213047Ssam if (strcmp(fs->fs_type, FSTAB_RW) && 32313047Ssam strcmp(fs->fs_type, FSTAB_RO) && 32413047Ssam strcmp(fs->fs_type, FSTAB_RQ)) 32513047Ssam continue; 32613047Ssam fs = allocfsent(fs); 32713047Ssam pf = (struct pfstab *)malloc(sizeof (*pf)); 32813047Ssam pf->pf_fstab = fs; 32913047Ssam pf->pf_next = table; 33013047Ssam table = pf; 33113047Ssam } 33213047Ssam endfsent(); 3331424Sroot } 3341424Sroot 3351424Sroot /* 33613047Ssam * Search in the fstab for a file name. 33713047Ssam * This file name can be either the special or the path file name. 3381424Sroot * 33913047Ssam * The entries in the fstab are the BLOCK special names, not the 34013047Ssam * character special names. 34113047Ssam * The caller of fstabsearch assures that the character device 34213047Ssam * is dumped (that is much faster) 3431424Sroot * 34413047Ssam * The file name can omit the leading '/'. 3451424Sroot */ 34613047Ssam struct fstab * 34713047Ssam fstabsearch(key) 34813047Ssam char *key; 3491424Sroot { 35013047Ssam register struct pfstab *pf; 35113047Ssam register struct fstab *fs; 35213047Ssam char *rawname(); 3531424Sroot 35413047Ssam if (table == NULL) 35513047Ssam return ((struct fstab *)0); 35613047Ssam for (pf = table; pf; pf = pf->pf_next) { 35713047Ssam fs = pf->pf_fstab; 35813197Sroot if (strcmp(fs->fs_file, key) == 0) 35913047Ssam return (fs); 36013197Sroot if (strcmp(fs->fs_spec, key) == 0) 36113047Ssam return (fs); 36213197Sroot if (strcmp(rawname(fs->fs_spec), key) == 0) 36313047Ssam return (fs); 3641424Sroot if (key[0] != '/'){ 36513047Ssam if (*fs->fs_spec == '/' && 36613197Sroot strcmp(fs->fs_spec + 1, key) == 0) 36713047Ssam return (fs); 36813047Ssam if (*fs->fs_file == '/' && 36913197Sroot strcmp(fs->fs_file + 1, key) == 0) 37013047Ssam return (fs); 3711424Sroot } 3721424Sroot } 37313047Ssam return (0); 3741424Sroot } 3751424Sroot 3761424Sroot /* 3771424Sroot * Tell the operator what to do 3781424Sroot */ 3791463Sroot lastdump(arg) 3801463Sroot char arg; /* w ==> just what to do; W ==> most recent dumps */ 3811424Sroot { 3821424Sroot char *lastname; 3831424Sroot char *date; 3841424Sroot register int i; 3851424Sroot time_t tnow; 3861424Sroot register struct fstab *dt; 3871424Sroot int dumpme; 3881424Sroot register struct idates *itwalk; 3891424Sroot 3901424Sroot int idatesort(); 3911424Sroot 3921424Sroot time(&tnow); 3931424Sroot getfstab(); /* /etc/fstab input */ 3941424Sroot inititimes(); /* /etc/dumpdates input */ 3951424Sroot qsort(idatev, nidates, sizeof(struct idates *), idatesort); 3961424Sroot 3971463Sroot if (arg == 'w') 3981463Sroot fprintf(stdout, "Dump these file systems:\n"); 3991463Sroot else 4001463Sroot fprintf(stdout, "Last dump(s) done (Dump '>' file systems):\n"); 4011424Sroot lastname = "??"; 4021424Sroot ITITERATE(i, itwalk){ 4031424Sroot if (strncmp(lastname, itwalk->id_name, sizeof(itwalk->id_name)) == 0) 4041424Sroot continue; 4051424Sroot date = (char *)ctime(&itwalk->id_ddate); 4061424Sroot date[16] = '\0'; /* blast away seconds and year */ 4071424Sroot lastname = itwalk->id_name; 4081424Sroot dt = fstabsearch(itwalk->id_name); 4091424Sroot dumpme = ( (dt != 0) 4101424Sroot && (dt->fs_freq != 0) 4111424Sroot && (itwalk->id_ddate < tnow - (dt->fs_freq*DAY))); 4121463Sroot if ( (arg != 'w') || dumpme) 4131463Sroot fprintf(stdout,"%c %8s\t(%6s) Last dump: Level %c, Date %s\n", 4141463Sroot dumpme && (arg != 'w') ? '>' : ' ', 4151424Sroot itwalk->id_name, 41610910Ssam dt ? dt->fs_file : "", 4171424Sroot itwalk->id_incno, 4181424Sroot date 4191424Sroot ); 4201424Sroot } 4211424Sroot } 4221424Sroot 4231424Sroot int idatesort(p1, p2) 4241424Sroot struct idates **p1, **p2; 4251424Sroot { 4261424Sroot int diff; 4271424Sroot 4281424Sroot diff = strncmp((*p1)->id_name, (*p2)->id_name, sizeof((*p1)->id_name)); 4291424Sroot if (diff == 0) 4301424Sroot return ((*p2)->id_ddate - (*p1)->id_ddate); 4311424Sroot else 4321424Sroot return (diff); 4331424Sroot } 4341424Sroot 4351424Sroot int max(a,b) 4365319Smckusic int a, b; 4371424Sroot { 4381424Sroot return(a>b?a:b); 4391424Sroot } 4401424Sroot int min(a,b) 4415319Smckusic int a, b; 4421424Sroot { 4431424Sroot return(a<b?a:b); 4441424Sroot } 445