xref: /onnv-gate/usr/src/cmd/backup/dump/dumponline.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright (c) 1991,1996,1998 by Sun Microsystems, Inc.
24*0Sstevel@tonic-gate  * All rights reserved.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include "dump.h"
30*0Sstevel@tonic-gate #include <math.h>
31*0Sstevel@tonic-gate #include <limits.h>
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate /*
34*0Sstevel@tonic-gate  * Uncomment if using mmap'ing of files for pre-fetch.
35*0Sstevel@tonic-gate  * #define ENABLE_MMAP 1
36*0Sstevel@tonic-gate  */
37*0Sstevel@tonic-gate 
38*0Sstevel@tonic-gate struct inodesc {
39*0Sstevel@tonic-gate 	ino_t	id_inumber;		/* inode number */
40*0Sstevel@tonic-gate 	long	id_gen;			/* generation number */
41*0Sstevel@tonic-gate 	struct inodesc *id_next;	/* next on linked list */
42*0Sstevel@tonic-gate };
43*0Sstevel@tonic-gate 
44*0Sstevel@tonic-gate static struct inodesc	ilist;		/* list of used inodesc structs */
45*0Sstevel@tonic-gate static struct inodesc	*last;		/* last inodesc init'd or matched */
46*0Sstevel@tonic-gate static struct inodesc	*freeinodesc;	/* free list of inodesc structs */
47*0Sstevel@tonic-gate static struct inodesc	**ialloc;	/* allocated chunks, for freeing */
48*0Sstevel@tonic-gate static int		nchunks;	/* number of allocations */
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate #ifdef ENABLE_MMAP /* XXX part of mmap support */
51*0Sstevel@tonic-gate /*
52*0Sstevel@tonic-gate  * If an mmap'ed file is truncated as it is being dumped or
53*0Sstevel@tonic-gate  * faulted in, we are delivered a SIGBUS.
54*0Sstevel@tonic-gate  */
55*0Sstevel@tonic-gate static jmp_buf	truncate_buf;
56*0Sstevel@tonic-gate static void	(*savebus)();
57*0Sstevel@tonic-gate static int	incopy;
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate #ifdef __STDC__
60*0Sstevel@tonic-gate static void onsigbus(int);
61*0Sstevel@tonic-gate #else
62*0Sstevel@tonic-gate static void onsigbus();
63*0Sstevel@tonic-gate #endif
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate #endif	/* ENABLE_MMAP */
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate #ifdef DEBUG
68*0Sstevel@tonic-gate extern int xflag;
69*0Sstevel@tonic-gate #endif
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate #ifdef ENABLE_MMAP /* XXX part of mmap support */
72*0Sstevel@tonic-gate static void
onsigbus(sig)73*0Sstevel@tonic-gate onsigbus(sig)
74*0Sstevel@tonic-gate 	int	sig;
75*0Sstevel@tonic-gate {
76*0Sstevel@tonic-gate 	if (!incopy) {
77*0Sstevel@tonic-gate 		dumpabort();
78*0Sstevel@tonic-gate 		/*NOTREACHED*/
79*0Sstevel@tonic-gate 	}
80*0Sstevel@tonic-gate 	incopy = 0;
81*0Sstevel@tonic-gate 	longjmp(truncate_buf, 1);
82*0Sstevel@tonic-gate 	/*NOTREACHED*/
83*0Sstevel@tonic-gate }
84*0Sstevel@tonic-gate #endif	/* ENABLE_MMAP */
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate void
87*0Sstevel@tonic-gate #ifdef __STDC__
allocino(void)88*0Sstevel@tonic-gate allocino(void)
89*0Sstevel@tonic-gate #else
90*0Sstevel@tonic-gate allocino()
91*0Sstevel@tonic-gate #endif
92*0Sstevel@tonic-gate {
93*0Sstevel@tonic-gate 	ino_t maxino;
94*0Sstevel@tonic-gate 	size_t nused;
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate 	maxino = (unsigned)(sblock->fs_ipg * sblock->fs_ncg);
97*0Sstevel@tonic-gate 	if (maxino > ULONG_MAX) {
98*0Sstevel@tonic-gate 		msg(gettext("allocino: filesystem too large\n"));
99*0Sstevel@tonic-gate 		dumpabort();
100*0Sstevel@tonic-gate 		/*NOTREACHED*/
101*0Sstevel@tonic-gate 	}
102*0Sstevel@tonic-gate 	/* LINTED maxino guaranteed to fit into a size_t by above test */
103*0Sstevel@tonic-gate 	nused =  maxino - sblock->fs_cstotal.cs_nifree;
104*0Sstevel@tonic-gate 	freeinodesc = (struct inodesc *)xcalloc(nused, sizeof (*freeinodesc));
105*0Sstevel@tonic-gate 	if (freeinodesc == (struct inodesc *)0) {
106*0Sstevel@tonic-gate 		msg(gettext("%s: out of memory\n"), "allocino");
107*0Sstevel@tonic-gate 		dumpabort();
108*0Sstevel@tonic-gate 		/*NOTREACHED*/
109*0Sstevel@tonic-gate 	}
110*0Sstevel@tonic-gate 	last = &ilist;
111*0Sstevel@tonic-gate 	ialloc =
112*0Sstevel@tonic-gate 	    (struct inodesc **)xmalloc(2*sizeof (*ialloc));
113*0Sstevel@tonic-gate 	ialloc[0] = freeinodesc;
114*0Sstevel@tonic-gate 	ialloc[1] = (struct inodesc *)0;
115*0Sstevel@tonic-gate 	nchunks = 1;
116*0Sstevel@tonic-gate }
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate void
119*0Sstevel@tonic-gate #ifdef __STDC__
freeino(void)120*0Sstevel@tonic-gate freeino(void)
121*0Sstevel@tonic-gate #else
122*0Sstevel@tonic-gate freeino()
123*0Sstevel@tonic-gate #endif
124*0Sstevel@tonic-gate {
125*0Sstevel@tonic-gate 	int i;
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate 	if (ialloc == (struct inodesc **)0)
128*0Sstevel@tonic-gate 		return;
129*0Sstevel@tonic-gate 	for (i = 0; i < nchunks; i++)
130*0Sstevel@tonic-gate 		if (ialloc[i] != 0)
131*0Sstevel@tonic-gate 			free(ialloc[i]);
132*0Sstevel@tonic-gate 	free(ialloc);
133*0Sstevel@tonic-gate 	ialloc = (struct inodesc **)0;
134*0Sstevel@tonic-gate }
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate void
resetino(ino)137*0Sstevel@tonic-gate resetino(ino)
138*0Sstevel@tonic-gate 	ino_t	ino;
139*0Sstevel@tonic-gate {
140*0Sstevel@tonic-gate 	last = ilist.id_next;
141*0Sstevel@tonic-gate 	while (last && last->id_inumber < ino)
142*0Sstevel@tonic-gate 		last = last->id_next;
143*0Sstevel@tonic-gate }
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate char *
unrawname(cp)146*0Sstevel@tonic-gate unrawname(cp)
147*0Sstevel@tonic-gate 	char *cp;
148*0Sstevel@tonic-gate {
149*0Sstevel@tonic-gate 	char *dp;
150*0Sstevel@tonic-gate 	extern char *getfullblkname();
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 	dp = getfullblkname(cp);
153*0Sstevel@tonic-gate 	if (dp == 0)
154*0Sstevel@tonic-gate 		return (0);
155*0Sstevel@tonic-gate 	if (*dp == '\0') {
156*0Sstevel@tonic-gate 		free(dp);
157*0Sstevel@tonic-gate 		return (0);
158*0Sstevel@tonic-gate 	}
159*0Sstevel@tonic-gate 	if (dp == cp)		/* caller wants to always free() dp */
160*0Sstevel@tonic-gate 		dp = strdup(cp);
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 	return (dp);
163*0Sstevel@tonic-gate }
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate /*
166*0Sstevel@tonic-gate  * Determine if specified device is mounted at
167*0Sstevel@tonic-gate  * specified mount point.  Returns 1 if mounted,
168*0Sstevel@tonic-gate  * 0 if not mounted, -1 on error.
169*0Sstevel@tonic-gate  */
170*0Sstevel@tonic-gate int
lf_ismounted(devname,dirname)171*0Sstevel@tonic-gate lf_ismounted(devname, dirname)
172*0Sstevel@tonic-gate 	char	*devname;	/* name of device (raw or block) */
173*0Sstevel@tonic-gate 	char	*dirname;	/* name of f/s mount point */
174*0Sstevel@tonic-gate {
175*0Sstevel@tonic-gate 	struct stat64 st;
176*0Sstevel@tonic-gate 	char	*blockname;	/* name of block device */
177*0Sstevel@tonic-gate 	dev_t	dev;
178*0Sstevel@tonic-gate 	int	saverr;
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 	if ((blockname = unrawname(devname)) == NULL) {
181*0Sstevel@tonic-gate 		msg(gettext("Cannot obtain block name from `%s'\n"), devname);
182*0Sstevel@tonic-gate 		return (-1);
183*0Sstevel@tonic-gate 	}
184*0Sstevel@tonic-gate 	if (stat64(blockname, &st) < 0) {
185*0Sstevel@tonic-gate 		saverr = errno;
186*0Sstevel@tonic-gate 		msg(gettext("Cannot obtain status of device `%s': %s\n"),
187*0Sstevel@tonic-gate 		    blockname, strerror(saverr));
188*0Sstevel@tonic-gate 		free(blockname);
189*0Sstevel@tonic-gate 		return (-1);
190*0Sstevel@tonic-gate 	}
191*0Sstevel@tonic-gate 	free(blockname);
192*0Sstevel@tonic-gate 	dev = st.st_rdev;
193*0Sstevel@tonic-gate 	if (stat64(dirname, &st) < 0) {
194*0Sstevel@tonic-gate 		saverr = errno;
195*0Sstevel@tonic-gate 		msg(gettext("Cannot obtain status of device `%s': %s\n"),
196*0Sstevel@tonic-gate 		    dirname, strerror(saverr));
197*0Sstevel@tonic-gate 		return (-1);
198*0Sstevel@tonic-gate 	}
199*0Sstevel@tonic-gate 	if (dev == st.st_dev)
200*0Sstevel@tonic-gate 		return (1);
201*0Sstevel@tonic-gate 	return (0);
202*0Sstevel@tonic-gate }
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate #ifdef ENABLE_MMAP /* XXX mapped-file support */
205*0Sstevel@tonic-gate #define	MINMAPSIZE	1024*1024
206*0Sstevel@tonic-gate #define	MAXMAPSIZE	1024*1024*32
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate static caddr_t	mapbase;	/* base of mapped data */
209*0Sstevel@tonic-gate static caddr_t	mapend;		/* last byte of mapped data */
210*0Sstevel@tonic-gate static size_t	mapsize;	/* amount of mapped data */
211*0Sstevel@tonic-gate /*
212*0Sstevel@tonic-gate  * Map a file prior to dumping and start faulting in its
213*0Sstevel@tonic-gate  * pages.  Stop if we catch a signal indicating our turn
214*0Sstevel@tonic-gate  * to dump has arrived.  If the file is truncated out from
215*0Sstevel@tonic-gate  * under us, immediately return.
216*0Sstevel@tonic-gate  * NB:  the base of the mapped data may not coincide
217*0Sstevel@tonic-gate  * exactly to the requested offset, due to alignment
218*0Sstevel@tonic-gate  * constraints.
219*0Sstevel@tonic-gate  */
220*0Sstevel@tonic-gate caddr_t
mapfile(fd,offset,bytes,fetch)221*0Sstevel@tonic-gate mapfile(fd, offset, bytes, fetch)
222*0Sstevel@tonic-gate 	int	fd;
223*0Sstevel@tonic-gate 	off_t	offset;		/* offset within file */
224*0Sstevel@tonic-gate 	off_t	bytes;		/* number of bytes to map */
225*0Sstevel@tonic-gate 	int	fetch;		/* start faulting in pages */
226*0Sstevel@tonic-gate {
227*0Sstevel@tonic-gate 	/*LINTED [c used during pre-fetch faulting]*/
228*0Sstevel@tonic-gate 	volatile char c, *p;
229*0Sstevel@tonic-gate 	int stride = (int)sysconf(_SC_PAGESIZE);
230*0Sstevel@tonic-gate 	extern int caught;		/* pre-fetch until set */
231*0Sstevel@tonic-gate 	caddr_t	mapstart;		/* beginning of file's mapped data */
232*0Sstevel@tonic-gate 	off_t	mapoffset;		/* page-aligned offset */
233*0Sstevel@tonic-gate 	int	saverr;
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate 	mapbase = mapend = (caddr_t)0;
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate 	if (bytes == 0)
238*0Sstevel@tonic-gate 		return ((caddr_t)0);
239*0Sstevel@tonic-gate 	/*
240*0Sstevel@tonic-gate 	 * mmap the file for reading
241*0Sstevel@tonic-gate 	 */
242*0Sstevel@tonic-gate 	mapoffset = offset & ~(stride - 1);
243*0Sstevel@tonic-gate 	/* LINTED: "bytes" will always fit into a size_t */
244*0Sstevel@tonic-gate 	mapsize = bytes + (offset - mapoffset);
245*0Sstevel@tonic-gate 	if (mapsize > MAXMAPSIZE)
246*0Sstevel@tonic-gate 		mapsize = MAXMAPSIZE;
247*0Sstevel@tonic-gate 	while ((mapbase = mmap((caddr_t)0, mapsize, PROT_READ,
248*0Sstevel@tonic-gate 	    MAP_SHARED, fd, mapoffset)) == (caddr_t)-1 &&
249*0Sstevel@tonic-gate 	    errno == ENOMEM && mapsize >= MINMAPSIZE) {
250*0Sstevel@tonic-gate 		/*
251*0Sstevel@tonic-gate 		 * Due to address space limitations, we
252*0Sstevel@tonic-gate 		 * may not be able to map as much as we want.
253*0Sstevel@tonic-gate 		 */
254*0Sstevel@tonic-gate 		mapsize /= 2;	/* exponential back-off */
255*0Sstevel@tonic-gate 	}
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate 	if (mapbase == (caddr_t)-1) {
258*0Sstevel@tonic-gate 		saverr = errno;
259*0Sstevel@tonic-gate 		msg(gettext("Cannot map file at inode `%lu' into memory: %s\n"),
260*0Sstevel@tonic-gate 			ino, strerror(saverr));
261*0Sstevel@tonic-gate 		/* XXX why not call dumpailing() here? */
262*0Sstevel@tonic-gate 		if (!query(gettext(
263*0Sstevel@tonic-gate 	    "Do you want to attempt to continue? (\"yes\" or \"no\") "))) {
264*0Sstevel@tonic-gate 			dumpabort();
265*0Sstevel@tonic-gate 			/*NOTREACHED*/
266*0Sstevel@tonic-gate 		}
267*0Sstevel@tonic-gate 		mapbase = (caddr_t)0;
268*0Sstevel@tonic-gate 		return ((caddr_t)0);
269*0Sstevel@tonic-gate 	}
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate 	(void) madvise(mapbase, mapsize, MADV_SEQUENTIAL);
272*0Sstevel@tonic-gate 	mapstart = mapbase + (offset - mapoffset);
273*0Sstevel@tonic-gate 	mapend = mapbase + (mapsize - 1);
274*0Sstevel@tonic-gate 
275*0Sstevel@tonic-gate 	if (!fetch)
276*0Sstevel@tonic-gate 		return (mapstart);
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 	if (setjmp(truncate_buf) == 0) {
279*0Sstevel@tonic-gate 		savebus = signal(SIGBUS, onsigbus);
280*0Sstevel@tonic-gate 		/*
281*0Sstevel@tonic-gate 		 * Touch each page to pre-fetch by faulting.  At least
282*0Sstevel@tonic-gate 		 * one of c or *p must be declared volatile, lest the
283*0Sstevel@tonic-gate 		 * optimizer eliminate the assignment in the loop.
284*0Sstevel@tonic-gate 		 */
285*0Sstevel@tonic-gate 		incopy = 1;
286*0Sstevel@tonic-gate 		for (p = mapbase; !caught && p <= mapend; p += stride) {
287*0Sstevel@tonic-gate 			/* LINTED: c is used for its side-effects */
288*0Sstevel@tonic-gate 			c = *p;
289*0Sstevel@tonic-gate 		}
290*0Sstevel@tonic-gate 		incopy = 0;
291*0Sstevel@tonic-gate 	}
292*0Sstevel@tonic-gate #ifdef DEBUG
293*0Sstevel@tonic-gate 	else
294*0Sstevel@tonic-gate 		/* XGETTEXT:  #ifdef DEBUG only */
295*0Sstevel@tonic-gate 		msg(gettext(
296*0Sstevel@tonic-gate 			"FILE TRUNCATED (fault): Interrupting pre-fetch\n"));
297*0Sstevel@tonic-gate #endif
298*0Sstevel@tonic-gate 	(void) signal(SIGBUS, savebus);
299*0Sstevel@tonic-gate 	return (mapstart);
300*0Sstevel@tonic-gate }
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate void
303*0Sstevel@tonic-gate #ifdef __STDC__
unmapfile(void)304*0Sstevel@tonic-gate unmapfile(void)
305*0Sstevel@tonic-gate #else
306*0Sstevel@tonic-gate unmapfile()
307*0Sstevel@tonic-gate #endif
308*0Sstevel@tonic-gate {
309*0Sstevel@tonic-gate 	if (mapbase) {
310*0Sstevel@tonic-gate 		/* XXX we're unmapping it, so what does this gain us? */
311*0Sstevel@tonic-gate 		(void) msync(mapbase, mapsize, MS_ASYNC|MS_INVALIDATE);
312*0Sstevel@tonic-gate 		(void) munmap(mapbase, mapsize);
313*0Sstevel@tonic-gate 		mapbase = (caddr_t)0;
314*0Sstevel@tonic-gate 	}
315*0Sstevel@tonic-gate }
316*0Sstevel@tonic-gate #endif	/* ENABLE_MMAP */
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate void
319*0Sstevel@tonic-gate #ifdef __STDC__
activepass(void)320*0Sstevel@tonic-gate activepass(void)
321*0Sstevel@tonic-gate #else
322*0Sstevel@tonic-gate activepass()
323*0Sstevel@tonic-gate #endif
324*0Sstevel@tonic-gate {
325*0Sstevel@tonic-gate 	static int passno = 1;			/* active file pass number */
326*0Sstevel@tonic-gate 	char *ext, *old;
327*0Sstevel@tonic-gate 	char buf[3000];
328*0Sstevel@tonic-gate 	static char defext[] = ".retry";
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate 	if (pipeout) {
331*0Sstevel@tonic-gate 		msg(gettext("Cannot re-dump active files to `%s'\n"), tape);
332*0Sstevel@tonic-gate 		dumpabort();
333*0Sstevel@tonic-gate 		/*NOTREACHED*/
334*0Sstevel@tonic-gate 	}
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate 	if (active > 1)
337*0Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), gettext(
338*0Sstevel@tonic-gate 		    "%d files were active and will be re-dumped\n"), active);
339*0Sstevel@tonic-gate 	else
340*0Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), gettext(
341*0Sstevel@tonic-gate 		    "1 file was active and will be re-dumped\n"));
342*0Sstevel@tonic-gate 	msg(buf);
343*0Sstevel@tonic-gate 
344*0Sstevel@tonic-gate 	doingactive++;
345*0Sstevel@tonic-gate 	active = 0;
346*0Sstevel@tonic-gate 	reset();			/* reset tape params */
347*0Sstevel@tonic-gate 	spcl.c_ddate = spcl.c_date;	/* chain with last dump/pass */
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 	/*
350*0Sstevel@tonic-gate 	 * If archiving, create a new
351*0Sstevel@tonic-gate 	 * archive file.
352*0Sstevel@tonic-gate 	 */
353*0Sstevel@tonic-gate 	if (archivefile) {
354*0Sstevel@tonic-gate 		old = archivefile;
355*0Sstevel@tonic-gate 
356*0Sstevel@tonic-gate 		ext = strstr(old, defext);
357*0Sstevel@tonic-gate 		if (ext != (char *)NULL)
358*0Sstevel@tonic-gate 			*ext = '\0'; /* just want the base name */
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 		/* The two is for the trailing \0 and rounding up log10() */
361*0Sstevel@tonic-gate 		archivefile = xmalloc(strlen(old) + strlen(defext) +
362*0Sstevel@tonic-gate 		    (int)log10((double)passno) + 2);
363*0Sstevel@tonic-gate 
364*0Sstevel@tonic-gate 		/* Always fits */
365*0Sstevel@tonic-gate 		(void) sprintf(archivefile, "%s%s%d", old, defext, passno);
366*0Sstevel@tonic-gate 		free(old);
367*0Sstevel@tonic-gate 	}
368*0Sstevel@tonic-gate 
369*0Sstevel@tonic-gate 	if (tapeout) {
370*0Sstevel@tonic-gate 		if (isrewind(to)) {
371*0Sstevel@tonic-gate 			/*
372*0Sstevel@tonic-gate 			 * A "rewind" tape device.  When we do
373*0Sstevel@tonic-gate 			 * the close, we will lose our position.
374*0Sstevel@tonic-gate 			 * Be nice and switch volumes.
375*0Sstevel@tonic-gate 			 */
376*0Sstevel@tonic-gate 			(void) snprintf(buf, sizeof (buf), gettext(
377*0Sstevel@tonic-gate 		"Warning - cannot dump active files to rewind device `%s'\n"),
378*0Sstevel@tonic-gate 				tape);
379*0Sstevel@tonic-gate 			msg(buf);
380*0Sstevel@tonic-gate 			close_rewind();
381*0Sstevel@tonic-gate 			changevol();
382*0Sstevel@tonic-gate 		} else {
383*0Sstevel@tonic-gate 			trewind();
384*0Sstevel@tonic-gate 			doposition = 0;
385*0Sstevel@tonic-gate 			filenum++;
386*0Sstevel@tonic-gate 		}
387*0Sstevel@tonic-gate 	} else {
388*0Sstevel@tonic-gate 		/*
389*0Sstevel@tonic-gate 		 * Not a tape.  Do a volume switch.
390*0Sstevel@tonic-gate 		 * This will advance to the next file
391*0Sstevel@tonic-gate 		 * if using a sequence of files, next
392*0Sstevel@tonic-gate 		 * diskette if using diskettes, or
393*0Sstevel@tonic-gate 		 * let the user move the old file out
394*0Sstevel@tonic-gate 		 * of the way.
395*0Sstevel@tonic-gate 		 */
396*0Sstevel@tonic-gate 		close_rewind();
397*0Sstevel@tonic-gate 		changevol();	/* switch files */
398*0Sstevel@tonic-gate 	}
399*0Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), gettext(
400*0Sstevel@tonic-gate 	    "Dumping active files (retry pass %d) to `%s'\n"), passno, tape);
401*0Sstevel@tonic-gate 	msg(buf);
402*0Sstevel@tonic-gate 	passno++;
403*0Sstevel@tonic-gate }
404