1*1925Swnj static char *sccsid = "@(#)optr.c 1.4 (Berkeley) 12/18/80"; 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) 150*1925Swnj 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 2791424Sroot getfstab() 2801424Sroot { 2811424Sroot register struct fstab *dt; 2821428Sroot struct fstab *fsp; 2831424Sroot 2841424Sroot nfstab = 0; 2851428Sroot if (setfsent() == 0) { 2861424Sroot msg("Can't open %s for dump table information.\n", FSTAB); 2871424Sroot } else { 2881424Sroot for (nfstab = 0, dt = fstab; nfstab < MAXFSTAB;){ 2891428Sroot if ( (fsp = getfsent()) == 0) 2901424Sroot break; 2911428Sroot if ( (strcmp(fsp->fs_type, FSTAB_RW) == 0) 2921428Sroot || (strcmp(fsp->fs_type, FSTAB_RO) == 0) ){ 2931428Sroot *dt = *fsp; 2941428Sroot nfstab++; 2951428Sroot dt++; 2961428Sroot } 2971424Sroot } 2981428Sroot endfsent(); 2991424Sroot } 3001424Sroot } 3011424Sroot 3021424Sroot /* 3031424Sroot * Search in the fstab for a file name. 3041424Sroot * This file name can be either the special or the path file name. 3051424Sroot * 3061424Sroot * The entries in the fstab are the BLOCK special names, not the 3071424Sroot * character special names. 3081424Sroot * The caller of fstabsearch assures that the character device 3091424Sroot * is dumped (that is much faster) 3101424Sroot * 3111424Sroot * The file name can omit the leading '/'. 3121424Sroot */ 3131424Sroot struct fstab *fstabsearch(key) 3141424Sroot char *key; 3151424Sroot { 3161424Sroot register struct fstab *dt; 3171424Sroot int i; 3181424Sroot int keylength; 3191424Sroot char *rawname(); 3201424Sroot 3211424Sroot keylength = min(strlen(key), sizeof (dt->fs_file)); 3221424Sroot for (i = 0, dt = fstab; i < nfstab; i++, dt++){ 3231424Sroot if (strncmp(dt->fs_file, key, keylength) == 0) 3241424Sroot return(dt); 3251424Sroot if (strncmp(dt->fs_spec, key, keylength) == 0) 3261424Sroot return(dt); 3271424Sroot if (strncmp(rawname(dt->fs_spec), key, keylength) == 0) 3281424Sroot return(dt); 3291424Sroot 3301424Sroot if (key[0] != '/'){ 3311424Sroot if ( (dt->fs_spec[0] == '/') 3321424Sroot && (strncmp(dt->fs_spec+1, key, keylength) == 0)) 3331424Sroot return(dt); 3341424Sroot if ( (dt->fs_file[0] == '/') 3351424Sroot && (strncmp(dt->fs_file+1, key, keylength) == 0)) 3361424Sroot return(dt); 3371424Sroot } 3381424Sroot } 3391424Sroot return(0); 3401424Sroot } 3411424Sroot 3421424Sroot /* 3431424Sroot * Tell the operator what to do 3441424Sroot */ 3451463Sroot lastdump(arg) 3461463Sroot char arg; /* w ==> just what to do; W ==> most recent dumps */ 3471424Sroot { 3481424Sroot char *lastname; 3491424Sroot char *date; 3501424Sroot register int i; 3511424Sroot time_t tnow; 3521424Sroot register struct fstab *dt; 3531424Sroot int dumpme; 3541424Sroot register struct idates *itwalk; 3551424Sroot 3561424Sroot int idatesort(); 3571424Sroot 3581424Sroot time(&tnow); 3591424Sroot getfstab(); /* /etc/fstab input */ 3601424Sroot inititimes(); /* /etc/dumpdates input */ 3611424Sroot qsort(idatev, nidates, sizeof(struct idates *), idatesort); 3621424Sroot 3631463Sroot if (arg == 'w') 3641463Sroot fprintf(stdout, "Dump these file systems:\n"); 3651463Sroot else 3661463Sroot fprintf(stdout, "Last dump(s) done (Dump '>' file systems):\n"); 3671424Sroot lastname = "??"; 3681424Sroot ITITERATE(i, itwalk){ 3691424Sroot if (strncmp(lastname, itwalk->id_name, sizeof(itwalk->id_name)) == 0) 3701424Sroot continue; 3711424Sroot date = (char *)ctime(&itwalk->id_ddate); 3721424Sroot date[16] = '\0'; /* blast away seconds and year */ 3731424Sroot lastname = itwalk->id_name; 3741424Sroot dt = fstabsearch(itwalk->id_name); 3751424Sroot dumpme = ( (dt != 0) 3761424Sroot && (dt->fs_freq != 0) 3771424Sroot && (itwalk->id_ddate < tnow - (dt->fs_freq*DAY))); 3781463Sroot if ( (arg != 'w') || dumpme) 3791463Sroot fprintf(stdout,"%c %8s\t(%6s) Last dump: Level %c, Date %s\n", 3801463Sroot dumpme && (arg != 'w') ? '>' : ' ', 3811424Sroot itwalk->id_name, 3821424Sroot dt ? dt->fs_file : 0, 3831424Sroot itwalk->id_incno, 3841424Sroot date 3851424Sroot ); 3861424Sroot } 3871424Sroot } 3881424Sroot 3891424Sroot int idatesort(p1, p2) 3901424Sroot struct idates **p1, **p2; 3911424Sroot { 3921424Sroot int diff; 3931424Sroot 3941424Sroot diff = strncmp((*p1)->id_name, (*p2)->id_name, sizeof((*p1)->id_name)); 3951424Sroot if (diff == 0) 3961424Sroot return ((*p2)->id_ddate - (*p1)->id_ddate); 3971424Sroot else 3981424Sroot return (diff); 3991424Sroot } 4001424Sroot 4011424Sroot int max(a,b) 4021424Sroot { 4031424Sroot return(a>b?a:b); 4041424Sroot } 4051424Sroot int min(a,b) 4061424Sroot { 4071424Sroot return(a<b?a:b); 4081424Sroot } 409