122038Sdist /* 2*39130Smckusick * Copyright (c) 1980, 1988 Regents of the University of California. 322038Sdist * All rights reserved. The Berkeley software License Agreement 422038Sdist * specifies the terms and conditions for redistribution. 522038Sdist */ 65319Smckusic 722038Sdist #ifndef lint 8*39130Smckusick static char sccsid[] = "@(#)optr.c 5.2 (Berkeley) 09/12/89"; 922038Sdist #endif not lint 1022038Sdist 111424Sroot #include "dump.h" 12*39130Smckusick #include "pathnames.h" 131424Sroot 141424Sroot /* 151424Sroot * This is from /usr/include/grp.h 161424Sroot * That defined struct group, which conflicts 171424Sroot * with the struct group defined in param.h 181424Sroot */ 191424Sroot struct Group { /* see getgrent(3) */ 201424Sroot char *gr_name; 211424Sroot char *gr_passwd; 221424Sroot int gr_gid; 231424Sroot char **gr_mem; 241424Sroot }; 251424Sroot struct Group *getgrnam(); 261424Sroot /* 27*39130Smckusick * Query the operator; This previously-fascist piece of code 28*39130Smckusick * no longer requires an exact response. 291424Sroot * It is intended to protect dump aborting by inquisitive 301424Sroot * people banging on the console terminal to see what is 311424Sroot * happening which might cause dump to croak, destroying 321424Sroot * a large number of hours of work. 331424Sroot * 341424Sroot * Every 2 minutes we reprint the message, alerting others 351424Sroot * that dump needs attention. 361424Sroot */ 371424Sroot int timeout; 3821124Smckusick char *attnmessage; /* attention message */ 391424Sroot query(question) 401424Sroot char *question; 411424Sroot { 421424Sroot char replybuffer[64]; 431424Sroot int back; 441424Sroot FILE *mytty; 451424Sroot 46*39130Smckusick if ( (mytty = fopen(_PATH_TTY, "r")) == NULL){ 47*39130Smckusick msg("fopen on %s fails\n", _PATH_TTY); 481424Sroot abort(); 491424Sroot } 501424Sroot attnmessage = question; 511424Sroot timeout = 0; 521424Sroot alarmcatch(); 531424Sroot for(;;){ 541424Sroot if ( fgets(replybuffer, 63, mytty) == NULL){ 551424Sroot if (ferror(mytty)){ 561424Sroot clearerr(mytty); 571424Sroot continue; 581424Sroot } 59*39130Smckusick } else if (replybuffer[0] == 'y' || replybuffer[0] == 'Y') { 601424Sroot back = 1; 611424Sroot goto done; 62*39130Smckusick } else if (replybuffer[0] == 'n' || replybuffer[0] == 'N') { 631424Sroot back = 0; 641424Sroot goto done; 651424Sroot } else { 66*39130Smckusick fprintf(stderr, " DUMP: \"Yes\" or \"No\"?\n"); 67*39130Smckusick fprintf(stderr," DUMP: %s: (\"yes\" or \"no\") ", 68*39130Smckusick question); 691424Sroot } 701424Sroot } 711424Sroot done: 721424Sroot /* 731424Sroot * Turn off the alarm, and reset the signal to trap out.. 741424Sroot */ 751424Sroot alarm(0); 761424Sroot if (signal(SIGALRM, sigalrm) == SIG_IGN) 771424Sroot signal(SIGALRM, SIG_IGN); 781424Sroot fclose(mytty); 791424Sroot return(back); 801424Sroot } 81*39130Smckusick 82*39130Smckusick char lastmsg[100]; 83*39130Smckusick 841424Sroot /* 851424Sroot * Alert the console operator, and enable the alarm clock to 861424Sroot * sleep for 2 minutes in case nobody comes to satisfy dump 871424Sroot */ 881424Sroot alarmcatch() 891424Sroot { 90*39130Smckusick if (notify == 0) { 91*39130Smckusick if (timeout == 0) 92*39130Smckusick fprintf(stderr," DUMP: %s: (\"yes\" or \"no\") ", 93*39130Smckusick attnmessage); 94*39130Smckusick else 95*39130Smckusick msgtail("\7\7"); 96*39130Smckusick } else { 97*39130Smckusick if (timeout) { 98*39130Smckusick msgtail("\n"); 99*39130Smckusick broadcast(""); /* just print last msg */ 100*39130Smckusick } 101*39130Smckusick fprintf(stderr," DUMP: %s: (\"yes\" or \"no\") ", 102*39130Smckusick attnmessage); 103*39130Smckusick } 1041424Sroot signal(SIGALRM, alarmcatch); 1051424Sroot alarm(120); 1061424Sroot timeout = 1; 1071424Sroot } 1081424Sroot /* 1091424Sroot * Here if an inquisitive operator interrupts the dump program 1101424Sroot */ 1111424Sroot interrupt() 1121424Sroot { 11321124Smckusick msg("Interrupt received.\n"); 11421124Smckusick if (query("Do you want to abort dump?")) 1151424Sroot dumpabort(); 1161424Sroot } 1171424Sroot 1181424Sroot /* 1191424Sroot * The following variables and routines manage alerting 1201424Sroot * operators to the status of dump. 1211424Sroot * This works much like wall(1) does. 1221424Sroot */ 1231424Sroot struct Group *gp; 1241424Sroot 1251424Sroot /* 1261424Sroot * Get the names from the group entry "operator" to notify. 1271424Sroot */ 1281424Sroot set_operators() 1291424Sroot { 1301424Sroot if (!notify) /*not going to notify*/ 1311424Sroot return; 1321424Sroot gp = getgrnam(OPGRENT); 1331424Sroot endgrent(); 1341424Sroot if (gp == (struct Group *)0){ 135*39130Smckusick msg("No group entry for %s.\n", 1361424Sroot OPGRENT); 1371424Sroot notify = 0; 1381424Sroot return; 1391424Sroot } 1401424Sroot } 1411424Sroot 1421424Sroot struct tm *localtime(); 1431424Sroot struct tm *localclock; 1441424Sroot 1451424Sroot /* 1461424Sroot * We fork a child to do the actual broadcasting, so 1471424Sroot * that the process control groups are not messed up 1481424Sroot */ 1491424Sroot broadcast(message) 1501424Sroot char *message; 1511424Sroot { 1521424Sroot time_t clock; 1531424Sroot FILE *f_utmp; 1541424Sroot struct utmp utmp; 1551424Sroot int nusers; 1561424Sroot char **np; 1571424Sroot int pid, s; 1581424Sroot 1591424Sroot switch (pid = fork()) { 1601424Sroot case -1: 1611424Sroot return; 1621424Sroot case 0: 1631424Sroot break; 1641424Sroot default: 1651424Sroot while (wait(&s) != pid) 1661424Sroot continue; 1671424Sroot return; 1681424Sroot } 1691424Sroot 1701424Sroot if (!notify || gp == 0) 1711925Swnj exit(0); 1721424Sroot clock = time(0); 1731424Sroot localclock = localtime(&clock); 1741424Sroot 175*39130Smckusick if((f_utmp = fopen(_PATH_UTMP, "r")) == NULL) { 176*39130Smckusick msg("Cannot open %s\n", _PATH_UTMP); 1771424Sroot return; 1781424Sroot } 1791424Sroot 1801424Sroot nusers = 0; 1811424Sroot while (!feof(f_utmp)){ 1821424Sroot if (fread(&utmp, sizeof (struct utmp), 1, f_utmp) != 1) 1831424Sroot break; 1841424Sroot if (utmp.ut_name[0] == 0) 1851424Sroot continue; 1861424Sroot nusers++; 1871424Sroot for (np = gp->gr_mem; *np; np++){ 1881424Sroot if (strncmp(*np, utmp.ut_name, sizeof(utmp.ut_name)) != 0) 1891424Sroot continue; 1901424Sroot /* 1911424Sroot * Do not send messages to operators on dialups 1921424Sroot */ 1931424Sroot if (strncmp(utmp.ut_line, DIALUP, strlen(DIALUP)) == 0) 1941424Sroot continue; 1951424Sroot #ifdef DEBUG 1961424Sroot msg("Message to %s at %s\n", 1971424Sroot utmp.ut_name, utmp.ut_line); 1981424Sroot #endif DEBUG 1991424Sroot sendmes(utmp.ut_line, message); 2001424Sroot } 2011424Sroot } 2021424Sroot fclose(f_utmp); 2031424Sroot Exit(0); /* the wait in this same routine will catch this */ 2041424Sroot /* NOTREACHED */ 2051424Sroot } 2061424Sroot 2071424Sroot sendmes(tty, message) 2085319Smckusic char *tty, *message; 2091424Sroot { 2101424Sroot char t[50], buf[BUFSIZ]; 2111424Sroot register char *cp; 212*39130Smckusick int lmsg = 1; 2131424Sroot FILE *f_tty; 2141424Sroot 215*39130Smckusick strcpy(t, _PATH_DEV); 2161424Sroot strcat(t, tty); 2171424Sroot 2181424Sroot if((f_tty = fopen(t, "w")) != NULL) { 2191424Sroot setbuf(f_tty, buf); 220*39130Smckusick fprintf(f_tty, "\n\07\07\07Message from the dump program to all operators at %d:%02d ...\r\n\n DUMP: NEEDS ATTENTION: " 2211424Sroot ,localclock->tm_hour 2221424Sroot ,localclock->tm_min); 223*39130Smckusick for (cp = lastmsg; ; cp++) { 224*39130Smckusick if (*cp == '\0') { 225*39130Smckusick if (lmsg) { 226*39130Smckusick cp = message; 227*39130Smckusick if (*cp == '\0') 228*39130Smckusick break; 229*39130Smckusick lmsg = 0; 230*39130Smckusick } else 231*39130Smckusick break; 232*39130Smckusick } 233*39130Smckusick if (*cp == '\n') 2341424Sroot putc('\r', f_tty); 235*39130Smckusick putc(*cp, f_tty); 2361424Sroot } 2371424Sroot fclose(f_tty); 2381424Sroot } 2391424Sroot } 2401424Sroot 2411424Sroot /* 2421424Sroot * print out an estimate of the amount of time left to do the dump 2431424Sroot */ 2441424Sroot 2451424Sroot time_t tschedule = 0; 2461424Sroot 2471424Sroot timeest() 2481424Sroot { 2491424Sroot time_t tnow, deltat; 2501424Sroot 2511424Sroot time (&tnow); 2521424Sroot if (tnow >= tschedule){ 2531424Sroot tschedule = tnow + 300; 2541424Sroot if (blockswritten < 500) 2551424Sroot return; 2561424Sroot deltat = tstart_writing - tnow + 2571424Sroot (((1.0*(tnow - tstart_writing))/blockswritten) * esize); 2581424Sroot msg("%3.2f%% done, finished in %d:%02d\n", 2591424Sroot (blockswritten*100.0)/esize, 2601424Sroot deltat/3600, (deltat%3600)/60); 2611424Sroot } 2621424Sroot } 2631424Sroot 2641424Sroot int blocksontape() 2651424Sroot { 2661424Sroot /* 2671424Sroot * esize: total number of blocks estimated over all reels 2681424Sroot * blockswritten: blocks actually written, over all reels 2691424Sroot * etapes: estimated number of tapes to write 2701424Sroot * 2711424Sroot * tsize: blocks can write on this reel 2721424Sroot * asize: blocks written on this reel 2731424Sroot * tapeno: number of tapes written so far 2741424Sroot */ 2751424Sroot if (tapeno == etapes) 2761424Sroot return(esize - (etapes - 1)*tsize); 2771424Sroot return(tsize); 2781424Sroot } 2791424Sroot 2801424Sroot /* VARARGS1 */ 2811424Sroot /* ARGSUSED */ 2821424Sroot msg(fmt, a1, a2, a3, a4, a5) 2831424Sroot char *fmt; 2845319Smckusic int a1, a2, a3, a4, a5; 2851424Sroot { 2861424Sroot fprintf(stderr," DUMP: "); 2871424Sroot #ifdef TDEBUG 2881424Sroot fprintf(stderr,"pid=%d ", getpid()); 2891424Sroot #endif 2901424Sroot fprintf(stderr, fmt, a1, a2, a3, a4, a5); 2911424Sroot fflush(stdout); 2921424Sroot fflush(stderr); 293*39130Smckusick sprintf(lastmsg, fmt, a1, a2, a3, a4, a5); 2941424Sroot } 2951424Sroot 2961424Sroot /* VARARGS1 */ 2971424Sroot /* ARGSUSED */ 2981424Sroot msgtail(fmt, a1, a2, a3, a4, a5) 2991424Sroot char *fmt; 3005319Smckusic int a1, a2, a3, a4, a5; 3011424Sroot { 3021424Sroot fprintf(stderr, fmt, a1, a2, a3, a4, a5); 3031424Sroot } 3041424Sroot /* 3051424Sroot * Tell the operator what has to be done; 3061424Sroot * we don't actually do it 3071424Sroot */ 3081424Sroot 30913047Ssam struct fstab * 31013047Ssam allocfsent(fs) 31113047Ssam register struct fstab *fs; 31213047Ssam { 31313047Ssam register struct fstab *new; 31413047Ssam register char *cp; 31513047Ssam char *malloc(); 31613047Ssam 31713047Ssam new = (struct fstab *)malloc(sizeof (*fs)); 31813047Ssam cp = malloc(strlen(fs->fs_file) + 1); 31913047Ssam strcpy(cp, fs->fs_file); 32013047Ssam new->fs_file = cp; 32113047Ssam cp = malloc(strlen(fs->fs_type) + 1); 32213047Ssam strcpy(cp, fs->fs_type); 32313047Ssam new->fs_type = cp; 32413047Ssam cp = malloc(strlen(fs->fs_spec) + 1); 32513047Ssam strcpy(cp, fs->fs_spec); 32613047Ssam new->fs_spec = cp; 32713047Ssam new->fs_passno = fs->fs_passno; 32813047Ssam new->fs_freq = fs->fs_freq; 32913047Ssam return (new); 33013047Ssam } 33113047Ssam 33213047Ssam struct pfstab { 33313047Ssam struct pfstab *pf_next; 33413047Ssam struct fstab *pf_fstab; 33513047Ssam }; 33613047Ssam 33713047Ssam static struct pfstab *table = NULL; 33813047Ssam 3391424Sroot getfstab() 3401424Sroot { 34113047Ssam register struct fstab *fs; 34213047Ssam register struct pfstab *pf; 3431424Sroot 3441428Sroot if (setfsent() == 0) { 345*39130Smckusick msg("Can't open %s for dump table information.\n", _PATH_FSTAB); 34613047Ssam return; 3471424Sroot } 34813047Ssam while (fs = getfsent()) { 34913047Ssam if (strcmp(fs->fs_type, FSTAB_RW) && 35013047Ssam strcmp(fs->fs_type, FSTAB_RO) && 35113047Ssam strcmp(fs->fs_type, FSTAB_RQ)) 35213047Ssam continue; 35313047Ssam fs = allocfsent(fs); 35413047Ssam pf = (struct pfstab *)malloc(sizeof (*pf)); 35513047Ssam pf->pf_fstab = fs; 35613047Ssam pf->pf_next = table; 35713047Ssam table = pf; 35813047Ssam } 35913047Ssam endfsent(); 3601424Sroot } 3611424Sroot 3621424Sroot /* 36313047Ssam * Search in the fstab for a file name. 36413047Ssam * This file name can be either the special or the path file name. 3651424Sroot * 36613047Ssam * The entries in the fstab are the BLOCK special names, not the 36713047Ssam * character special names. 36813047Ssam * The caller of fstabsearch assures that the character device 36913047Ssam * is dumped (that is much faster) 3701424Sroot * 37113047Ssam * The file name can omit the leading '/'. 3721424Sroot */ 37313047Ssam struct fstab * 37413047Ssam fstabsearch(key) 37513047Ssam char *key; 3761424Sroot { 37713047Ssam register struct pfstab *pf; 37813047Ssam register struct fstab *fs; 37913047Ssam char *rawname(); 3801424Sroot 38113047Ssam if (table == NULL) 38213047Ssam return ((struct fstab *)0); 38313047Ssam for (pf = table; pf; pf = pf->pf_next) { 38413047Ssam fs = pf->pf_fstab; 38513197Sroot if (strcmp(fs->fs_file, key) == 0) 38613047Ssam return (fs); 38713197Sroot if (strcmp(fs->fs_spec, key) == 0) 38813047Ssam return (fs); 38913197Sroot if (strcmp(rawname(fs->fs_spec), key) == 0) 39013047Ssam return (fs); 3911424Sroot if (key[0] != '/'){ 39213047Ssam if (*fs->fs_spec == '/' && 39313197Sroot strcmp(fs->fs_spec + 1, key) == 0) 39413047Ssam return (fs); 39513047Ssam if (*fs->fs_file == '/' && 39613197Sroot strcmp(fs->fs_file + 1, key) == 0) 39713047Ssam return (fs); 3981424Sroot } 3991424Sroot } 40013047Ssam return (0); 4011424Sroot } 4021424Sroot 4031424Sroot /* 4041424Sroot * Tell the operator what to do 4051424Sroot */ 4061463Sroot lastdump(arg) 4071463Sroot char arg; /* w ==> just what to do; W ==> most recent dumps */ 4081424Sroot { 4091424Sroot char *lastname; 4101424Sroot char *date; 4111424Sroot register int i; 4121424Sroot time_t tnow; 4131424Sroot register struct fstab *dt; 4141424Sroot int dumpme; 4151424Sroot register struct idates *itwalk; 4161424Sroot 4171424Sroot int idatesort(); 4181424Sroot 4191424Sroot time(&tnow); 4201424Sroot getfstab(); /* /etc/fstab input */ 4211424Sroot inititimes(); /* /etc/dumpdates input */ 4221424Sroot qsort(idatev, nidates, sizeof(struct idates *), idatesort); 4231424Sroot 4241463Sroot if (arg == 'w') 4251463Sroot fprintf(stdout, "Dump these file systems:\n"); 4261463Sroot else 4271463Sroot fprintf(stdout, "Last dump(s) done (Dump '>' file systems):\n"); 4281424Sroot lastname = "??"; 4291424Sroot ITITERATE(i, itwalk){ 4301424Sroot if (strncmp(lastname, itwalk->id_name, sizeof(itwalk->id_name)) == 0) 4311424Sroot continue; 4321424Sroot date = (char *)ctime(&itwalk->id_ddate); 4331424Sroot date[16] = '\0'; /* blast away seconds and year */ 4341424Sroot lastname = itwalk->id_name; 4351424Sroot dt = fstabsearch(itwalk->id_name); 4361424Sroot dumpme = ( (dt != 0) 4371424Sroot && (dt->fs_freq != 0) 4381424Sroot && (itwalk->id_ddate < tnow - (dt->fs_freq*DAY))); 4391463Sroot if ( (arg != 'w') || dumpme) 4401463Sroot fprintf(stdout,"%c %8s\t(%6s) Last dump: Level %c, Date %s\n", 4411463Sroot dumpme && (arg != 'w') ? '>' : ' ', 4421424Sroot itwalk->id_name, 44310910Ssam dt ? dt->fs_file : "", 4441424Sroot itwalk->id_incno, 4451424Sroot date 4461424Sroot ); 4471424Sroot } 4481424Sroot } 4491424Sroot 4501424Sroot int idatesort(p1, p2) 4511424Sroot struct idates **p1, **p2; 4521424Sroot { 4531424Sroot int diff; 4541424Sroot 4551424Sroot diff = strncmp((*p1)->id_name, (*p2)->id_name, sizeof((*p1)->id_name)); 4561424Sroot if (diff == 0) 4571424Sroot return ((*p2)->id_ddate - (*p1)->id_ddate); 4581424Sroot else 4591424Sroot return (diff); 4601424Sroot } 4611424Sroot 4621424Sroot int max(a,b) 4635319Smckusic int a, b; 4641424Sroot { 4651424Sroot return(a>b?a:b); 4661424Sroot } 4671424Sroot int min(a,b) 4685319Smckusic int a, b; 4691424Sroot { 4701424Sroot return(a<b?a:b); 4711424Sroot } 472