xref: /csrg-svn/sbin/dump/optr.c (revision 1424)
1*1424Sroot static	char *sccsid = "@(#)optr.c	1.1 (Berkeley) 10/13/80";
2*1424Sroot #include "dump.h"
3*1424Sroot 
4*1424Sroot /*
5*1424Sroot  *	This is from /usr/include/grp.h
6*1424Sroot  *	That defined struct group, which conflicts
7*1424Sroot  *	with the struct group defined in param.h
8*1424Sroot  */
9*1424Sroot struct	Group { /* see getgrent(3) */
10*1424Sroot 	char	*gr_name;
11*1424Sroot 	char	*gr_passwd;
12*1424Sroot 	int	gr_gid;
13*1424Sroot 	char	**gr_mem;
14*1424Sroot };
15*1424Sroot struct	Group *getgrnam();
16*1424Sroot /*
17*1424Sroot  *	Query the operator; This fascist piece of code requires
18*1424Sroot  *	an exact response.
19*1424Sroot  *	It is intended to protect dump aborting by inquisitive
20*1424Sroot  *	people banging on the console terminal to see what is
21*1424Sroot  *	happening which might cause dump to croak, destroying
22*1424Sroot  *	a large number of hours of work.
23*1424Sroot  *
24*1424Sroot  *	Every 2 minutes we reprint the message, alerting others
25*1424Sroot  *	that dump needs attention.
26*1424Sroot  */
27*1424Sroot int	timeout;
28*1424Sroot char	*attnmessage;		/* attemtion message */
29*1424Sroot query(question)
30*1424Sroot 	char	*question;
31*1424Sroot {
32*1424Sroot 	char	replybuffer[64];
33*1424Sroot 	int	back;
34*1424Sroot 	FILE	*mytty;
35*1424Sroot 
36*1424Sroot 	if ( (mytty = fopen("/dev/tty", "r")) == NULL){
37*1424Sroot 		msg("fopen on /dev/tty fails\n");
38*1424Sroot 		abort();
39*1424Sroot 	}
40*1424Sroot 	attnmessage = question;
41*1424Sroot 	timeout = 0;
42*1424Sroot 	alarmcatch();
43*1424Sroot 	for(;;){
44*1424Sroot 		if ( fgets(replybuffer, 63, mytty) == NULL){
45*1424Sroot 			if (ferror(mytty)){
46*1424Sroot 				clearerr(mytty);
47*1424Sroot 				continue;
48*1424Sroot 			}
49*1424Sroot 		} else if ( (strcmp(replybuffer, "yes\n") == 0) ||
50*1424Sroot 			    (strcmp(replybuffer, "Yes\n") == 0)){
51*1424Sroot 				back = 1;
52*1424Sroot 				goto done;
53*1424Sroot 		} else if ( (strcmp(replybuffer, "no\n") == 0) ||
54*1424Sroot 			    (strcmp(replybuffer, "No\n") == 0)){
55*1424Sroot 				back = 0;
56*1424Sroot 				goto done;
57*1424Sroot 		} else {
58*1424Sroot 			msg("\"Yes\" or \"No\" ONLY!\n");
59*1424Sroot 			alarmcatch();
60*1424Sroot 		}
61*1424Sroot 	}
62*1424Sroot     done:
63*1424Sroot 	/*
64*1424Sroot 	 *	Turn off the alarm, and reset the signal to trap out..
65*1424Sroot 	 */
66*1424Sroot 	alarm(0);
67*1424Sroot 	if (signal(SIGALRM, sigalrm) == SIG_IGN)
68*1424Sroot 		signal(SIGALRM, SIG_IGN);
69*1424Sroot 	fclose(mytty);
70*1424Sroot 	return(back);
71*1424Sroot }
72*1424Sroot /*
73*1424Sroot  *	Alert the console operator, and enable the alarm clock to
74*1424Sroot  *	sleep for 2 minutes in case nobody comes to satisfy dump
75*1424Sroot  */
76*1424Sroot alarmcatch()
77*1424Sroot {
78*1424Sroot 	if (timeout)
79*1424Sroot 		msgtail("\n");
80*1424Sroot 	msg("NEEDS ATTENTION: %s: (\"yes\" or \"no\") ",
81*1424Sroot 		attnmessage);
82*1424Sroot 	signal(SIGALRM, alarmcatch);
83*1424Sroot 	alarm(120);
84*1424Sroot 	timeout = 1;
85*1424Sroot }
86*1424Sroot /*
87*1424Sroot  *	Here if an inquisitive operator interrupts the dump program
88*1424Sroot  */
89*1424Sroot interrupt()
90*1424Sroot {
91*1424Sroot 	msg("Interrupt received. Do >>>YOU<<< know what are you doing?\n");
92*1424Sroot 	if (query("Do you really want to abort dump?"))
93*1424Sroot 		dumpabort();
94*1424Sroot 	signal(SIGINT, interrupt);
95*1424Sroot }
96*1424Sroot 
97*1424Sroot /*
98*1424Sroot  *	The following variables and routines manage alerting
99*1424Sroot  *	operators to the status of dump.
100*1424Sroot  *	This works much like wall(1) does.
101*1424Sroot  */
102*1424Sroot struct	Group *gp;
103*1424Sroot 
104*1424Sroot /*
105*1424Sroot  *	Get the names from the group entry "operator" to notify.
106*1424Sroot  */
107*1424Sroot set_operators()
108*1424Sroot {
109*1424Sroot 	if (!notify)		/*not going to notify*/
110*1424Sroot 		return;
111*1424Sroot 	gp = getgrnam(OPGRENT);
112*1424Sroot 	endgrent();
113*1424Sroot 	if (gp == (struct Group *)0){
114*1424Sroot 		msg("No entry in /etc/group for %s.\n",
115*1424Sroot 			OPGRENT);
116*1424Sroot 		notify = 0;
117*1424Sroot 		return;
118*1424Sroot 	}
119*1424Sroot }
120*1424Sroot 
121*1424Sroot struct tm *localtime();
122*1424Sroot struct tm *localclock;
123*1424Sroot 
124*1424Sroot /*
125*1424Sroot  *	We fork a child to do the actual broadcasting, so
126*1424Sroot  *	that the process control groups are not messed up
127*1424Sroot  */
128*1424Sroot broadcast(message)
129*1424Sroot 	char	*message;
130*1424Sroot {
131*1424Sroot 	time_t		clock;
132*1424Sroot 	FILE	*f_utmp;
133*1424Sroot 	struct	utmp	utmp;
134*1424Sroot 	int	nusers;
135*1424Sroot 	char	**np;
136*1424Sroot 	int	pid, s;
137*1424Sroot 
138*1424Sroot 	switch (pid = fork()) {
139*1424Sroot 	case -1:
140*1424Sroot 		return;
141*1424Sroot 	case 0:
142*1424Sroot 		break;
143*1424Sroot 	default:
144*1424Sroot 		while (wait(&s) != pid)
145*1424Sroot 			continue;
146*1424Sroot 		return;
147*1424Sroot 	}
148*1424Sroot 
149*1424Sroot 	if (!notify || gp == 0)
150*1424Sroot 		return;
151*1424Sroot 	clock = time(0);
152*1424Sroot 	localclock = localtime(&clock);
153*1424Sroot 
154*1424Sroot 	if((f_utmp = fopen("/etc/utmp", "r")) == NULL) {
155*1424Sroot 		msg("Cannot open /etc/utmp\n");
156*1424Sroot 		return;
157*1424Sroot 	}
158*1424Sroot 
159*1424Sroot 	nusers = 0;
160*1424Sroot 	while (!feof(f_utmp)){
161*1424Sroot 		if (fread(&utmp, sizeof (struct utmp), 1, f_utmp) != 1)
162*1424Sroot 			break;
163*1424Sroot 		if (utmp.ut_name[0] == 0)
164*1424Sroot 			continue;
165*1424Sroot 		nusers++;
166*1424Sroot 		for (np = gp->gr_mem; *np; np++){
167*1424Sroot 			if (strncmp(*np, utmp.ut_name, sizeof(utmp.ut_name)) != 0)
168*1424Sroot 				continue;
169*1424Sroot 			/*
170*1424Sroot 			 *	Do not send messages to operators on dialups
171*1424Sroot 			 */
172*1424Sroot 			if (strncmp(utmp.ut_line, DIALUP, strlen(DIALUP)) == 0)
173*1424Sroot 				continue;
174*1424Sroot #ifdef DEBUG
175*1424Sroot 			msg("Message to %s at %s\n",
176*1424Sroot 				utmp.ut_name, utmp.ut_line);
177*1424Sroot #endif DEBUG
178*1424Sroot 			sendmes(utmp.ut_line, message);
179*1424Sroot 		}
180*1424Sroot 	}
181*1424Sroot 	fclose(f_utmp);
182*1424Sroot 	Exit(0);	/* the wait in this same routine will catch this */
183*1424Sroot 	/* NOTREACHED */
184*1424Sroot }
185*1424Sroot 
186*1424Sroot sendmes(tty, message)
187*1424Sroot char *tty, *message;
188*1424Sroot {
189*1424Sroot 	char t[50], buf[BUFSIZ];
190*1424Sroot 	register char *cp;
191*1424Sroot 	register int c, ch;
192*1424Sroot 	int	msize;
193*1424Sroot 	FILE *f_tty;
194*1424Sroot 
195*1424Sroot 	msize = strlen(message);
196*1424Sroot 	strcpy(t, "/dev/");
197*1424Sroot 	strcat(t, tty);
198*1424Sroot 
199*1424Sroot 	if((f_tty = fopen(t, "w")) != NULL) {
200*1424Sroot 		setbuf(f_tty, buf);
201*1424Sroot 		fprintf(f_tty, "\nMessage from the dump program to all operators at %d:%02d ...\r\n\n"
202*1424Sroot 		       ,localclock->tm_hour
203*1424Sroot 		       ,localclock->tm_min);
204*1424Sroot 		for (cp = message, c = msize; c-- > 0; cp++) {
205*1424Sroot 			ch = *cp;
206*1424Sroot 			if (ch == '\n')
207*1424Sroot 				putc('\r', f_tty);
208*1424Sroot 			putc(ch, f_tty);
209*1424Sroot 		}
210*1424Sroot 		fclose(f_tty);
211*1424Sroot 	}
212*1424Sroot }
213*1424Sroot 
214*1424Sroot /*
215*1424Sroot  *	print out an estimate of the amount of time left to do the dump
216*1424Sroot  */
217*1424Sroot 
218*1424Sroot time_t	tschedule = 0;
219*1424Sroot 
220*1424Sroot timeest()
221*1424Sroot {
222*1424Sroot 	time_t	tnow, deltat;
223*1424Sroot 
224*1424Sroot 	time (&tnow);
225*1424Sroot 	if (tnow >= tschedule){
226*1424Sroot 		tschedule = tnow + 300;
227*1424Sroot 		if (blockswritten < 500)
228*1424Sroot 			return;
229*1424Sroot 		deltat = tstart_writing - tnow +
230*1424Sroot 			(((1.0*(tnow - tstart_writing))/blockswritten) * esize);
231*1424Sroot 		msg("%3.2f%% done, finished in %d:%02d\n",
232*1424Sroot 			(blockswritten*100.0)/esize,
233*1424Sroot 			deltat/3600, (deltat%3600)/60);
234*1424Sroot 	}
235*1424Sroot }
236*1424Sroot 
237*1424Sroot int blocksontape()
238*1424Sroot {
239*1424Sroot 	/*
240*1424Sroot 	 *	esize: total number of blocks estimated over all reels
241*1424Sroot 	 *	blockswritten:	blocks actually written, over all reels
242*1424Sroot 	 *	etapes:	estimated number of tapes to write
243*1424Sroot 	 *
244*1424Sroot 	 *	tsize:	blocks can write on this reel
245*1424Sroot 	 *	asize:	blocks written on this reel
246*1424Sroot 	 *	tapeno:	number of tapes written so far
247*1424Sroot 	 */
248*1424Sroot 	if (tapeno == etapes)
249*1424Sroot 		return(esize - (etapes - 1)*tsize);
250*1424Sroot 	return(tsize);
251*1424Sroot }
252*1424Sroot 
253*1424Sroot 	/* VARARGS1 */
254*1424Sroot 	/* ARGSUSED */
255*1424Sroot msg(fmt, a1, a2, a3, a4, a5)
256*1424Sroot 	char	*fmt;
257*1424Sroot {
258*1424Sroot 	fprintf(stderr,"  DUMP: ");
259*1424Sroot #ifdef TDEBUG
260*1424Sroot 	fprintf(stderr,"pid=%d ", getpid());
261*1424Sroot #endif
262*1424Sroot 	fprintf(stderr, fmt, a1, a2, a3, a4, a5);
263*1424Sroot 	fflush(stdout);
264*1424Sroot 	fflush(stderr);
265*1424Sroot }
266*1424Sroot 
267*1424Sroot 	/* VARARGS1 */
268*1424Sroot 	/* ARGSUSED */
269*1424Sroot msgtail(fmt, a1, a2, a3, a4, a5)
270*1424Sroot 	char	*fmt;
271*1424Sroot {
272*1424Sroot 	fprintf(stderr, fmt, a1, a2, a3, a4, a5);
273*1424Sroot }
274*1424Sroot /*
275*1424Sroot  *	Tell the operator what has to be done;
276*1424Sroot  *	we don't actually do it
277*1424Sroot  */
278*1424Sroot 
279*1424Sroot getfstab()
280*1424Sroot {
281*1424Sroot 	register	struct	fstab	*dt;
282*1424Sroot 			FILE	*fstabfile;
283*1424Sroot 
284*1424Sroot 	nfstab = 0;
285*1424Sroot 	if ( (fstabfile = fopen(FSTAB, "r")) == NULL){
286*1424Sroot 		msg("Can't open %s for dump table information.\n", FSTAB);
287*1424Sroot 	} else {
288*1424Sroot 		for (nfstab = 0, dt = fstab; nfstab < MAXFSTAB;){
289*1424Sroot 			if (feof(fstabfile))
290*1424Sroot 				break;
291*1424Sroot 			fscanf(fstabfile, FSTABFMT, FSTABARG(dt));
292*1424Sroot 			if (!strcmp(dt->fs_type, "rw") ||
293*1424Sroot 			    !strcmp(dt->fs_type, "ro"))
294*1424Sroot 				nfstab++, dt++;
295*1424Sroot 		}
296*1424Sroot 		fclose(fstabfile);
297*1424Sroot 	}
298*1424Sroot }
299*1424Sroot 
300*1424Sroot /*
301*1424Sroot  *	Search in the fstab for a file name.
302*1424Sroot  *	This file name can be either the special or the path file name.
303*1424Sroot  *
304*1424Sroot  *	The entries in the fstab are the BLOCK special names, not the
305*1424Sroot  *	character special names.
306*1424Sroot  *	The caller of fstabsearch assures that the character device
307*1424Sroot  *	is dumped (that is much faster)
308*1424Sroot  *
309*1424Sroot  *	The file name can omit the leading '/'.
310*1424Sroot  */
311*1424Sroot struct	fstab	*fstabsearch(key)
312*1424Sroot 	char	*key;
313*1424Sroot {
314*1424Sroot 	register	struct	fstab *dt;
315*1424Sroot 			int	i;
316*1424Sroot 			int	keylength;
317*1424Sroot 			char	*rawname();
318*1424Sroot 
319*1424Sroot 	keylength = min(strlen(key), sizeof (dt->fs_file));
320*1424Sroot 	for (i = 0, dt = fstab; i < nfstab; i++, dt++){
321*1424Sroot 		if (strncmp(dt->fs_file, key, keylength) == 0)
322*1424Sroot 			return(dt);
323*1424Sroot 		if (strncmp(dt->fs_spec, key, keylength) == 0)
324*1424Sroot 			return(dt);
325*1424Sroot 		if (strncmp(rawname(dt->fs_spec), key, keylength) == 0)
326*1424Sroot 			return(dt);
327*1424Sroot 
328*1424Sroot 		if (key[0] != '/'){
329*1424Sroot 			if (   (dt->fs_spec[0] == '/')
330*1424Sroot 			    && (strncmp(dt->fs_spec+1, key, keylength) == 0))
331*1424Sroot 				return(dt);
332*1424Sroot 			if (   (dt->fs_file[0] == '/')
333*1424Sroot 			    && (strncmp(dt->fs_file+1, key, keylength) == 0))
334*1424Sroot 				return(dt);
335*1424Sroot 		}
336*1424Sroot 	}
337*1424Sroot 	return(0);
338*1424Sroot }
339*1424Sroot 
340*1424Sroot /*
341*1424Sroot  *	Tell the operator what to do
342*1424Sroot  */
343*1424Sroot lastdump()
344*1424Sroot {
345*1424Sroot 			char	*lastname;
346*1424Sroot 			char	*date;
347*1424Sroot 	register	int	i;
348*1424Sroot 			time_t	tnow;
349*1424Sroot 	register	struct	fstab	*dt;
350*1424Sroot 			int	dumpme;
351*1424Sroot 	register	struct	idates	*itwalk;
352*1424Sroot 
353*1424Sroot 	int	idatesort();
354*1424Sroot 
355*1424Sroot 	time(&tnow);
356*1424Sroot 	getfstab();		/* /etc/fstab input */
357*1424Sroot 	inititimes();		/* /etc/dumpdates input */
358*1424Sroot 	qsort(idatev, nidates, sizeof(struct idates *), idatesort);
359*1424Sroot 
360*1424Sroot 	fprintf(stdout, "Last dump(s) done (Dump '*' file systems):\n");
361*1424Sroot 	lastname = "??";
362*1424Sroot 	ITITERATE(i, itwalk){
363*1424Sroot 		if (strncmp(lastname, itwalk->id_name, sizeof(itwalk->id_name)) == 0)
364*1424Sroot 			continue;
365*1424Sroot 		date = (char *)ctime(&itwalk->id_ddate);
366*1424Sroot 		date[16] = '\0';		/* blast away seconds and year */
367*1424Sroot 		lastname = itwalk->id_name;
368*1424Sroot 		dt = fstabsearch(itwalk->id_name);
369*1424Sroot 		dumpme = (  (dt != 0)
370*1424Sroot 			 && (dt->fs_freq != 0)
371*1424Sroot 			 && (itwalk->id_ddate < tnow - (dt->fs_freq*DAY)));
372*1424Sroot 		fprintf(stdout,"%c %8s\t(%6s) Last dump: Level %c, Date %s\n",
373*1424Sroot 			dumpme ? '*' : ' ',
374*1424Sroot 			itwalk->id_name,
375*1424Sroot 			dt ? dt->fs_file : 0,
376*1424Sroot 			itwalk->id_incno,
377*1424Sroot 			date
378*1424Sroot 		    );
379*1424Sroot 	}
380*1424Sroot }
381*1424Sroot 
382*1424Sroot int	idatesort(p1, p2)
383*1424Sroot 	struct	idates	**p1, **p2;
384*1424Sroot {
385*1424Sroot 	int	diff;
386*1424Sroot 
387*1424Sroot 	diff = strncmp((*p1)->id_name, (*p2)->id_name, sizeof((*p1)->id_name));
388*1424Sroot 	if (diff == 0)
389*1424Sroot 		return ((*p2)->id_ddate - (*p1)->id_ddate);
390*1424Sroot 	else
391*1424Sroot 		return (diff);
392*1424Sroot }
393*1424Sroot 
394*1424Sroot int max(a,b)
395*1424Sroot {
396*1424Sroot 	return(a>b?a:b);
397*1424Sroot }
398*1424Sroot int min(a,b)
399*1424Sroot {
400*1424Sroot 	return(a<b?a:b);
401*1424Sroot }
402