1*22029Sdist /*
2*22029Sdist * Copyright (c) 1980 Regents of the University of California.
3*22029Sdist * All rights reserved. The Berkeley software License Agreement
4*22029Sdist * specifies the terms and conditions for redistribution.
5*22029Sdist */
6*22029Sdist
7*22029Sdist #ifndef lint
8*22029Sdist static char sccsid[] = "@(#)dumpoptr.c 5.1 (Berkeley) 06/05/85";
9*22029Sdist #endif not lint
10*22029Sdist
111424Sroot #include "dump.h"
121424Sroot
131424Sroot /*
141424Sroot * This is from /usr/include/grp.h
151424Sroot * That defined struct group, which conflicts
161424Sroot * with the struct group defined in param.h
171424Sroot */
181424Sroot struct Group { /* see getgrent(3) */
191424Sroot char *gr_name;
201424Sroot char *gr_passwd;
211424Sroot int gr_gid;
221424Sroot char **gr_mem;
231424Sroot };
241424Sroot struct Group *getgrnam();
251424Sroot /*
261424Sroot * Query the operator; This fascist piece of code requires
271424Sroot * an exact response.
281424Sroot * It is intended to protect dump aborting by inquisitive
291424Sroot * people banging on the console terminal to see what is
301424Sroot * happening which might cause dump to croak, destroying
311424Sroot * a large number of hours of work.
321424Sroot *
331424Sroot * Every 2 minutes we reprint the message, alerting others
341424Sroot * that dump needs attention.
351424Sroot */
361424Sroot int timeout;
371424Sroot char *attnmessage; /* attemtion message */
query(question)381424Sroot query(question)
391424Sroot char *question;
401424Sroot {
411424Sroot char replybuffer[64];
421424Sroot int back;
431424Sroot FILE *mytty;
441424Sroot
451424Sroot if ( (mytty = fopen("/dev/tty", "r")) == NULL){
461424Sroot msg("fopen on /dev/tty fails\n");
471424Sroot abort();
481424Sroot }
491424Sroot attnmessage = question;
501424Sroot timeout = 0;
511424Sroot alarmcatch();
521424Sroot for(;;){
531424Sroot if ( fgets(replybuffer, 63, mytty) == NULL){
541424Sroot if (ferror(mytty)){
551424Sroot clearerr(mytty);
561424Sroot continue;
571424Sroot }
581424Sroot } else if ( (strcmp(replybuffer, "yes\n") == 0) ||
591424Sroot (strcmp(replybuffer, "Yes\n") == 0)){
601424Sroot back = 1;
611424Sroot goto done;
621424Sroot } else if ( (strcmp(replybuffer, "no\n") == 0) ||
631424Sroot (strcmp(replybuffer, "No\n") == 0)){
641424Sroot back = 0;
651424Sroot goto done;
661424Sroot } else {
671424Sroot msg("\"Yes\" or \"No\" ONLY!\n");
681424Sroot alarmcatch();
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 }
811424Sroot /*
821424Sroot * Alert the console operator, and enable the alarm clock to
831424Sroot * sleep for 2 minutes in case nobody comes to satisfy dump
841424Sroot */
alarmcatch()851424Sroot alarmcatch()
861424Sroot {
871424Sroot if (timeout)
881424Sroot msgtail("\n");
891424Sroot msg("NEEDS ATTENTION: %s: (\"yes\" or \"no\") ",
901424Sroot attnmessage);
911424Sroot signal(SIGALRM, alarmcatch);
921424Sroot alarm(120);
931424Sroot timeout = 1;
941424Sroot }
951424Sroot /*
961424Sroot * Here if an inquisitive operator interrupts the dump program
971424Sroot */
interrupt()981424Sroot interrupt()
991424Sroot {
1001424Sroot msg("Interrupt received. Do >>>YOU<<< know what are you doing?\n");
1011424Sroot if (query("Do you really want to abort dump?"))
1021424Sroot dumpabort();
1031424Sroot signal(SIGINT, interrupt);
1041424Sroot }
1051424Sroot
1061424Sroot /*
1071424Sroot * The following variables and routines manage alerting
1081424Sroot * operators to the status of dump.
1091424Sroot * This works much like wall(1) does.
1101424Sroot */
1111424Sroot struct Group *gp;
1121424Sroot
1131424Sroot /*
1141424Sroot * Get the names from the group entry "operator" to notify.
1151424Sroot */
set_operators()1161424Sroot set_operators()
1171424Sroot {
1181424Sroot if (!notify) /*not going to notify*/
1191424Sroot return;
1201424Sroot gp = getgrnam(OPGRENT);
1211424Sroot endgrent();
1221424Sroot if (gp == (struct Group *)0){
1231424Sroot msg("No entry in /etc/group for %s.\n",
1241424Sroot OPGRENT);
1251424Sroot notify = 0;
1261424Sroot return;
1271424Sroot }
1281424Sroot }
1291424Sroot
1301424Sroot struct tm *localtime();
1311424Sroot struct tm *localclock;
1321424Sroot
1331424Sroot /*
1341424Sroot * We fork a child to do the actual broadcasting, so
1351424Sroot * that the process control groups are not messed up
1361424Sroot */
broadcast(message)1371424Sroot broadcast(message)
1381424Sroot char *message;
1391424Sroot {
1401424Sroot time_t clock;
1411424Sroot FILE *f_utmp;
1421424Sroot struct utmp utmp;
1431424Sroot int nusers;
1441424Sroot char **np;
1451424Sroot int pid, s;
1461424Sroot
1471424Sroot switch (pid = fork()) {
1481424Sroot case -1:
1491424Sroot return;
1501424Sroot case 0:
1511424Sroot break;
1521424Sroot default:
1531424Sroot while (wait(&s) != pid)
1541424Sroot continue;
1551424Sroot return;
1561424Sroot }
1571424Sroot
1581424Sroot if (!notify || gp == 0)
1591925Swnj exit(0);
1601424Sroot clock = time(0);
1611424Sroot localclock = localtime(&clock);
1621424Sroot
1631424Sroot if((f_utmp = fopen("/etc/utmp", "r")) == NULL) {
1641424Sroot msg("Cannot open /etc/utmp\n");
1651424Sroot return;
1661424Sroot }
1671424Sroot
1681424Sroot nusers = 0;
1691424Sroot while (!feof(f_utmp)){
1701424Sroot if (fread(&utmp, sizeof (struct utmp), 1, f_utmp) != 1)
1711424Sroot break;
1721424Sroot if (utmp.ut_name[0] == 0)
1731424Sroot continue;
1741424Sroot nusers++;
1751424Sroot for (np = gp->gr_mem; *np; np++){
1761424Sroot if (strncmp(*np, utmp.ut_name, sizeof(utmp.ut_name)) != 0)
1771424Sroot continue;
1781424Sroot /*
1791424Sroot * Do not send messages to operators on dialups
1801424Sroot */
1811424Sroot if (strncmp(utmp.ut_line, DIALUP, strlen(DIALUP)) == 0)
1821424Sroot continue;
1831424Sroot #ifdef DEBUG
1841424Sroot msg("Message to %s at %s\n",
1851424Sroot utmp.ut_name, utmp.ut_line);
1861424Sroot #endif DEBUG
1871424Sroot sendmes(utmp.ut_line, message);
1881424Sroot }
1891424Sroot }
1901424Sroot fclose(f_utmp);
1911424Sroot Exit(0); /* the wait in this same routine will catch this */
1921424Sroot /* NOTREACHED */
1931424Sroot }
1941424Sroot
sendmes(tty,message)1951424Sroot sendmes(tty, message)
1961424Sroot char *tty, *message;
1971424Sroot {
1981424Sroot char t[50], buf[BUFSIZ];
1991424Sroot register char *cp;
2001424Sroot register int c, ch;
2011424Sroot int msize;
2021424Sroot FILE *f_tty;
2031424Sroot
2041424Sroot msize = strlen(message);
2051424Sroot strcpy(t, "/dev/");
2061424Sroot strcat(t, tty);
2071424Sroot
2081424Sroot if((f_tty = fopen(t, "w")) != NULL) {
2091424Sroot setbuf(f_tty, buf);
2101424Sroot fprintf(f_tty, "\nMessage from the dump program to all operators at %d:%02d ...\r\n\n"
2111424Sroot ,localclock->tm_hour
2121424Sroot ,localclock->tm_min);
2131424Sroot for (cp = message, c = msize; c-- > 0; cp++) {
2141424Sroot ch = *cp;
2151424Sroot if (ch == '\n')
2161424Sroot putc('\r', f_tty);
2171424Sroot putc(ch, f_tty);
2181424Sroot }
2191424Sroot fclose(f_tty);
2201424Sroot }
2211424Sroot }
2221424Sroot
2231424Sroot /*
2241424Sroot * print out an estimate of the amount of time left to do the dump
2251424Sroot */
2261424Sroot
2271424Sroot time_t tschedule = 0;
2281424Sroot
timeest()2291424Sroot timeest()
2301424Sroot {
2311424Sroot time_t tnow, deltat;
2321424Sroot
2331424Sroot time (&tnow);
2341424Sroot if (tnow >= tschedule){
2351424Sroot tschedule = tnow + 300;
2361424Sroot if (blockswritten < 500)
2371424Sroot return;
2381424Sroot deltat = tstart_writing - tnow +
2391424Sroot (((1.0*(tnow - tstart_writing))/blockswritten) * esize);
2401424Sroot msg("%3.2f%% done, finished in %d:%02d\n",
2411424Sroot (blockswritten*100.0)/esize,
2421424Sroot deltat/3600, (deltat%3600)/60);
2431424Sroot }
2441424Sroot }
2451424Sroot
blocksontape()2461424Sroot int blocksontape()
2471424Sroot {
2481424Sroot /*
2491424Sroot * esize: total number of blocks estimated over all reels
2501424Sroot * blockswritten: blocks actually written, over all reels
2511424Sroot * etapes: estimated number of tapes to write
2521424Sroot *
2531424Sroot * tsize: blocks can write on this reel
2541424Sroot * asize: blocks written on this reel
2551424Sroot * tapeno: number of tapes written so far
2561424Sroot */
2571424Sroot if (tapeno == etapes)
2581424Sroot return(esize - (etapes - 1)*tsize);
2591424Sroot return(tsize);
2601424Sroot }
2611424Sroot
2621424Sroot /* VARARGS1 */
2631424Sroot /* ARGSUSED */
msg(fmt,a1,a2,a3,a4,a5)2641424Sroot msg(fmt, a1, a2, a3, a4, a5)
2651424Sroot char *fmt;
2661424Sroot {
2671424Sroot fprintf(stderr," DUMP: ");
2681424Sroot #ifdef TDEBUG
2691424Sroot fprintf(stderr,"pid=%d ", getpid());
2701424Sroot #endif
2711424Sroot fprintf(stderr, fmt, a1, a2, a3, a4, a5);
2721424Sroot fflush(stdout);
2731424Sroot fflush(stderr);
2741424Sroot }
2751424Sroot
2761424Sroot /* VARARGS1 */
2771424Sroot /* ARGSUSED */
msgtail(fmt,a1,a2,a3,a4,a5)2781424Sroot msgtail(fmt, a1, a2, a3, a4, a5)
2791424Sroot char *fmt;
2801424Sroot {
2811424Sroot fprintf(stderr, fmt, a1, a2, a3, a4, a5);
2821424Sroot }
2831424Sroot /*
2841424Sroot * Tell the operator what has to be done;
2851424Sroot * we don't actually do it
2861424Sroot */
2871424Sroot
28813048Ssam struct fstab *
allocfsent(fs)28913048Ssam allocfsent(fs)
29013048Ssam register struct fstab *fs;
29113048Ssam {
29213048Ssam register struct fstab *new;
29313048Ssam register char *cp;
29413048Ssam char *malloc();
29513048Ssam
29613048Ssam new = (struct fstab *)malloc(sizeof (*fs));
29713048Ssam cp = malloc(strlen(fs->fs_file) + 1);
29813048Ssam strcpy(cp, fs->fs_file);
29913048Ssam new->fs_file = cp;
30013048Ssam cp = malloc(strlen(fs->fs_type) + 1);
30113048Ssam strcpy(cp, fs->fs_type);
30213048Ssam new->fs_type = cp;
30313048Ssam cp = malloc(strlen(fs->fs_spec) + 1);
30413048Ssam strcpy(cp, fs->fs_spec);
30513048Ssam new->fs_spec = cp;
30613048Ssam new->fs_passno = fs->fs_passno;
30713048Ssam new->fs_freq = fs->fs_freq;
30813048Ssam return (new);
30913048Ssam }
31013048Ssam
31113048Ssam struct pfstab {
31213048Ssam struct pfstab *pf_next;
31313048Ssam struct fstab *pf_fstab;
31413048Ssam };
31513048Ssam
31613048Ssam static struct pfstab *table = NULL;
31713048Ssam
getfstab()3181424Sroot getfstab()
3191424Sroot {
32013048Ssam register struct fstab *fs;
32113048Ssam register struct pfstab *pf;
3221424Sroot
3231428Sroot if (setfsent() == 0) {
3241424Sroot msg("Can't open %s for dump table information.\n", FSTAB);
32513048Ssam return;
3261424Sroot }
32713048Ssam while (fs = getfsent()) {
32813048Ssam if (strcmp(fs->fs_type, FSTAB_RW) &&
32913048Ssam strcmp(fs->fs_type, FSTAB_RO) &&
33013048Ssam strcmp(fs->fs_type, FSTAB_RQ))
33113048Ssam continue;
33213048Ssam fs = allocfsent(fs);
33313048Ssam pf = (struct pfstab *)malloc(sizeof (*pf));
33413048Ssam pf->pf_fstab = fs;
33513048Ssam pf->pf_next = table;
33613048Ssam table = pf;
33713048Ssam }
33813048Ssam endfsent();
3391424Sroot }
3401424Sroot
3411424Sroot /*
34213048Ssam * Search in the fstab for a file name.
34313048Ssam * This file name can be either the special or the path file name.
3441424Sroot *
34513048Ssam * The entries in the fstab are the BLOCK special names, not the
34613048Ssam * character special names.
34713048Ssam * The caller of fstabsearch assures that the character device
34813048Ssam * is dumped (that is much faster)
3491424Sroot *
35013048Ssam * The file name can omit the leading '/'.
3511424Sroot */
35213048Ssam struct fstab *
fstabsearch(key)35313048Ssam fstabsearch(key)
35413048Ssam char *key;
3551424Sroot {
35613048Ssam register struct pfstab *pf;
35713048Ssam register struct fstab *fs;
35813048Ssam char *rawname();
3591424Sroot
36013048Ssam if (table == NULL)
36113048Ssam return ((struct fstab *)0);
36213048Ssam for (pf = table; pf; pf = pf->pf_next) {
36313048Ssam fs = pf->pf_fstab;
36413205Ssam if (strcmp(fs->fs_file, key) == 0)
36513048Ssam return (fs);
36613205Ssam if (strcmp(fs->fs_spec, key) == 0)
36713048Ssam return (fs);
36813205Ssam if (strcmp(rawname(fs->fs_spec), key) == 0)
36913048Ssam return (fs);
3701424Sroot if (key[0] != '/'){
37113048Ssam if (*fs->fs_spec == '/' &&
37213205Ssam strcmp(fs->fs_spec + 1, key) == 0)
37313048Ssam return (fs);
37413048Ssam if (*fs->fs_file == '/' &&
37513205Ssam strcmp(fs->fs_file + 1, key) == 0)
37613048Ssam return (fs);
3771424Sroot }
3781424Sroot }
37913048Ssam return (0);
3801424Sroot }
3811424Sroot
3821424Sroot /*
3831424Sroot * Tell the operator what to do
3841424Sroot */
lastdump(arg)3851463Sroot lastdump(arg)
3861463Sroot char arg; /* w ==> just what to do; W ==> most recent dumps */
3871424Sroot {
3881424Sroot char *lastname;
3891424Sroot char *date;
3901424Sroot register int i;
3911424Sroot time_t tnow;
3921424Sroot register struct fstab *dt;
3931424Sroot int dumpme;
3941424Sroot register struct idates *itwalk;
3951424Sroot
3961424Sroot int idatesort();
3971424Sroot
3981424Sroot time(&tnow);
3991424Sroot getfstab(); /* /etc/fstab input */
4001424Sroot inititimes(); /* /etc/dumpdates input */
4011424Sroot qsort(idatev, nidates, sizeof(struct idates *), idatesort);
4021424Sroot
4031463Sroot if (arg == 'w')
4041463Sroot fprintf(stdout, "Dump these file systems:\n");
4051463Sroot else
4061463Sroot fprintf(stdout, "Last dump(s) done (Dump '>' file systems):\n");
4071424Sroot lastname = "??";
4081424Sroot ITITERATE(i, itwalk){
4091424Sroot if (strncmp(lastname, itwalk->id_name, sizeof(itwalk->id_name)) == 0)
4101424Sroot continue;
4111424Sroot date = (char *)ctime(&itwalk->id_ddate);
4121424Sroot date[16] = '\0'; /* blast away seconds and year */
4131424Sroot lastname = itwalk->id_name;
4141424Sroot dt = fstabsearch(itwalk->id_name);
4151424Sroot dumpme = ( (dt != 0)
4161424Sroot && (dt->fs_freq != 0)
4171424Sroot && (itwalk->id_ddate < tnow - (dt->fs_freq*DAY)));
4181463Sroot if ( (arg != 'w') || dumpme)
4191463Sroot fprintf(stdout,"%c %8s\t(%6s) Last dump: Level %c, Date %s\n",
4201463Sroot dumpme && (arg != 'w') ? '>' : ' ',
4211424Sroot itwalk->id_name,
4221424Sroot dt ? dt->fs_file : 0,
4231424Sroot itwalk->id_incno,
4241424Sroot date
4251424Sroot );
4261424Sroot }
4271424Sroot }
4281424Sroot
idatesort(p1,p2)4291424Sroot int idatesort(p1, p2)
4301424Sroot struct idates **p1, **p2;
4311424Sroot {
4321424Sroot int diff;
4331424Sroot
4341424Sroot diff = strncmp((*p1)->id_name, (*p2)->id_name, sizeof((*p1)->id_name));
4351424Sroot if (diff == 0)
4361424Sroot return ((*p2)->id_ddate - (*p1)->id_ddate);
4371424Sroot else
4381424Sroot return (diff);
4391424Sroot }
4401424Sroot
max(a,b)4411424Sroot int max(a,b)
4421424Sroot {
4431424Sroot return(a>b?a:b);
4441424Sroot }
min(a,b)4451424Sroot int min(a,b)
4461424Sroot {
4471424Sroot return(a<b?a:b);
4481424Sroot }
449