xref: /csrg-svn/sbin/dump/optr.c (revision 5319)
1*5319Smckusic static	char *sccsid = "@(#)optr.c	1.5 (Berkeley) 01/04/82";
2*5319Smckusic 
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)
188*5319Smckusic 	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;
258*5319Smckusic 	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;
273*5319Smckusic 	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,
3851424Sroot 			dt ? dt->fs_file : 0,
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)
405*5319Smckusic 	int a, b;
4061424Sroot {
4071424Sroot 	return(a>b?a:b);
4081424Sroot }
4091424Sroot int min(a,b)
410*5319Smckusic 	int a, b;
4111424Sroot {
4121424Sroot 	return(a<b?a:b);
4131424Sroot }
414