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