1*10910Ssam static char *sccsid = "@(#)optr.c 1.6 (Berkeley) 02/11/83"; 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; 291424Sroot char *attnmessage; /* attemtion 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 { 591424Sroot msg("\"Yes\" or \"No\" ONLY!\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 { 921424Sroot msg("Interrupt received. Do >>>YOU<<< know what are you doing?\n"); 931424Sroot if (query("Do you really 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 2821424Sroot getfstab() 2831424Sroot { 2841424Sroot register struct fstab *dt; 2851428Sroot struct fstab *fsp; 2861424Sroot 2871424Sroot nfstab = 0; 2881428Sroot if (setfsent() == 0) { 2891424Sroot msg("Can't open %s for dump table information.\n", FSTAB); 2901424Sroot } else { 2911424Sroot for (nfstab = 0, dt = fstab; nfstab < MAXFSTAB;){ 2921428Sroot if ( (fsp = getfsent()) == 0) 2931424Sroot break; 2941428Sroot if ( (strcmp(fsp->fs_type, FSTAB_RW) == 0) 2951428Sroot || (strcmp(fsp->fs_type, FSTAB_RO) == 0) ){ 2961428Sroot *dt = *fsp; 2971428Sroot nfstab++; 2981428Sroot dt++; 2991428Sroot } 3001424Sroot } 3011428Sroot endfsent(); 3021424Sroot } 3031424Sroot } 3041424Sroot 3051424Sroot /* 3061424Sroot * Search in the fstab for a file name. 3071424Sroot * This file name can be either the special or the path file name. 3081424Sroot * 3091424Sroot * The entries in the fstab are the BLOCK special names, not the 3101424Sroot * character special names. 3111424Sroot * The caller of fstabsearch assures that the character device 3121424Sroot * is dumped (that is much faster) 3131424Sroot * 3141424Sroot * The file name can omit the leading '/'. 3151424Sroot */ 3161424Sroot struct fstab *fstabsearch(key) 3171424Sroot char *key; 3181424Sroot { 3191424Sroot register struct fstab *dt; 3201424Sroot int i; 3211424Sroot int keylength; 3221424Sroot char *rawname(); 3231424Sroot 3241424Sroot keylength = min(strlen(key), sizeof (dt->fs_file)); 3251424Sroot for (i = 0, dt = fstab; i < nfstab; i++, dt++){ 3261424Sroot if (strncmp(dt->fs_file, key, keylength) == 0) 3271424Sroot return(dt); 3281424Sroot if (strncmp(dt->fs_spec, key, keylength) == 0) 3291424Sroot return(dt); 3301424Sroot if (strncmp(rawname(dt->fs_spec), key, keylength) == 0) 3311424Sroot return(dt); 3321424Sroot 3331424Sroot if (key[0] != '/'){ 3341424Sroot if ( (dt->fs_spec[0] == '/') 3351424Sroot && (strncmp(dt->fs_spec+1, key, keylength) == 0)) 3361424Sroot return(dt); 3371424Sroot if ( (dt->fs_file[0] == '/') 3381424Sroot && (strncmp(dt->fs_file+1, key, keylength) == 0)) 3391424Sroot return(dt); 3401424Sroot } 3411424Sroot } 3421424Sroot return(0); 3431424Sroot } 3441424Sroot 3451424Sroot /* 3461424Sroot * Tell the operator what to do 3471424Sroot */ 3481463Sroot lastdump(arg) 3491463Sroot char arg; /* w ==> just what to do; W ==> most recent dumps */ 3501424Sroot { 3511424Sroot char *lastname; 3521424Sroot char *date; 3531424Sroot register int i; 3541424Sroot time_t tnow; 3551424Sroot register struct fstab *dt; 3561424Sroot int dumpme; 3571424Sroot register struct idates *itwalk; 3581424Sroot 3591424Sroot int idatesort(); 3601424Sroot 3611424Sroot time(&tnow); 3621424Sroot getfstab(); /* /etc/fstab input */ 3631424Sroot inititimes(); /* /etc/dumpdates input */ 3641424Sroot qsort(idatev, nidates, sizeof(struct idates *), idatesort); 3651424Sroot 3661463Sroot if (arg == 'w') 3671463Sroot fprintf(stdout, "Dump these file systems:\n"); 3681463Sroot else 3691463Sroot fprintf(stdout, "Last dump(s) done (Dump '>' file systems):\n"); 3701424Sroot lastname = "??"; 3711424Sroot ITITERATE(i, itwalk){ 3721424Sroot if (strncmp(lastname, itwalk->id_name, sizeof(itwalk->id_name)) == 0) 3731424Sroot continue; 3741424Sroot date = (char *)ctime(&itwalk->id_ddate); 3751424Sroot date[16] = '\0'; /* blast away seconds and year */ 3761424Sroot lastname = itwalk->id_name; 3771424Sroot dt = fstabsearch(itwalk->id_name); 3781424Sroot dumpme = ( (dt != 0) 3791424Sroot && (dt->fs_freq != 0) 3801424Sroot && (itwalk->id_ddate < tnow - (dt->fs_freq*DAY))); 3811463Sroot if ( (arg != 'w') || dumpme) 3821463Sroot fprintf(stdout,"%c %8s\t(%6s) Last dump: Level %c, Date %s\n", 3831463Sroot dumpme && (arg != 'w') ? '>' : ' ', 3841424Sroot itwalk->id_name, 385*10910Ssam dt ? dt->fs_file : "", 3861424Sroot itwalk->id_incno, 3871424Sroot date 3881424Sroot ); 3891424Sroot } 3901424Sroot } 3911424Sroot 3921424Sroot int idatesort(p1, p2) 3931424Sroot struct idates **p1, **p2; 3941424Sroot { 3951424Sroot int diff; 3961424Sroot 3971424Sroot diff = strncmp((*p1)->id_name, (*p2)->id_name, sizeof((*p1)->id_name)); 3981424Sroot if (diff == 0) 3991424Sroot return ((*p2)->id_ddate - (*p1)->id_ddate); 4001424Sroot else 4011424Sroot return (diff); 4021424Sroot } 4031424Sroot 4041424Sroot int max(a,b) 4055319Smckusic int a, b; 4061424Sroot { 4071424Sroot return(a>b?a:b); 4081424Sroot } 4091424Sroot int min(a,b) 4105319Smckusic int a, b; 4111424Sroot { 4121424Sroot return(a<b?a:b); 4131424Sroot } 414