xref: /illumos-gate/usr/src/cmd/backup/dump/dumpoptr.c (revision 30699046)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright (c) 1998 by Sun Microsystems, Inc.
37c478bd9Sstevel@tonic-gate  * All rights reserved.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
77c478bd9Sstevel@tonic-gate /*	  All Rights Reserved	*/
87c478bd9Sstevel@tonic-gate 
97c478bd9Sstevel@tonic-gate /*
107c478bd9Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
117c478bd9Sstevel@tonic-gate  * All rights reserved.  The Berkeley software License Agreement
127c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
137c478bd9Sstevel@tonic-gate  */
147c478bd9Sstevel@tonic-gate 
157c478bd9Sstevel@tonic-gate #include <errno.h>
167c478bd9Sstevel@tonic-gate #include "dump.h"
177c478bd9Sstevel@tonic-gate 
18e0dfa398SToomas Soome time_t *tschedule;
197c478bd9Sstevel@tonic-gate static unsigned int timeout;		/* current timeout */
207c478bd9Sstevel@tonic-gate static char *attnmessage, *saveattn;	/* attention message */
217c478bd9Sstevel@tonic-gate 
22*30699046SRichard Lowe static void alarmcatch(int);
237c478bd9Sstevel@tonic-gate static int idatesort(const void *, const void *);
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #ifdef DEBUG
267c478bd9Sstevel@tonic-gate extern int xflag;
277c478bd9Sstevel@tonic-gate #endif
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  *	Query the operator; This fascist piece of code requires
317c478bd9Sstevel@tonic-gate  *	an exact response.
327c478bd9Sstevel@tonic-gate  *	It is intended to protect dump aborting by inquisitive
337c478bd9Sstevel@tonic-gate  *	people banging on the console terminal to see what is
347c478bd9Sstevel@tonic-gate  *	happening which might cause dump to croak, destroying
357c478bd9Sstevel@tonic-gate  *	a large number of hours of work.
367c478bd9Sstevel@tonic-gate  *
377c478bd9Sstevel@tonic-gate  *	Every time += 2 minutes we reprint the message, alerting others
387c478bd9Sstevel@tonic-gate  *	that dump needs attention.
397c478bd9Sstevel@tonic-gate  */
407c478bd9Sstevel@tonic-gate int
query(char * question)41e0dfa398SToomas Soome query(char *question)
427c478bd9Sstevel@tonic-gate {
437c478bd9Sstevel@tonic-gate 	int def = -1;
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate 	while (def == -1)
467c478bd9Sstevel@tonic-gate 		def = query_once(question, -1);
477c478bd9Sstevel@tonic-gate 	return (def);
487c478bd9Sstevel@tonic-gate }
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate static int in_query_once;
517c478bd9Sstevel@tonic-gate static jmp_buf sjalarmbuf;
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate /* real simple check-sum */
547c478bd9Sstevel@tonic-gate static int
addem(char * s)55e0dfa398SToomas Soome addem(char *s)
567c478bd9Sstevel@tonic-gate {
577c478bd9Sstevel@tonic-gate 	int total = 0;
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate 	if (s == (char *)NULL)
607c478bd9Sstevel@tonic-gate 		return (total);
617c478bd9Sstevel@tonic-gate 	while (*s)
627c478bd9Sstevel@tonic-gate 		total += *s++;
637c478bd9Sstevel@tonic-gate 	return (total);
647c478bd9Sstevel@tonic-gate }
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate int
query_once(char * question,int def)67e0dfa398SToomas Soome query_once(char	*question, int def)
687c478bd9Sstevel@tonic-gate {
697c478bd9Sstevel@tonic-gate 	static char *lastmsg;
707c478bd9Sstevel@tonic-gate 	static int lastmsgsum;
717c478bd9Sstevel@tonic-gate 	int	msgsum;
727c478bd9Sstevel@tonic-gate 	char	replybuffer[BUFSIZ];
737c478bd9Sstevel@tonic-gate 	int	back;
747c478bd9Sstevel@tonic-gate 	time32_t timeclockstate;
757c478bd9Sstevel@tonic-gate 	pollfd_t pollset;
767c478bd9Sstevel@tonic-gate 	struct sigvec sv;
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate 	/* special hook to flush timeout cache */
797c478bd9Sstevel@tonic-gate 	if (question == NULL) {
807c478bd9Sstevel@tonic-gate 		lastmsg = (char *)NULL;
817c478bd9Sstevel@tonic-gate 		lastmsgsum = 0;
827c478bd9Sstevel@tonic-gate 		return (0);
837c478bd9Sstevel@tonic-gate 	}
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	attnmessage = question;
867c478bd9Sstevel@tonic-gate 	/*
877c478bd9Sstevel@tonic-gate 	 * Only reset the state if the message changed somehow
887c478bd9Sstevel@tonic-gate 	 */
897c478bd9Sstevel@tonic-gate 	msgsum = addem(question);
907c478bd9Sstevel@tonic-gate 	if (lastmsg != question || lastmsgsum != msgsum) {
917c478bd9Sstevel@tonic-gate 		timeout = 0;
927c478bd9Sstevel@tonic-gate 		if (telapsed && tstart_writing)
937c478bd9Sstevel@tonic-gate 			*telapsed += time((time_t *)0) - *tstart_writing;
947c478bd9Sstevel@tonic-gate 		lastmsg = question;
957c478bd9Sstevel@tonic-gate 		lastmsgsum = msgsum;
967c478bd9Sstevel@tonic-gate 	}
977c478bd9Sstevel@tonic-gate 	timeclockstate = timeclock((time_t)0);
987c478bd9Sstevel@tonic-gate 	if (setjmp(sjalarmbuf) != 0) {
997c478bd9Sstevel@tonic-gate 		if (def != -1) {
1007c478bd9Sstevel@tonic-gate 			if (def)
1017c478bd9Sstevel@tonic-gate 				msgtail(gettext("YES\n"));
1027c478bd9Sstevel@tonic-gate 			else
1037c478bd9Sstevel@tonic-gate 				msgtail(gettext("NO\n"));
1047c478bd9Sstevel@tonic-gate 		}
1057c478bd9Sstevel@tonic-gate 		back = def;
1067c478bd9Sstevel@tonic-gate 		goto done;
1077c478bd9Sstevel@tonic-gate 	}
108*30699046SRichard Lowe 	alarmcatch(SIGALRM);
1097c478bd9Sstevel@tonic-gate 	in_query_once = 1;
1107c478bd9Sstevel@tonic-gate 	pollset.fd = -1;
1117c478bd9Sstevel@tonic-gate 	pollset.events = 0;
1127c478bd9Sstevel@tonic-gate 	pollset.revents = 0;
1137c478bd9Sstevel@tonic-gate 	if (isatty(fileno(stdin))) {
1147c478bd9Sstevel@tonic-gate 		pollset.fd = fileno(stdin);
1157c478bd9Sstevel@tonic-gate 		pollset.events = POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND;
1167c478bd9Sstevel@tonic-gate 	} else {
1177c478bd9Sstevel@tonic-gate 		dumpabort();
1187c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
1197c478bd9Sstevel@tonic-gate 	}
1207c478bd9Sstevel@tonic-gate 	for (;;) {
1217c478bd9Sstevel@tonic-gate 		if (poll(&pollset, 1, -1) < 0) {
1227c478bd9Sstevel@tonic-gate 			if (errno == EINTR)
1237c478bd9Sstevel@tonic-gate 				continue;
1247c478bd9Sstevel@tonic-gate 			perror("poll(stdin)");
1257c478bd9Sstevel@tonic-gate 			dumpabort();
1267c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
1277c478bd9Sstevel@tonic-gate 		}
1287c478bd9Sstevel@tonic-gate 		if (pollset.revents == 0)
1297c478bd9Sstevel@tonic-gate 			continue;	/* sanity check */
1307c478bd9Sstevel@tonic-gate 		if (fgets(replybuffer, sizeof (replybuffer), stdin) == NULL) {
1317c478bd9Sstevel@tonic-gate 			if (ferror(stdin)) {
1327c478bd9Sstevel@tonic-gate 				clearerr(stdin);
1337c478bd9Sstevel@tonic-gate 				continue;
1347c478bd9Sstevel@tonic-gate 			} else {
1357c478bd9Sstevel@tonic-gate 				dumpabort();
1367c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
1377c478bd9Sstevel@tonic-gate 			}
1387c478bd9Sstevel@tonic-gate 		}
1397c478bd9Sstevel@tonic-gate 		timeout = 0;
1407c478bd9Sstevel@tonic-gate 		if (strcasecmp(replybuffer, gettext("yes\n")) == 0) {
1417c478bd9Sstevel@tonic-gate 			back = 1;
1427c478bd9Sstevel@tonic-gate 			lastmsg = (char *)NULL;
1437c478bd9Sstevel@tonic-gate 			lastmsgsum = 0;
1447c478bd9Sstevel@tonic-gate 			goto done;
1457c478bd9Sstevel@tonic-gate 		} else if (strcasecmp(replybuffer, gettext("no\n")) == 0) {
1467c478bd9Sstevel@tonic-gate 			back = 0;
1477c478bd9Sstevel@tonic-gate 			lastmsg = (char *)NULL;
1487c478bd9Sstevel@tonic-gate 			lastmsgsum = 0;
1497c478bd9Sstevel@tonic-gate 			goto done;
1507c478bd9Sstevel@tonic-gate 		} else {
1517c478bd9Sstevel@tonic-gate 			msg(gettext("\"yes\" or \"no\"?\n"));
1527c478bd9Sstevel@tonic-gate 			in_query_once = 0;
153*30699046SRichard Lowe 			alarmcatch(SIGALRM);
1547c478bd9Sstevel@tonic-gate 			in_query_once = 1;
1557c478bd9Sstevel@tonic-gate 		}
1567c478bd9Sstevel@tonic-gate 	}
1577c478bd9Sstevel@tonic-gate done:
1587c478bd9Sstevel@tonic-gate 	/*
1597c478bd9Sstevel@tonic-gate 	 * Turn off the alarm, and reset the signal to trap out..
1607c478bd9Sstevel@tonic-gate 	 */
1617c478bd9Sstevel@tonic-gate 	(void) alarm(0);
1627c478bd9Sstevel@tonic-gate 	attnmessage = NULL;
1637c478bd9Sstevel@tonic-gate 	sv.sv_handler = sigAbort;
1647c478bd9Sstevel@tonic-gate 	sv.sv_flags = SA_RESTART;
1657c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&sv.sa_mask);
1667c478bd9Sstevel@tonic-gate 	(void) sigvec(SIGALRM, &sv, (struct sigvec *)0);
1677c478bd9Sstevel@tonic-gate 	if (tstart_writing)
1687c478bd9Sstevel@tonic-gate 		(void) time(tstart_writing);
1697c478bd9Sstevel@tonic-gate 	(void) timeclock(timeclockstate);
1707c478bd9Sstevel@tonic-gate 	in_query_once = 0;
1717c478bd9Sstevel@tonic-gate 	return (back);
1727c478bd9Sstevel@tonic-gate }
1737c478bd9Sstevel@tonic-gate /*
1747c478bd9Sstevel@tonic-gate  *	Alert the console operator, and enable the alarm clock to
1757c478bd9Sstevel@tonic-gate  *	sleep for time += 2 minutes in case nobody comes to satisfy dump
1767c478bd9Sstevel@tonic-gate  *	If the alarm goes off while in the query_once for loop, we just
1777c478bd9Sstevel@tonic-gate  *	longjmp back there and return the default answer.
1787c478bd9Sstevel@tonic-gate  */
1797c478bd9Sstevel@tonic-gate static void
alarmcatch(int signal __unused)180*30699046SRichard Lowe alarmcatch(int signal __unused)
1817c478bd9Sstevel@tonic-gate {
1827c478bd9Sstevel@tonic-gate 	struct sigvec sv;
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	if (in_query_once) {
1857c478bd9Sstevel@tonic-gate 		longjmp(sjalarmbuf, 1);
1867c478bd9Sstevel@tonic-gate 	}
1877c478bd9Sstevel@tonic-gate 	if (timeout) {
1887c478bd9Sstevel@tonic-gate 		msgtail("\n");
1897c478bd9Sstevel@tonic-gate 	}
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	timeout += 120;
1927c478bd9Sstevel@tonic-gate 	msg(gettext("NEEDS ATTENTION: %s"), attnmessage);
1937c478bd9Sstevel@tonic-gate 	sv.sv_handler = alarmcatch;
1947c478bd9Sstevel@tonic-gate 	sv.sv_flags = SA_RESTART;
1957c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&sv.sa_mask);
1967c478bd9Sstevel@tonic-gate 	(void) sigvec(SIGALRM, &sv, (struct sigvec *)0);
1977c478bd9Sstevel@tonic-gate 	(void) alarm(timeout);
1987c478bd9Sstevel@tonic-gate }
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate /*
2017c478bd9Sstevel@tonic-gate  *	Here if an inquisitive operator interrupts the dump program
2027c478bd9Sstevel@tonic-gate  */
2037c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2047c478bd9Sstevel@tonic-gate void
interrupt(int sig)205e0dfa398SToomas Soome interrupt(int sig)
2067c478bd9Sstevel@tonic-gate {
2077c478bd9Sstevel@tonic-gate 	if (!saveattn) {
2087c478bd9Sstevel@tonic-gate 		saveattn = attnmessage;
2097c478bd9Sstevel@tonic-gate 	}
2107c478bd9Sstevel@tonic-gate 	msg(gettext("Interrupt received.\n"));
2117c478bd9Sstevel@tonic-gate 	if (query(gettext(
2127c478bd9Sstevel@tonic-gate 	    "Do you want to abort dump?: (\"yes\" or \"no\") "))) {
2137c478bd9Sstevel@tonic-gate 		dumpabort();
2147c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
2157c478bd9Sstevel@tonic-gate 	}
2167c478bd9Sstevel@tonic-gate 	if (saveattn) {
2177c478bd9Sstevel@tonic-gate 		attnmessage = saveattn;
2187c478bd9Sstevel@tonic-gate 		saveattn = NULL;
219*30699046SRichard Lowe 		alarmcatch(SIGALRM);
2207c478bd9Sstevel@tonic-gate 	}
2217c478bd9Sstevel@tonic-gate }
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate /*
2247c478bd9Sstevel@tonic-gate  *	We use wall(1) to do the actual broadcasting, so
2257c478bd9Sstevel@tonic-gate  *	that we don't have to worry about duplicated code
2267c478bd9Sstevel@tonic-gate  *	only getting fixed in one place.  This also saves
2277c478bd9Sstevel@tonic-gate  *	us from having to worry about process groups,
2287c478bd9Sstevel@tonic-gate  *	controlling terminals, and the like.
2297c478bd9Sstevel@tonic-gate  */
2307c478bd9Sstevel@tonic-gate void
broadcast(char * message)231e0dfa398SToomas Soome broadcast(char *message)
2327c478bd9Sstevel@tonic-gate {
2337c478bd9Sstevel@tonic-gate 	time_t	clock;
2347c478bd9Sstevel@tonic-gate 	pid_t	pid;
2357c478bd9Sstevel@tonic-gate 	int	saverr;
2367c478bd9Sstevel@tonic-gate 	int	fildes[2];
2377c478bd9Sstevel@tonic-gate 	FILE	*wall;
2387c478bd9Sstevel@tonic-gate 	struct tm *localclock;
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	if (!notify)
2417c478bd9Sstevel@tonic-gate 		return;
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	if (pipe(fildes) < 0) {
2447c478bd9Sstevel@tonic-gate 		saverr = errno;
2457c478bd9Sstevel@tonic-gate 		msg(gettext("pipe: %s\n"), strerror(saverr));
2467c478bd9Sstevel@tonic-gate 		return;
2477c478bd9Sstevel@tonic-gate 	}
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	switch (pid = fork()) {
2507c478bd9Sstevel@tonic-gate 	case -1:
2517c478bd9Sstevel@tonic-gate 		return;
2527c478bd9Sstevel@tonic-gate 	case 0:
2537c478bd9Sstevel@tonic-gate 		close(fildes[0]);
2547c478bd9Sstevel@tonic-gate 		if (dup2(fildes[1], 0) < 0) {
2557c478bd9Sstevel@tonic-gate 			saverr = errno;
2567c478bd9Sstevel@tonic-gate 			msg(gettext("dup2: %s\n"), strerror(saverr));
2577c478bd9Sstevel@tonic-gate 			exit(1);
2587c478bd9Sstevel@tonic-gate 		}
2597c478bd9Sstevel@tonic-gate 		execl("/usr/sbin/wall", "wall", "-g", OPGRENT, (char *)NULL);
2607c478bd9Sstevel@tonic-gate 		saverr = errno;
2617c478bd9Sstevel@tonic-gate 		msg(gettext("execl: %s\n"), strerror(saverr));
2627c478bd9Sstevel@tonic-gate 		exit(1);
2637c478bd9Sstevel@tonic-gate 	default:
2647c478bd9Sstevel@tonic-gate 		break;		/* parent */
2657c478bd9Sstevel@tonic-gate 	}
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	close(fildes[1]);
2687c478bd9Sstevel@tonic-gate 	wall = fdopen(fildes[0], "r+");
2697c478bd9Sstevel@tonic-gate 	if (wall == (FILE *)NULL) {
2707c478bd9Sstevel@tonic-gate 		saverr = errno;
2717c478bd9Sstevel@tonic-gate 		msg(gettext("fdopen: %s\n"), strerror(saverr));
2727c478bd9Sstevel@tonic-gate 		return;
2737c478bd9Sstevel@tonic-gate 	}
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	clock = time((time_t *)0);
2767c478bd9Sstevel@tonic-gate 	localclock = localtime(&clock);
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	(void) fprintf(wall, gettext(
2797c478bd9Sstevel@tonic-gate "\n\007\007\007Message from the dump program to all operators at \
2807c478bd9Sstevel@tonic-gate %d:%02d ...\n\n%s"),
2817c478bd9Sstevel@tonic-gate 	    localclock->tm_hour, localclock->tm_min, message);
2827c478bd9Sstevel@tonic-gate 	fclose(wall);
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	while (wait((int *)0) != pid) {
2857c478bd9Sstevel@tonic-gate 		continue;
2867c478bd9Sstevel@tonic-gate 		/*LINTED [empty loop body]*/
2877c478bd9Sstevel@tonic-gate 	}
2887c478bd9Sstevel@tonic-gate }
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate /*
2917c478bd9Sstevel@tonic-gate  *	print out an estimate of the amount of time left to do the dump
2927c478bd9Sstevel@tonic-gate  */
2937c478bd9Sstevel@tonic-gate #define	EST_SEC	600			/* every 10 minutes */
2947c478bd9Sstevel@tonic-gate void
timeest(int force,int blkswritten)295e0dfa398SToomas Soome timeest(int force, int blkswritten)
2967c478bd9Sstevel@tonic-gate {
2977c478bd9Sstevel@tonic-gate 	time_t tnow, deltat;
2987c478bd9Sstevel@tonic-gate 	char *msgp;
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	if (tschedule == NULL)
3017c478bd9Sstevel@tonic-gate 		return;
3027c478bd9Sstevel@tonic-gate 	if (*tschedule == 0)
3037c478bd9Sstevel@tonic-gate 		*tschedule = time((time_t *)0) + EST_SEC;
3047c478bd9Sstevel@tonic-gate 	(void) time(&tnow);
3057c478bd9Sstevel@tonic-gate 	if ((force || tnow >= *tschedule) && blkswritten) {
3067c478bd9Sstevel@tonic-gate 		*tschedule = tnow + EST_SEC;
3077c478bd9Sstevel@tonic-gate 		if (!force && blkswritten < 50 * ntrec)
3087c478bd9Sstevel@tonic-gate 			return;
3097c478bd9Sstevel@tonic-gate 		deltat = (*telapsed + (tnow - *tstart_writing))
310e0dfa398SToomas Soome 		    * ((double)esize / blkswritten - 1.0);
3117c478bd9Sstevel@tonic-gate 		msgp = gettext("%3.2f%% done, finished in %d:%02d\n");
3127c478bd9Sstevel@tonic-gate 		msg(msgp, (blkswritten*100.0)/esize,
313e0dfa398SToomas Soome 		    deltat/3600, (deltat%3600)/60);
3147c478bd9Sstevel@tonic-gate 	}
3157c478bd9Sstevel@tonic-gate }
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate #include <stdarg.h>
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate /* VARARGS1 */
3207c478bd9Sstevel@tonic-gate void
msg(const char * fmt,...)3217c478bd9Sstevel@tonic-gate msg(const char *fmt, ...)
3227c478bd9Sstevel@tonic-gate {
3237c478bd9Sstevel@tonic-gate 	char buf[1024], *cp;
3247c478bd9Sstevel@tonic-gate 	size_t size;
3257c478bd9Sstevel@tonic-gate 	va_list args;
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	va_start(args, fmt);
3287c478bd9Sstevel@tonic-gate 	(void) strcpy(buf, "  DUMP: ");
3297c478bd9Sstevel@tonic-gate 	cp = &buf[strlen(buf)];
3307c478bd9Sstevel@tonic-gate #ifdef TDEBUG
3317c478bd9Sstevel@tonic-gate 	(void) sprintf(cp, "pid=%d ", getpid());
3327c478bd9Sstevel@tonic-gate 	cp = &buf[strlen(buf)];
3337c478bd9Sstevel@tonic-gate #endif
3347c478bd9Sstevel@tonic-gate 	/* don't need -1, vsnprintf does it right */
3357c478bd9Sstevel@tonic-gate 	/* LINTED pointer arithmetic result fits in size_t */
3367c478bd9Sstevel@tonic-gate 	size = ((size_t)sizeof (buf)) - (size_t)(cp - buf);
3377c478bd9Sstevel@tonic-gate 	(void) vsnprintf(cp, size, fmt, args);
3387c478bd9Sstevel@tonic-gate 	(void) fputs(buf, stderr);
3397c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
3407c478bd9Sstevel@tonic-gate 	(void) fflush(stderr);
3417c478bd9Sstevel@tonic-gate 	va_end(args);
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate /* VARARGS1 */
3457c478bd9Sstevel@tonic-gate void
msgtail(const char * fmt,...)3467c478bd9Sstevel@tonic-gate msgtail(const char *fmt, ...)
3477c478bd9Sstevel@tonic-gate {
3487c478bd9Sstevel@tonic-gate 	va_list args;
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	va_start(args, fmt);
3517c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, fmt, args);
3527c478bd9Sstevel@tonic-gate 	va_end(args);
3537c478bd9Sstevel@tonic-gate }
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate #define	MINUTES(x)	((x) * 60)
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate /*
3587c478bd9Sstevel@tonic-gate  *	Tell the operator what has to be done;
3597c478bd9Sstevel@tonic-gate  *	we don't actually do it
3607c478bd9Sstevel@tonic-gate  */
3617c478bd9Sstevel@tonic-gate void
lastdump(int arg)362e0dfa398SToomas Soome lastdump(int arg)	/* w ==> just what to do; W ==> most recent dumps */
3637c478bd9Sstevel@tonic-gate {
3647c478bd9Sstevel@tonic-gate 	char *lastname;
3657c478bd9Sstevel@tonic-gate 	char *date;
3667c478bd9Sstevel@tonic-gate 	int i;
3677c478bd9Sstevel@tonic-gate 	time_t tnow, ddate;
3687c478bd9Sstevel@tonic-gate 	struct mntent *dt;
3697c478bd9Sstevel@tonic-gate 	int dumpme = 0;
3707c478bd9Sstevel@tonic-gate 	struct idates *itwalk;
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	(void) time(&tnow);
3737c478bd9Sstevel@tonic-gate 	mnttabread();		/* /etc/fstab input */
3747c478bd9Sstevel@tonic-gate 	inititimes();		/* /etc/dumpdates input */
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	/* Don't use msg(), this isn't a tell-the-world kind of thing */
3777c478bd9Sstevel@tonic-gate 	if (arg == 'w')
3787c478bd9Sstevel@tonic-gate 		(void) fprintf(stdout, gettext("Dump these file systems:\n"));
3797c478bd9Sstevel@tonic-gate 	else
3807c478bd9Sstevel@tonic-gate 		(void) fprintf(stdout, gettext(
3817c478bd9Sstevel@tonic-gate 		    "Last dump(s) done (Dump '>' file systems):\n"));
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	if (idatev != NULL) {
3847c478bd9Sstevel@tonic-gate 		qsort((char *)idatev, nidates, sizeof (*idatev), idatesort);
3857c478bd9Sstevel@tonic-gate 		lastname = "??";
3867c478bd9Sstevel@tonic-gate 		ITITERATE(i, itwalk) {
3877c478bd9Sstevel@tonic-gate 			if (strncmp(lastname, itwalk->id_name,
3887c478bd9Sstevel@tonic-gate 			    sizeof (itwalk->id_name)) == 0)
3897c478bd9Sstevel@tonic-gate 				continue;
390bbf21555SRichard Lowe 			/* must be ctime(), per ufsdump(5) */
3917c478bd9Sstevel@tonic-gate 			ddate = itwalk->id_ddate;
3927c478bd9Sstevel@tonic-gate 			date = (char *)ctime(&ddate);
3937c478bd9Sstevel@tonic-gate 			date[16] = '\0';	/* blow away seconds and year */
3947c478bd9Sstevel@tonic-gate 			lastname = itwalk->id_name;
3957c478bd9Sstevel@tonic-gate 			dt = mnttabsearch(itwalk->id_name, 0);
3967c478bd9Sstevel@tonic-gate 			if ((time_t)(itwalk->id_ddate) < (tnow - DAY)) {
3977c478bd9Sstevel@tonic-gate 				dumpme = 1;
3987c478bd9Sstevel@tonic-gate 			}
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 			if ((arg == 'w') && dumpme) {
4017c478bd9Sstevel@tonic-gate 				/*
4027c478bd9Sstevel@tonic-gate 				 * Handle the w option: print out file systems
4037c478bd9Sstevel@tonic-gate 				 * which haven't been backed up within a day.
4047c478bd9Sstevel@tonic-gate 				 */
4057c478bd9Sstevel@tonic-gate 				(void) printf(gettext("%8s\t(%6s)\n"),
4067c478bd9Sstevel@tonic-gate 				    itwalk->id_name, dt ? dt->mnt_dir : "");
4077c478bd9Sstevel@tonic-gate 			}
4087c478bd9Sstevel@tonic-gate 			if (arg == 'W') {
4097c478bd9Sstevel@tonic-gate 				/*
4107c478bd9Sstevel@tonic-gate 				 * Handle the W option: print out ALL
4117c478bd9Sstevel@tonic-gate 				 * filesystems including recent dump dates and
4127c478bd9Sstevel@tonic-gate 				 * dump levels.  Mark the backup-needing
4137c478bd9Sstevel@tonic-gate 				 * filesystems with a >.
4147c478bd9Sstevel@tonic-gate 				 */
4157c478bd9Sstevel@tonic-gate 				(void) printf(gettext(
4167c478bd9Sstevel@tonic-gate 			    "%c %8s\t(%6s) Last dump: Level %c, Date %s\n"),
4177c478bd9Sstevel@tonic-gate 				    dumpme ? '>' : ' ',
4187c478bd9Sstevel@tonic-gate 				    itwalk->id_name,
4197c478bd9Sstevel@tonic-gate 				    dt ? dt->mnt_dir : "",
4207c478bd9Sstevel@tonic-gate 				    (uchar_t)itwalk->id_incno,
4217c478bd9Sstevel@tonic-gate 				    date);
4227c478bd9Sstevel@tonic-gate 			}
4237c478bd9Sstevel@tonic-gate 			dumpme = 0;
4247c478bd9Sstevel@tonic-gate 		}
4257c478bd9Sstevel@tonic-gate 	}
4267c478bd9Sstevel@tonic-gate }
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate static int
idatesort(const void * v1,const void * v2)429e0dfa398SToomas Soome idatesort(const void *v1, const void *v2)
4307c478bd9Sstevel@tonic-gate {
4317c478bd9Sstevel@tonic-gate 	struct idates **p1 = (struct idates **)v1;
4327c478bd9Sstevel@tonic-gate 	struct idates **p2 = (struct idates **)v2;
4337c478bd9Sstevel@tonic-gate 	int diff;
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	diff = strcoll((*p1)->id_name, (*p2)->id_name);
4367c478bd9Sstevel@tonic-gate 	if (diff == 0) {
4377c478bd9Sstevel@tonic-gate 		/*
4387c478bd9Sstevel@tonic-gate 		 * Time may eventually become unsigned, so can't
4397c478bd9Sstevel@tonic-gate 		 * rely on subtraction to give a useful result.
4407c478bd9Sstevel@tonic-gate 		 * Note that we are sorting dates into reverse
4417c478bd9Sstevel@tonic-gate 		 * order, so that we will report based on the
4427c478bd9Sstevel@tonic-gate 		 * most-recent record for a particular filesystem.
4437c478bd9Sstevel@tonic-gate 		 */
4447c478bd9Sstevel@tonic-gate 		if ((*p1)->id_ddate > (*p2)->id_ddate)
4457c478bd9Sstevel@tonic-gate 			diff = -1;
4467c478bd9Sstevel@tonic-gate 		else if ((*p1)->id_ddate < (*p2)->id_ddate)
4477c478bd9Sstevel@tonic-gate 			diff = 1;
4487c478bd9Sstevel@tonic-gate 	}
4497c478bd9Sstevel@tonic-gate 	return (diff);
4507c478bd9Sstevel@tonic-gate }
451