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