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