xref: /titanic_52/usr/src/cmd/backup/dump/dumpoptr.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1998 by Sun Microsystems, Inc.
3*7c478bd9Sstevel@tonic-gate  * All rights reserved.
4*7c478bd9Sstevel@tonic-gate  */
5*7c478bd9Sstevel@tonic-gate 
6*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
7*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved	*/
8*7c478bd9Sstevel@tonic-gate 
9*7c478bd9Sstevel@tonic-gate /*
10*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
11*7c478bd9Sstevel@tonic-gate  * All rights reserved.  The Berkeley software License Agreement
12*7c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
13*7c478bd9Sstevel@tonic-gate  */
14*7c478bd9Sstevel@tonic-gate 
15*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
16*7c478bd9Sstevel@tonic-gate 
17*7c478bd9Sstevel@tonic-gate #include <errno.h>
18*7c478bd9Sstevel@tonic-gate #include "dump.h"
19*7c478bd9Sstevel@tonic-gate 
20*7c478bd9Sstevel@tonic-gate static unsigned int timeout;		/* current timeout */
21*7c478bd9Sstevel@tonic-gate static char *attnmessage, *saveattn;	/* attention message */
22*7c478bd9Sstevel@tonic-gate 
23*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
24*7c478bd9Sstevel@tonic-gate static void alarmcatch();
25*7c478bd9Sstevel@tonic-gate static int idatesort(const void *, const void *);
26*7c478bd9Sstevel@tonic-gate #else /* !__STDC__ */
27*7c478bd9Sstevel@tonic-gate static void alarmcatch();
28*7c478bd9Sstevel@tonic-gate static int idatesort();
29*7c478bd9Sstevel@tonic-gate #endif
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
32*7c478bd9Sstevel@tonic-gate extern int xflag;
33*7c478bd9Sstevel@tonic-gate #endif
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate /*
36*7c478bd9Sstevel@tonic-gate  *	Query the operator; This fascist piece of code requires
37*7c478bd9Sstevel@tonic-gate  *	an exact response.
38*7c478bd9Sstevel@tonic-gate  *	It is intended to protect dump aborting by inquisitive
39*7c478bd9Sstevel@tonic-gate  *	people banging on the console terminal to see what is
40*7c478bd9Sstevel@tonic-gate  *	happening which might cause dump to croak, destroying
41*7c478bd9Sstevel@tonic-gate  *	a large number of hours of work.
42*7c478bd9Sstevel@tonic-gate  *
43*7c478bd9Sstevel@tonic-gate  *	Every time += 2 minutes we reprint the message, alerting others
44*7c478bd9Sstevel@tonic-gate  *	that dump needs attention.
45*7c478bd9Sstevel@tonic-gate  */
46*7c478bd9Sstevel@tonic-gate int
47*7c478bd9Sstevel@tonic-gate query(question)
48*7c478bd9Sstevel@tonic-gate 	char	*question;
49*7c478bd9Sstevel@tonic-gate {
50*7c478bd9Sstevel@tonic-gate 	int def = -1;
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate 	while (def == -1)
53*7c478bd9Sstevel@tonic-gate 		def = query_once(question, -1);
54*7c478bd9Sstevel@tonic-gate 	return (def);
55*7c478bd9Sstevel@tonic-gate }
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate static int in_query_once;
58*7c478bd9Sstevel@tonic-gate static jmp_buf sjalarmbuf;
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate /* real simple check-sum */
61*7c478bd9Sstevel@tonic-gate static int
62*7c478bd9Sstevel@tonic-gate addem(s)
63*7c478bd9Sstevel@tonic-gate 	char *s;
64*7c478bd9Sstevel@tonic-gate {
65*7c478bd9Sstevel@tonic-gate 	int total = 0;
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate 	if (s == (char *)NULL)
68*7c478bd9Sstevel@tonic-gate 		return (total);
69*7c478bd9Sstevel@tonic-gate 	while (*s)
70*7c478bd9Sstevel@tonic-gate 		total += *s++;
71*7c478bd9Sstevel@tonic-gate 	return (total);
72*7c478bd9Sstevel@tonic-gate }
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate int
75*7c478bd9Sstevel@tonic-gate query_once(question, def)
76*7c478bd9Sstevel@tonic-gate 	char	*question;
77*7c478bd9Sstevel@tonic-gate 	int	def;
78*7c478bd9Sstevel@tonic-gate {
79*7c478bd9Sstevel@tonic-gate 	static char *lastmsg;
80*7c478bd9Sstevel@tonic-gate 	static int lastmsgsum;
81*7c478bd9Sstevel@tonic-gate 	int	msgsum;
82*7c478bd9Sstevel@tonic-gate 	char	replybuffer[BUFSIZ];
83*7c478bd9Sstevel@tonic-gate 	int	back;
84*7c478bd9Sstevel@tonic-gate 	time32_t timeclockstate;
85*7c478bd9Sstevel@tonic-gate 	pollfd_t pollset;
86*7c478bd9Sstevel@tonic-gate 	struct sigvec sv;
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate 	/* special hook to flush timeout cache */
89*7c478bd9Sstevel@tonic-gate 	if (question == NULL) {
90*7c478bd9Sstevel@tonic-gate 		lastmsg = (char *)NULL;
91*7c478bd9Sstevel@tonic-gate 		lastmsgsum = 0;
92*7c478bd9Sstevel@tonic-gate 		return (0);
93*7c478bd9Sstevel@tonic-gate 	}
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate 	attnmessage = question;
96*7c478bd9Sstevel@tonic-gate 	/*
97*7c478bd9Sstevel@tonic-gate 	 * Only reset the state if the message changed somehow
98*7c478bd9Sstevel@tonic-gate 	 */
99*7c478bd9Sstevel@tonic-gate 	msgsum = addem(question);
100*7c478bd9Sstevel@tonic-gate 	if (lastmsg != question || lastmsgsum != msgsum) {
101*7c478bd9Sstevel@tonic-gate 		timeout = 0;
102*7c478bd9Sstevel@tonic-gate 		if (telapsed && tstart_writing)
103*7c478bd9Sstevel@tonic-gate 			*telapsed += time((time_t *)0) - *tstart_writing;
104*7c478bd9Sstevel@tonic-gate 		lastmsg = question;
105*7c478bd9Sstevel@tonic-gate 		lastmsgsum = msgsum;
106*7c478bd9Sstevel@tonic-gate 	}
107*7c478bd9Sstevel@tonic-gate 	timeclockstate = timeclock((time_t)0);
108*7c478bd9Sstevel@tonic-gate 	if (setjmp(sjalarmbuf) != 0) {
109*7c478bd9Sstevel@tonic-gate 		if (def != -1) {
110*7c478bd9Sstevel@tonic-gate 			if (def)
111*7c478bd9Sstevel@tonic-gate 				msgtail(gettext("YES\n"));
112*7c478bd9Sstevel@tonic-gate 			else
113*7c478bd9Sstevel@tonic-gate 				msgtail(gettext("NO\n"));
114*7c478bd9Sstevel@tonic-gate 		}
115*7c478bd9Sstevel@tonic-gate 		back = def;
116*7c478bd9Sstevel@tonic-gate 		goto done;
117*7c478bd9Sstevel@tonic-gate 	}
118*7c478bd9Sstevel@tonic-gate 	alarmcatch();
119*7c478bd9Sstevel@tonic-gate 	in_query_once = 1;
120*7c478bd9Sstevel@tonic-gate 	pollset.fd = -1;
121*7c478bd9Sstevel@tonic-gate 	pollset.events = 0;
122*7c478bd9Sstevel@tonic-gate 	pollset.revents = 0;
123*7c478bd9Sstevel@tonic-gate 	if (isatty(fileno(stdin))) {
124*7c478bd9Sstevel@tonic-gate 		pollset.fd = fileno(stdin);
125*7c478bd9Sstevel@tonic-gate 		pollset.events = POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND;
126*7c478bd9Sstevel@tonic-gate 	} else {
127*7c478bd9Sstevel@tonic-gate 		dumpabort();
128*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
129*7c478bd9Sstevel@tonic-gate 	}
130*7c478bd9Sstevel@tonic-gate 	for (;;) {
131*7c478bd9Sstevel@tonic-gate 		if (poll(&pollset, 1, -1) < 0) {
132*7c478bd9Sstevel@tonic-gate 			if (errno == EINTR)
133*7c478bd9Sstevel@tonic-gate 				continue;
134*7c478bd9Sstevel@tonic-gate 			perror("poll(stdin)");
135*7c478bd9Sstevel@tonic-gate 			dumpabort();
136*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
137*7c478bd9Sstevel@tonic-gate 		}
138*7c478bd9Sstevel@tonic-gate 		if (pollset.revents == 0)
139*7c478bd9Sstevel@tonic-gate 			continue;	/* sanity check */
140*7c478bd9Sstevel@tonic-gate 		if (fgets(replybuffer, sizeof (replybuffer), stdin) == NULL) {
141*7c478bd9Sstevel@tonic-gate 			if (ferror(stdin)) {
142*7c478bd9Sstevel@tonic-gate 				clearerr(stdin);
143*7c478bd9Sstevel@tonic-gate 				continue;
144*7c478bd9Sstevel@tonic-gate 			} else {
145*7c478bd9Sstevel@tonic-gate 				dumpabort();
146*7c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
147*7c478bd9Sstevel@tonic-gate 			}
148*7c478bd9Sstevel@tonic-gate 		}
149*7c478bd9Sstevel@tonic-gate 		timeout = 0;
150*7c478bd9Sstevel@tonic-gate 		if (strcasecmp(replybuffer, gettext("yes\n")) == 0) {
151*7c478bd9Sstevel@tonic-gate 			back = 1;
152*7c478bd9Sstevel@tonic-gate 			lastmsg = (char *)NULL;
153*7c478bd9Sstevel@tonic-gate 			lastmsgsum = 0;
154*7c478bd9Sstevel@tonic-gate 			goto done;
155*7c478bd9Sstevel@tonic-gate 		} else if (strcasecmp(replybuffer, gettext("no\n")) == 0) {
156*7c478bd9Sstevel@tonic-gate 			back = 0;
157*7c478bd9Sstevel@tonic-gate 			lastmsg = (char *)NULL;
158*7c478bd9Sstevel@tonic-gate 			lastmsgsum = 0;
159*7c478bd9Sstevel@tonic-gate 			goto done;
160*7c478bd9Sstevel@tonic-gate 		} else {
161*7c478bd9Sstevel@tonic-gate 			msg(gettext("\"yes\" or \"no\"?\n"));
162*7c478bd9Sstevel@tonic-gate 			in_query_once = 0;
163*7c478bd9Sstevel@tonic-gate 			alarmcatch();
164*7c478bd9Sstevel@tonic-gate 			in_query_once = 1;
165*7c478bd9Sstevel@tonic-gate 		}
166*7c478bd9Sstevel@tonic-gate 	}
167*7c478bd9Sstevel@tonic-gate done:
168*7c478bd9Sstevel@tonic-gate 	/*
169*7c478bd9Sstevel@tonic-gate 	 * Turn off the alarm, and reset the signal to trap out..
170*7c478bd9Sstevel@tonic-gate 	 */
171*7c478bd9Sstevel@tonic-gate 	(void) alarm(0);
172*7c478bd9Sstevel@tonic-gate 	attnmessage = NULL;
173*7c478bd9Sstevel@tonic-gate 	sv.sv_handler = sigAbort;
174*7c478bd9Sstevel@tonic-gate 	sv.sv_flags = SA_RESTART;
175*7c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&sv.sa_mask);
176*7c478bd9Sstevel@tonic-gate 	(void) sigvec(SIGALRM, &sv, (struct sigvec *)0);
177*7c478bd9Sstevel@tonic-gate 	if (tstart_writing)
178*7c478bd9Sstevel@tonic-gate 		(void) time(tstart_writing);
179*7c478bd9Sstevel@tonic-gate 	(void) timeclock(timeclockstate);
180*7c478bd9Sstevel@tonic-gate 	in_query_once = 0;
181*7c478bd9Sstevel@tonic-gate 	return (back);
182*7c478bd9Sstevel@tonic-gate }
183*7c478bd9Sstevel@tonic-gate /*
184*7c478bd9Sstevel@tonic-gate  *	Alert the console operator, and enable the alarm clock to
185*7c478bd9Sstevel@tonic-gate  *	sleep for time += 2 minutes in case nobody comes to satisfy dump
186*7c478bd9Sstevel@tonic-gate  *	If the alarm goes off while in the query_once for loop, we just
187*7c478bd9Sstevel@tonic-gate  *	longjmp back there and return the default answer.
188*7c478bd9Sstevel@tonic-gate  */
189*7c478bd9Sstevel@tonic-gate static void
190*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
191*7c478bd9Sstevel@tonic-gate alarmcatch(void)
192*7c478bd9Sstevel@tonic-gate #else
193*7c478bd9Sstevel@tonic-gate alarmcatch()
194*7c478bd9Sstevel@tonic-gate #endif
195*7c478bd9Sstevel@tonic-gate {
196*7c478bd9Sstevel@tonic-gate 	struct sigvec sv;
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 	if (in_query_once) {
199*7c478bd9Sstevel@tonic-gate 		longjmp(sjalarmbuf, 1);
200*7c478bd9Sstevel@tonic-gate 	}
201*7c478bd9Sstevel@tonic-gate 	if (timeout) {
202*7c478bd9Sstevel@tonic-gate 		msgtail("\n");
203*7c478bd9Sstevel@tonic-gate 	}
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate 	timeout += 120;
206*7c478bd9Sstevel@tonic-gate 	msg(gettext("NEEDS ATTENTION: %s"), attnmessage);
207*7c478bd9Sstevel@tonic-gate 	sv.sv_handler = alarmcatch;
208*7c478bd9Sstevel@tonic-gate 	sv.sv_flags = SA_RESTART;
209*7c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&sv.sa_mask);
210*7c478bd9Sstevel@tonic-gate 	(void) sigvec(SIGALRM, &sv, (struct sigvec *)0);
211*7c478bd9Sstevel@tonic-gate 	(void) alarm(timeout);
212*7c478bd9Sstevel@tonic-gate }
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate /*
215*7c478bd9Sstevel@tonic-gate  *	Here if an inquisitive operator interrupts the dump program
216*7c478bd9Sstevel@tonic-gate  */
217*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
218*7c478bd9Sstevel@tonic-gate void
219*7c478bd9Sstevel@tonic-gate interrupt(sig)
220*7c478bd9Sstevel@tonic-gate 	int	sig;
221*7c478bd9Sstevel@tonic-gate {
222*7c478bd9Sstevel@tonic-gate 	if (!saveattn) {
223*7c478bd9Sstevel@tonic-gate 		saveattn = attnmessage;
224*7c478bd9Sstevel@tonic-gate 	}
225*7c478bd9Sstevel@tonic-gate 	msg(gettext("Interrupt received.\n"));
226*7c478bd9Sstevel@tonic-gate 	if (query(gettext(
227*7c478bd9Sstevel@tonic-gate 	    "Do you want to abort dump?: (\"yes\" or \"no\") "))) {
228*7c478bd9Sstevel@tonic-gate 		dumpabort();
229*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
230*7c478bd9Sstevel@tonic-gate 	}
231*7c478bd9Sstevel@tonic-gate 	if (saveattn) {
232*7c478bd9Sstevel@tonic-gate 		attnmessage = saveattn;
233*7c478bd9Sstevel@tonic-gate 		saveattn = NULL;
234*7c478bd9Sstevel@tonic-gate 		alarmcatch();
235*7c478bd9Sstevel@tonic-gate 	}
236*7c478bd9Sstevel@tonic-gate }
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate /*
239*7c478bd9Sstevel@tonic-gate  *	We use wall(1) to do the actual broadcasting, so
240*7c478bd9Sstevel@tonic-gate  *	that we don't have to worry about duplicated code
241*7c478bd9Sstevel@tonic-gate  *	only getting fixed in one place.  This also saves
242*7c478bd9Sstevel@tonic-gate  *	us from having to worry about process groups,
243*7c478bd9Sstevel@tonic-gate  *	controlling terminals, and the like.
244*7c478bd9Sstevel@tonic-gate  */
245*7c478bd9Sstevel@tonic-gate void
246*7c478bd9Sstevel@tonic-gate broadcast(message)
247*7c478bd9Sstevel@tonic-gate 	char	*message;
248*7c478bd9Sstevel@tonic-gate {
249*7c478bd9Sstevel@tonic-gate 	time_t	clock;
250*7c478bd9Sstevel@tonic-gate 	pid_t	pid;
251*7c478bd9Sstevel@tonic-gate 	int	saverr;
252*7c478bd9Sstevel@tonic-gate 	int	fildes[2];
253*7c478bd9Sstevel@tonic-gate 	FILE	*wall;
254*7c478bd9Sstevel@tonic-gate 	struct tm *localclock;
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 	if (!notify)
257*7c478bd9Sstevel@tonic-gate 		return;
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 	if (pipe(fildes) < 0) {
260*7c478bd9Sstevel@tonic-gate 		saverr = errno;
261*7c478bd9Sstevel@tonic-gate 		msg(gettext("pipe: %s\n"), strerror(saverr));
262*7c478bd9Sstevel@tonic-gate 		return;
263*7c478bd9Sstevel@tonic-gate 	}
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate 	switch (pid = fork()) {
266*7c478bd9Sstevel@tonic-gate 	case -1:
267*7c478bd9Sstevel@tonic-gate 		return;
268*7c478bd9Sstevel@tonic-gate 	case 0:
269*7c478bd9Sstevel@tonic-gate 		close(fildes[0]);
270*7c478bd9Sstevel@tonic-gate 		if (dup2(fildes[1], 0) < 0) {
271*7c478bd9Sstevel@tonic-gate 			saverr = errno;
272*7c478bd9Sstevel@tonic-gate 			msg(gettext("dup2: %s\n"), strerror(saverr));
273*7c478bd9Sstevel@tonic-gate 			exit(1);
274*7c478bd9Sstevel@tonic-gate 		}
275*7c478bd9Sstevel@tonic-gate 		execl("/usr/sbin/wall", "wall", "-g", OPGRENT, (char *)NULL);
276*7c478bd9Sstevel@tonic-gate 		saverr = errno;
277*7c478bd9Sstevel@tonic-gate 		msg(gettext("execl: %s\n"), strerror(saverr));
278*7c478bd9Sstevel@tonic-gate 		exit(1);
279*7c478bd9Sstevel@tonic-gate 	default:
280*7c478bd9Sstevel@tonic-gate 		break;		/* parent */
281*7c478bd9Sstevel@tonic-gate 	}
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 	close(fildes[1]);
284*7c478bd9Sstevel@tonic-gate 	wall = fdopen(fildes[0], "r+");
285*7c478bd9Sstevel@tonic-gate 	if (wall == (FILE *)NULL) {
286*7c478bd9Sstevel@tonic-gate 		saverr = errno;
287*7c478bd9Sstevel@tonic-gate 		msg(gettext("fdopen: %s\n"), strerror(saverr));
288*7c478bd9Sstevel@tonic-gate 		return;
289*7c478bd9Sstevel@tonic-gate 	}
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate 	clock = time((time_t *)0);
292*7c478bd9Sstevel@tonic-gate 	localclock = localtime(&clock);
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate 	(void) fprintf(wall, gettext(
295*7c478bd9Sstevel@tonic-gate "\n\007\007\007Message from the dump program to all operators at \
296*7c478bd9Sstevel@tonic-gate %d:%02d ...\n\n%s"),
297*7c478bd9Sstevel@tonic-gate 	    localclock->tm_hour, localclock->tm_min, message);
298*7c478bd9Sstevel@tonic-gate 	fclose(wall);
299*7c478bd9Sstevel@tonic-gate 
300*7c478bd9Sstevel@tonic-gate 	while (wait((int *)0) != pid) {
301*7c478bd9Sstevel@tonic-gate 		continue;
302*7c478bd9Sstevel@tonic-gate 		/*LINTED [empty loop body]*/
303*7c478bd9Sstevel@tonic-gate 	}
304*7c478bd9Sstevel@tonic-gate }
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate /*
307*7c478bd9Sstevel@tonic-gate  *	print out an estimate of the amount of time left to do the dump
308*7c478bd9Sstevel@tonic-gate  */
309*7c478bd9Sstevel@tonic-gate #define	EST_SEC	600			/* every 10 minutes */
310*7c478bd9Sstevel@tonic-gate void
311*7c478bd9Sstevel@tonic-gate timeest(force, blkswritten)
312*7c478bd9Sstevel@tonic-gate 	int force;
313*7c478bd9Sstevel@tonic-gate 	int blkswritten;
314*7c478bd9Sstevel@tonic-gate {
315*7c478bd9Sstevel@tonic-gate 	time_t tnow, deltat;
316*7c478bd9Sstevel@tonic-gate 	char *msgp;
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 	if (tschedule == NULL)
319*7c478bd9Sstevel@tonic-gate 		return;
320*7c478bd9Sstevel@tonic-gate 	if (*tschedule == 0)
321*7c478bd9Sstevel@tonic-gate 		*tschedule = time((time_t *)0) + EST_SEC;
322*7c478bd9Sstevel@tonic-gate 	(void) time(&tnow);
323*7c478bd9Sstevel@tonic-gate 	if ((force || tnow >= *tschedule) && blkswritten) {
324*7c478bd9Sstevel@tonic-gate 		*tschedule = tnow + EST_SEC;
325*7c478bd9Sstevel@tonic-gate 		if (!force && blkswritten < 50 * ntrec)
326*7c478bd9Sstevel@tonic-gate 			return;
327*7c478bd9Sstevel@tonic-gate 		deltat = (*telapsed + (tnow - *tstart_writing))
328*7c478bd9Sstevel@tonic-gate 				* ((double)esize / blkswritten - 1.0);
329*7c478bd9Sstevel@tonic-gate 		msgp = gettext("%3.2f%% done, finished in %d:%02d\n");
330*7c478bd9Sstevel@tonic-gate 		msg(msgp, (blkswritten*100.0)/esize,
331*7c478bd9Sstevel@tonic-gate 			deltat/3600, (deltat%3600)/60);
332*7c478bd9Sstevel@tonic-gate 	}
333*7c478bd9Sstevel@tonic-gate }
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
336*7c478bd9Sstevel@tonic-gate 
337*7c478bd9Sstevel@tonic-gate /* VARARGS1 */
338*7c478bd9Sstevel@tonic-gate void
339*7c478bd9Sstevel@tonic-gate msg(const char *fmt, ...)
340*7c478bd9Sstevel@tonic-gate {
341*7c478bd9Sstevel@tonic-gate 	char buf[1024], *cp;
342*7c478bd9Sstevel@tonic-gate 	size_t size;
343*7c478bd9Sstevel@tonic-gate 	va_list args;
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 	va_start(args, fmt);
346*7c478bd9Sstevel@tonic-gate 	(void) strcpy(buf, "  DUMP: ");
347*7c478bd9Sstevel@tonic-gate 	cp = &buf[strlen(buf)];
348*7c478bd9Sstevel@tonic-gate #ifdef TDEBUG
349*7c478bd9Sstevel@tonic-gate 	(void) sprintf(cp, "pid=%d ", getpid());
350*7c478bd9Sstevel@tonic-gate 	cp = &buf[strlen(buf)];
351*7c478bd9Sstevel@tonic-gate #endif
352*7c478bd9Sstevel@tonic-gate 	/* don't need -1, vsnprintf does it right */
353*7c478bd9Sstevel@tonic-gate 	/* LINTED pointer arithmetic result fits in size_t */
354*7c478bd9Sstevel@tonic-gate 	size = ((size_t)sizeof (buf)) - (size_t)(cp - buf);
355*7c478bd9Sstevel@tonic-gate 	(void) vsnprintf(cp, size, fmt, args);
356*7c478bd9Sstevel@tonic-gate 	(void) fputs(buf, stderr);
357*7c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
358*7c478bd9Sstevel@tonic-gate 	(void) fflush(stderr);
359*7c478bd9Sstevel@tonic-gate 	va_end(args);
360*7c478bd9Sstevel@tonic-gate }
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate /* VARARGS1 */
363*7c478bd9Sstevel@tonic-gate void
364*7c478bd9Sstevel@tonic-gate msgtail(const char *fmt, ...)
365*7c478bd9Sstevel@tonic-gate {
366*7c478bd9Sstevel@tonic-gate 	va_list args;
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 	va_start(args, fmt);
369*7c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, fmt, args);
370*7c478bd9Sstevel@tonic-gate 	va_end(args);
371*7c478bd9Sstevel@tonic-gate }
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate #define	MINUTES(x)	((x) * 60)
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate /*
376*7c478bd9Sstevel@tonic-gate  *	Tell the operator what has to be done;
377*7c478bd9Sstevel@tonic-gate  *	we don't actually do it
378*7c478bd9Sstevel@tonic-gate  */
379*7c478bd9Sstevel@tonic-gate void
380*7c478bd9Sstevel@tonic-gate lastdump(arg)		/* w ==> just what to do; W ==> most recent dumps */
381*7c478bd9Sstevel@tonic-gate 	int	arg;
382*7c478bd9Sstevel@tonic-gate {
383*7c478bd9Sstevel@tonic-gate 	char *lastname;
384*7c478bd9Sstevel@tonic-gate 	char *date;
385*7c478bd9Sstevel@tonic-gate 	int i;
386*7c478bd9Sstevel@tonic-gate 	time_t tnow, ddate;
387*7c478bd9Sstevel@tonic-gate 	struct mntent *dt;
388*7c478bd9Sstevel@tonic-gate 	int dumpme = 0;
389*7c478bd9Sstevel@tonic-gate 	struct idates *itwalk;
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 	(void) time(&tnow);
392*7c478bd9Sstevel@tonic-gate 	mnttabread();		/* /etc/fstab input */
393*7c478bd9Sstevel@tonic-gate 	inititimes();		/* /etc/dumpdates input */
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate 	/* Don't use msg(), this isn't a tell-the-world kind of thing */
396*7c478bd9Sstevel@tonic-gate 	if (arg == 'w')
397*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stdout, gettext("Dump these file systems:\n"));
398*7c478bd9Sstevel@tonic-gate 	else
399*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stdout, gettext(
400*7c478bd9Sstevel@tonic-gate 		    "Last dump(s) done (Dump '>' file systems):\n"));
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate 	if (idatev != NULL) {
403*7c478bd9Sstevel@tonic-gate 		qsort((char *)idatev, nidates, sizeof (*idatev), idatesort);
404*7c478bd9Sstevel@tonic-gate 		lastname = "??";
405*7c478bd9Sstevel@tonic-gate 		ITITERATE(i, itwalk) {
406*7c478bd9Sstevel@tonic-gate 			if (strncmp(lastname, itwalk->id_name,
407*7c478bd9Sstevel@tonic-gate 			    sizeof (itwalk->id_name)) == 0)
408*7c478bd9Sstevel@tonic-gate 				continue;
409*7c478bd9Sstevel@tonic-gate 			/* must be ctime(), per ufsdump(4) */
410*7c478bd9Sstevel@tonic-gate 			ddate = itwalk->id_ddate;
411*7c478bd9Sstevel@tonic-gate 			date = (char *)ctime(&ddate);
412*7c478bd9Sstevel@tonic-gate 			date[16] = '\0';	/* blow away seconds and year */
413*7c478bd9Sstevel@tonic-gate 			lastname = itwalk->id_name;
414*7c478bd9Sstevel@tonic-gate 			dt = mnttabsearch(itwalk->id_name, 0);
415*7c478bd9Sstevel@tonic-gate 			if ((time_t)(itwalk->id_ddate) < (tnow - DAY)) {
416*7c478bd9Sstevel@tonic-gate 				dumpme = 1;
417*7c478bd9Sstevel@tonic-gate 			}
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate 			if ((arg == 'w') && dumpme) {
420*7c478bd9Sstevel@tonic-gate 				/*
421*7c478bd9Sstevel@tonic-gate 				 * Handle the w option: print out file systems
422*7c478bd9Sstevel@tonic-gate 				 * which haven't been backed up within a day.
423*7c478bd9Sstevel@tonic-gate 				 */
424*7c478bd9Sstevel@tonic-gate 				(void) printf(gettext("%8s\t(%6s)\n"),
425*7c478bd9Sstevel@tonic-gate 				    itwalk->id_name, dt ? dt->mnt_dir : "");
426*7c478bd9Sstevel@tonic-gate 			}
427*7c478bd9Sstevel@tonic-gate 			if (arg == 'W') {
428*7c478bd9Sstevel@tonic-gate 				/*
429*7c478bd9Sstevel@tonic-gate 				 * Handle the W option: print out ALL
430*7c478bd9Sstevel@tonic-gate 				 * filesystems including recent dump dates and
431*7c478bd9Sstevel@tonic-gate 				 * dump levels.  Mark the backup-needing
432*7c478bd9Sstevel@tonic-gate 				 * filesystems with a >.
433*7c478bd9Sstevel@tonic-gate 				 */
434*7c478bd9Sstevel@tonic-gate 				(void) printf(gettext(
435*7c478bd9Sstevel@tonic-gate 			    "%c %8s\t(%6s) Last dump: Level %c, Date %s\n"),
436*7c478bd9Sstevel@tonic-gate 				    dumpme ? '>' : ' ',
437*7c478bd9Sstevel@tonic-gate 				    itwalk->id_name,
438*7c478bd9Sstevel@tonic-gate 				    dt ? dt->mnt_dir : "",
439*7c478bd9Sstevel@tonic-gate 				    (uchar_t)itwalk->id_incno,
440*7c478bd9Sstevel@tonic-gate 				    date);
441*7c478bd9Sstevel@tonic-gate 			}
442*7c478bd9Sstevel@tonic-gate 			dumpme = 0;
443*7c478bd9Sstevel@tonic-gate 		}
444*7c478bd9Sstevel@tonic-gate 	}
445*7c478bd9Sstevel@tonic-gate }
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate static int
448*7c478bd9Sstevel@tonic-gate idatesort(v1, v2)
449*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
450*7c478bd9Sstevel@tonic-gate 	const void *v1;
451*7c478bd9Sstevel@tonic-gate 	const void *v2;
452*7c478bd9Sstevel@tonic-gate #else
453*7c478bd9Sstevel@tonic-gate 	void *v1;
454*7c478bd9Sstevel@tonic-gate 	void *v2;
455*7c478bd9Sstevel@tonic-gate #endif
456*7c478bd9Sstevel@tonic-gate {
457*7c478bd9Sstevel@tonic-gate 	struct idates **p1 = (struct idates **)v1;
458*7c478bd9Sstevel@tonic-gate 	struct idates **p2 = (struct idates **)v2;
459*7c478bd9Sstevel@tonic-gate 	int diff;
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate 	diff = strcoll((*p1)->id_name, (*p2)->id_name);
462*7c478bd9Sstevel@tonic-gate 	if (diff == 0) {
463*7c478bd9Sstevel@tonic-gate 		/*
464*7c478bd9Sstevel@tonic-gate 		 * Time may eventually become unsigned, so can't
465*7c478bd9Sstevel@tonic-gate 		 * rely on subtraction to give a useful result.
466*7c478bd9Sstevel@tonic-gate 		 * Note that we are sorting dates into reverse
467*7c478bd9Sstevel@tonic-gate 		 * order, so that we will report based on the
468*7c478bd9Sstevel@tonic-gate 		 * most-recent record for a particular filesystem.
469*7c478bd9Sstevel@tonic-gate 		 */
470*7c478bd9Sstevel@tonic-gate 		if ((*p1)->id_ddate > (*p2)->id_ddate)
471*7c478bd9Sstevel@tonic-gate 			diff = -1;
472*7c478bd9Sstevel@tonic-gate 		else if ((*p1)->id_ddate < (*p2)->id_ddate)
473*7c478bd9Sstevel@tonic-gate 			diff = 1;
474*7c478bd9Sstevel@tonic-gate 	}
475*7c478bd9Sstevel@tonic-gate 	return (diff);
476*7c478bd9Sstevel@tonic-gate }
477