xref: /titanic_50/usr/src/cmd/backup/dump/dumptape.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
28*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved	*/
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate /*
31*7c478bd9Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley 4.3 BSD
32*7c478bd9Sstevel@tonic-gate  * under license from the Regents of the University of California.
33*7c478bd9Sstevel@tonic-gate  */
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate #include "dump.h"
38*7c478bd9Sstevel@tonic-gate #include <rmt.h>
39*7c478bd9Sstevel@tonic-gate #include <setjmp.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/fdio.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
42*7c478bd9Sstevel@tonic-gate #include <assert.h>
43*7c478bd9Sstevel@tonic-gate #include <limits.h>
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate #define	SLEEPMS		50
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate static uint_t writesize;	/* size of malloc()ed buffer for tape */
48*7c478bd9Sstevel@tonic-gate static ino_t inos[TP_NINOS];	/* starting inodes on each tape */
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate /*
51*7c478bd9Sstevel@tonic-gate  * The req structure is used to pass commands from the parent
52*7c478bd9Sstevel@tonic-gate  * process through the pipes to the slave processes.  It comes
53*7c478bd9Sstevel@tonic-gate  * in two flavors, depending on which mode dump is operating under:
54*7c478bd9Sstevel@tonic-gate  * an inode request (on-line mode) and a disk block request ("old" mode).
55*7c478bd9Sstevel@tonic-gate  */
56*7c478bd9Sstevel@tonic-gate /*
57*7c478bd9Sstevel@tonic-gate  * The inode request structure is used during on-line mode.
58*7c478bd9Sstevel@tonic-gate  * The master passes inode numbers and starting offsets to
59*7c478bd9Sstevel@tonic-gate  * the slaves.  The tape writer passes out the current inode,
60*7c478bd9Sstevel@tonic-gate  * offset, and number of tape records written after completing a volume.
61*7c478bd9Sstevel@tonic-gate  */
62*7c478bd9Sstevel@tonic-gate struct ireq {
63*7c478bd9Sstevel@tonic-gate 	ino_t	inumber;	/* inode number to open/dump */
64*7c478bd9Sstevel@tonic-gate 	long	igen;		/* inode generation number */
65*7c478bd9Sstevel@tonic-gate 	off_t	offset;		/* starting offset in inode */
66*7c478bd9Sstevel@tonic-gate 	int	count;		/* count for 1st spclrec */
67*7c478bd9Sstevel@tonic-gate };
68*7c478bd9Sstevel@tonic-gate /*
69*7c478bd9Sstevel@tonic-gate  * The block request structure is used in off-line mode to pass
70*7c478bd9Sstevel@tonic-gate  * commands to dump disk blocks from the parent process through
71*7c478bd9Sstevel@tonic-gate  * the pipes to the slave processes.
72*7c478bd9Sstevel@tonic-gate  */
73*7c478bd9Sstevel@tonic-gate struct breq {
74*7c478bd9Sstevel@tonic-gate 	diskaddr_t dblk;		/* disk address to read */
75*7c478bd9Sstevel@tonic-gate 	size_t	size;		/* number of bytes to read from disk */
76*7c478bd9Sstevel@tonic-gate 	ulong_t	spclrec[1];	/* actually longer */
77*7c478bd9Sstevel@tonic-gate };
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate struct req {
80*7c478bd9Sstevel@tonic-gate 	short	aflag;		/* write data to archive process as well */
81*7c478bd9Sstevel@tonic-gate 	short	tflag;		/* begin new tape */
82*7c478bd9Sstevel@tonic-gate 	union	reqdata {
83*7c478bd9Sstevel@tonic-gate 		struct ireq ino;	/* used for on-line mode */
84*7c478bd9Sstevel@tonic-gate 		struct breq blks;	/* used for off-line mode */
85*7c478bd9Sstevel@tonic-gate 	} data;
86*7c478bd9Sstevel@tonic-gate };
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate #define	ir_inumber	data.ino.inumber
89*7c478bd9Sstevel@tonic-gate #define	ir_igen		data.ino.igen
90*7c478bd9Sstevel@tonic-gate #define	ir_offset	data.ino.offset
91*7c478bd9Sstevel@tonic-gate #define	ir_count	data.ino.count
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate #define	br_dblk		data.blks.dblk
94*7c478bd9Sstevel@tonic-gate #define	br_size		data.blks.size
95*7c478bd9Sstevel@tonic-gate #define	br_spcl		data.blks.spclrec
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate static int reqsiz = 0;	/* alloctape will initialize */
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate #define	SLAVES 3
100*7c478bd9Sstevel@tonic-gate struct slaves {
101*7c478bd9Sstevel@tonic-gate 	int	sl_slavefd;	/* pipe from master to slave */
102*7c478bd9Sstevel@tonic-gate 	pid_t	sl_slavepid;	/* slave pid; used by killall() */
103*7c478bd9Sstevel@tonic-gate 	ino_t	sl_inos;	/* inos, if this record starts tape */
104*7c478bd9Sstevel@tonic-gate 	int	sl_offset;	/* logical blocks written for object */
105*7c478bd9Sstevel@tonic-gate 	int	sl_count;	/* logical blocks left in spclrec */
106*7c478bd9Sstevel@tonic-gate 	int	sl_tapea;	/* header number, if starting tape */
107*7c478bd9Sstevel@tonic-gate 	int	sl_firstrec;	/* number of first block on tape */
108*7c478bd9Sstevel@tonic-gate 	int	sl_state;	/* dump output state */
109*7c478bd9Sstevel@tonic-gate 	struct	req *sl_req;	/* instruction packet to slave */
110*7c478bd9Sstevel@tonic-gate };
111*7c478bd9Sstevel@tonic-gate static struct slaves slaves[SLAVES];	/* one per slave */
112*7c478bd9Sstevel@tonic-gate static struct slaves *slp;	/* pointer to current slave */
113*7c478bd9Sstevel@tonic-gate static struct slaves chkpt;	/* checkpointed data */
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate struct bdesc {
116*7c478bd9Sstevel@tonic-gate 	char	*b_data;	/* pointer to buffer data */
117*7c478bd9Sstevel@tonic-gate 	int	b_flags;	/* flags (see below) */
118*7c478bd9Sstevel@tonic-gate };
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate /*
121*7c478bd9Sstevel@tonic-gate  * The following variables are in shared memory, and must be
122*7c478bd9Sstevel@tonic-gate  * explicitly checkpointed and/or reset.
123*7c478bd9Sstevel@tonic-gate  */
124*7c478bd9Sstevel@tonic-gate static caddr_t shared;		/* pointer to block of shared memory */
125*7c478bd9Sstevel@tonic-gate static struct bdesc *bufp;	/* buffer descriptors */
126*7c478bd9Sstevel@tonic-gate static struct bdesc **current;	/* output buffer to fill */
127*7c478bd9Sstevel@tonic-gate static int *tapea;		/* logical record count */
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate #ifdef INSTRUMENT
130*7c478bd9Sstevel@tonic-gate static int	*readmissp;	/* number of times writer was idle */
131*7c478bd9Sstevel@tonic-gate static int	*idle;		/* number of times slaves were idle */
132*7c478bd9Sstevel@tonic-gate #endif	/* INSTRUMENT */
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate /*
135*7c478bd9Sstevel@tonic-gate  * Buffer flags
136*7c478bd9Sstevel@tonic-gate  */
137*7c478bd9Sstevel@tonic-gate #define	BUF_EMPTY	0x0	/* nothing in buffer */
138*7c478bd9Sstevel@tonic-gate #define	BUF_FULL	0x1	/* data in buffer */
139*7c478bd9Sstevel@tonic-gate #define	BUF_SPCLREC	0x2	/* contains special record */
140*7c478bd9Sstevel@tonic-gate #define	BUF_ARCHIVE	0x4	/* dump to archive */
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate static int recsout;		/* number of req's sent to slaves */
143*7c478bd9Sstevel@tonic-gate static int totalrecsout;	/* total number of req's sent to slaves */
144*7c478bd9Sstevel@tonic-gate static int rotor;		/* next slave to be instructed */
145*7c478bd9Sstevel@tonic-gate static pid_t master;		/* pid of master, for sending error signals */
146*7c478bd9Sstevel@tonic-gate static int writer = -1;		/* fd of tape writer */
147*7c478bd9Sstevel@tonic-gate static pid_t writepid;		/* pid of tape writer */
148*7c478bd9Sstevel@tonic-gate static int arch;		/* fd of output archiver */
149*7c478bd9Sstevel@tonic-gate static pid_t archivepid;	/* pid of output archiver */
150*7c478bd9Sstevel@tonic-gate static int archivefd;		/* fd of archive file (proper) */
151*7c478bd9Sstevel@tonic-gate static offset_t lf_archoffset;	/* checkpointed offset into archive file */
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate int caught;			/* caught signal -- imported by mapfile() */
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
156*7c478bd9Sstevel@tonic-gate extern	int xflag;
157*7c478bd9Sstevel@tonic-gate #endif
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
160*7c478bd9Sstevel@tonic-gate static void cmdwrterr(void);
161*7c478bd9Sstevel@tonic-gate static void cmdrderr(void);
162*7c478bd9Sstevel@tonic-gate static void freetape(void);
163*7c478bd9Sstevel@tonic-gate static void bufclear(void);
164*7c478bd9Sstevel@tonic-gate static pid_t setuparchive(void);
165*7c478bd9Sstevel@tonic-gate static pid_t setupwriter(void);
166*7c478bd9Sstevel@tonic-gate static void nextslave(void);
167*7c478bd9Sstevel@tonic-gate static void tperror(int);
168*7c478bd9Sstevel@tonic-gate static void rollforward(int);
169*7c478bd9Sstevel@tonic-gate static void nap(int);
170*7c478bd9Sstevel@tonic-gate static void alrm(int);
171*7c478bd9Sstevel@tonic-gate static void just_rewind(void);
172*7c478bd9Sstevel@tonic-gate static void killall(void);
173*7c478bd9Sstevel@tonic-gate static void proceed(int);
174*7c478bd9Sstevel@tonic-gate static void die(int);
175*7c478bd9Sstevel@tonic-gate static void enslave(void);
176*7c478bd9Sstevel@tonic-gate static void wait_our_turn(void);
177*7c478bd9Sstevel@tonic-gate static void dumpoffline(int, pid_t, int);
178*7c478bd9Sstevel@tonic-gate static void onxfsz(int);
179*7c478bd9Sstevel@tonic-gate static void dowrite(int);
180*7c478bd9Sstevel@tonic-gate static void checkpoint(struct bdesc *, int);
181*7c478bd9Sstevel@tonic-gate static ssize_t atomic(int (*)(), int, char *, int);
182*7c478bd9Sstevel@tonic-gate #else
183*7c478bd9Sstevel@tonic-gate static void cmdwrterr();
184*7c478bd9Sstevel@tonic-gate static void cmdrderr();
185*7c478bd9Sstevel@tonic-gate static void freetape();
186*7c478bd9Sstevel@tonic-gate static void bufclear();
187*7c478bd9Sstevel@tonic-gate static pid_t setuparchive();
188*7c478bd9Sstevel@tonic-gate static pid_t setupwriter();
189*7c478bd9Sstevel@tonic-gate static void nextslave();
190*7c478bd9Sstevel@tonic-gate static void tperror();
191*7c478bd9Sstevel@tonic-gate static void rollforward();
192*7c478bd9Sstevel@tonic-gate static void nap();
193*7c478bd9Sstevel@tonic-gate static void alrm();
194*7c478bd9Sstevel@tonic-gate static void just_rewind();
195*7c478bd9Sstevel@tonic-gate static void killall();
196*7c478bd9Sstevel@tonic-gate static void proceed();
197*7c478bd9Sstevel@tonic-gate static void die();
198*7c478bd9Sstevel@tonic-gate static void enslave();
199*7c478bd9Sstevel@tonic-gate static void wait_our_turn();
200*7c478bd9Sstevel@tonic-gate static void dumpoffline();
201*7c478bd9Sstevel@tonic-gate static void onxfsz();
202*7c478bd9Sstevel@tonic-gate static void dowrite();
203*7c478bd9Sstevel@tonic-gate static void checkpoint();
204*7c478bd9Sstevel@tonic-gate static ssize_t atomic();
205*7c478bd9Sstevel@tonic-gate #endif
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate static size_t tapesize;
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate /*
210*7c478bd9Sstevel@tonic-gate  * Allocate buffers and shared memory variables.  Tape buffers are
211*7c478bd9Sstevel@tonic-gate  * allocated on page boundaries for tape write() efficiency.
212*7c478bd9Sstevel@tonic-gate  */
213*7c478bd9Sstevel@tonic-gate void
214*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
215*7c478bd9Sstevel@tonic-gate #else
216*7c478bd9Sstevel@tonic-gate #endif
217*7c478bd9Sstevel@tonic-gate alloctape(void)
218*7c478bd9Sstevel@tonic-gate {
219*7c478bd9Sstevel@tonic-gate 	struct slaves *slavep;
220*7c478bd9Sstevel@tonic-gate 	ulong_t pgoff = (unsigned)(getpagesize() - 1); /* 2**n - 1 */
221*7c478bd9Sstevel@tonic-gate 	int	mapfd;
222*7c478bd9Sstevel@tonic-gate 	char	*obuf;
223*7c478bd9Sstevel@tonic-gate 	int	saverr;
224*7c478bd9Sstevel@tonic-gate 	int	i, j;
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate 	writesize = ntrec * tp_bsize;
227*7c478bd9Sstevel@tonic-gate 	if (!printsize)
228*7c478bd9Sstevel@tonic-gate 		msg(gettext("Writing %d Kilobyte records\n"),
229*7c478bd9Sstevel@tonic-gate 			writesize / TP_BSIZE_MIN);
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 	/*
232*7c478bd9Sstevel@tonic-gate 	 * set up shared memory seg for here and child
233*7c478bd9Sstevel@tonic-gate 	 */
234*7c478bd9Sstevel@tonic-gate 	mapfd = open("/dev/zero", O_RDWR);
235*7c478bd9Sstevel@tonic-gate 	if (mapfd == -1) {
236*7c478bd9Sstevel@tonic-gate 		saverr = errno;
237*7c478bd9Sstevel@tonic-gate 		msg(gettext("Cannot open `%s': %s\n"),
238*7c478bd9Sstevel@tonic-gate 			"/dev/zero", strerror(saverr));
239*7c478bd9Sstevel@tonic-gate 		dumpabort();
240*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
241*7c478bd9Sstevel@tonic-gate 	}
242*7c478bd9Sstevel@tonic-gate 	/*
243*7c478bd9Sstevel@tonic-gate 	 * Allocate space such that buffers are page-aligned and
244*7c478bd9Sstevel@tonic-gate 	 * pointers are aligned on 4-byte boundaries (for SPARC).
245*7c478bd9Sstevel@tonic-gate 	 * This code assumes that (NBUF * writesize) is a multiple
246*7c478bd9Sstevel@tonic-gate 	 * of the page size and that pages are aligned on 4-byte
247*7c478bd9Sstevel@tonic-gate 	 * boundaries.  Space is allocated as follows:
248*7c478bd9Sstevel@tonic-gate 	 *
249*7c478bd9Sstevel@tonic-gate 	 *    (NBUF * writesize) for the actual buffers
250*7c478bd9Sstevel@tonic-gate 	 *    (pagesize - 1) for padding so the buffers are page-aligned
251*7c478bd9Sstevel@tonic-gate 	 *    (NBUF * ntrec * sizeof (struct bdesc)) for each buffer
252*7c478bd9Sstevel@tonic-gate 	 *    (n * sizeof (int)) for [n] debugging variables/pointers
253*7c478bd9Sstevel@tonic-gate 	 *    (n * sizeof (int)) for [n] miscellaneous variables/pointers
254*7c478bd9Sstevel@tonic-gate 	 */
255*7c478bd9Sstevel@tonic-gate 	tapesize =
256*7c478bd9Sstevel@tonic-gate 	    (NBUF * writesize)				/* output buffers */
257*7c478bd9Sstevel@tonic-gate 		/* LINTED: pgoff fits into a size_t */
258*7c478bd9Sstevel@tonic-gate 	    + (size_t)pgoff				/* page alignment */
259*7c478bd9Sstevel@tonic-gate 							/* buffer descriptors */
260*7c478bd9Sstevel@tonic-gate 	    + (((size_t)sizeof (struct bdesc)) * NBUF * ntrec)
261*7c478bd9Sstevel@tonic-gate #ifdef INSTRUMENT
262*7c478bd9Sstevel@tonic-gate 	    + (2 * (size_t)sizeof (int *))		/* instrumentation */
263*7c478bd9Sstevel@tonic-gate #endif
264*7c478bd9Sstevel@tonic-gate 							/* shared variables */
265*7c478bd9Sstevel@tonic-gate 	    + (size_t)sizeof (struct bdesc **)
266*7c478bd9Sstevel@tonic-gate 	    + (size_t)sizeof (int *)
267*7c478bd9Sstevel@tonic-gate 	    + (3 * (size_t)sizeof (time_t));
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 	shared = mmap((char *)0, tapesize, PROT_READ|PROT_WRITE,
270*7c478bd9Sstevel@tonic-gate 	    MAP_SHARED, mapfd, (off_t)0);
271*7c478bd9Sstevel@tonic-gate 	if (shared == (caddr_t)-1) {
272*7c478bd9Sstevel@tonic-gate 		saverr = errno;
273*7c478bd9Sstevel@tonic-gate 		msg(gettext("Cannot memory map output buffers: %s\n"),
274*7c478bd9Sstevel@tonic-gate 		    strerror(saverr));
275*7c478bd9Sstevel@tonic-gate 		dumpabort();
276*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
277*7c478bd9Sstevel@tonic-gate 	}
278*7c478bd9Sstevel@tonic-gate 	(void) close(mapfd);
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 	/*
281*7c478bd9Sstevel@tonic-gate 	 * Buffers and buffer headers
282*7c478bd9Sstevel@tonic-gate 	 */
283*7c478bd9Sstevel@tonic-gate 	obuf = (char *)(((ulong_t)shared + pgoff) & ~pgoff);
284*7c478bd9Sstevel@tonic-gate 	/* LINTED obuf and writesize are aligned */
285*7c478bd9Sstevel@tonic-gate 	bufp = (struct bdesc *)(obuf + NBUF*writesize);
286*7c478bd9Sstevel@tonic-gate 	/*
287*7c478bd9Sstevel@tonic-gate 	 * Shared memory variables
288*7c478bd9Sstevel@tonic-gate 	 */
289*7c478bd9Sstevel@tonic-gate 	current = (struct bdesc **)&bufp[NBUF*ntrec];
290*7c478bd9Sstevel@tonic-gate 	tapea = (int *)(current + 1);
291*7c478bd9Sstevel@tonic-gate 	/* LINTED pointer alignment ok */
292*7c478bd9Sstevel@tonic-gate 	telapsed = (time_t *)(tapea + 1);
293*7c478bd9Sstevel@tonic-gate 	tstart_writing = telapsed + 1;
294*7c478bd9Sstevel@tonic-gate 	tschedule = tstart_writing + 1;
295*7c478bd9Sstevel@tonic-gate #ifdef INSTRUMENT
296*7c478bd9Sstevel@tonic-gate 	/*
297*7c478bd9Sstevel@tonic-gate 	 * Debugging and instrumentation variables
298*7c478bd9Sstevel@tonic-gate 	 */
299*7c478bd9Sstevel@tonic-gate 	readmissp = (int *)(tschedule + 1);
300*7c478bd9Sstevel@tonic-gate 	idle = readmissp + 1;
301*7c478bd9Sstevel@tonic-gate #endif
302*7c478bd9Sstevel@tonic-gate 	for (i = 0, j = 0; i < NBUF * ntrec; i++, j += tp_bsize) {
303*7c478bd9Sstevel@tonic-gate 		bufp[i].b_data = &obuf[j];
304*7c478bd9Sstevel@tonic-gate 	}
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 	reqsiz = sizeof (struct req) + tp_bsize - sizeof (long);
307*7c478bd9Sstevel@tonic-gate 	for (slavep = slaves; slavep < &slaves[SLAVES]; slavep++)
308*7c478bd9Sstevel@tonic-gate 		slavep->sl_req = (struct req *)xmalloc(reqsiz);
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate 	chkpt.sl_offset = 0;		/* start at offset 0 */
311*7c478bd9Sstevel@tonic-gate 	chkpt.sl_count = 0;
312*7c478bd9Sstevel@tonic-gate 	chkpt.sl_inos = UFSROOTINO;	/* in root inode */
313*7c478bd9Sstevel@tonic-gate 	chkpt.sl_firstrec = 1;
314*7c478bd9Sstevel@tonic-gate 	chkpt.sl_tapea = 0;
315*7c478bd9Sstevel@tonic-gate }
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate static void
318*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
319*7c478bd9Sstevel@tonic-gate freetape(void)
320*7c478bd9Sstevel@tonic-gate #else
321*7c478bd9Sstevel@tonic-gate freetape()
322*7c478bd9Sstevel@tonic-gate #endif
323*7c478bd9Sstevel@tonic-gate {
324*7c478bd9Sstevel@tonic-gate 	if (shared == NULL)
325*7c478bd9Sstevel@tonic-gate 		return;
326*7c478bd9Sstevel@tonic-gate 	(void) timeclock((time_t)0);
327*7c478bd9Sstevel@tonic-gate 	(void) munmap(shared, tapesize);
328*7c478bd9Sstevel@tonic-gate 	shared = NULL;
329*7c478bd9Sstevel@tonic-gate }
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate /*
332*7c478bd9Sstevel@tonic-gate  * Reset tape state variables -- called
333*7c478bd9Sstevel@tonic-gate  * before a pass to dump active files.
334*7c478bd9Sstevel@tonic-gate  */
335*7c478bd9Sstevel@tonic-gate void
336*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
337*7c478bd9Sstevel@tonic-gate reset(void)
338*7c478bd9Sstevel@tonic-gate #else
339*7c478bd9Sstevel@tonic-gate reset()
340*7c478bd9Sstevel@tonic-gate #endif
341*7c478bd9Sstevel@tonic-gate {
342*7c478bd9Sstevel@tonic-gate 	bufclear();
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate #ifdef INSTRUMENT
345*7c478bd9Sstevel@tonic-gate 	(*readmissp) = 0;
346*7c478bd9Sstevel@tonic-gate 	(*idle) = 0;
347*7c478bd9Sstevel@tonic-gate #endif
348*7c478bd9Sstevel@tonic-gate 
349*7c478bd9Sstevel@tonic-gate 	spcl.c_flags = 0;
350*7c478bd9Sstevel@tonic-gate 	spcl.c_volume = 0;
351*7c478bd9Sstevel@tonic-gate 	tapeno = 0;
352*7c478bd9Sstevel@tonic-gate 
353*7c478bd9Sstevel@tonic-gate 	chkpt.sl_offset = 0;		/* start at offset 0 */
354*7c478bd9Sstevel@tonic-gate 	chkpt.sl_count = 0;
355*7c478bd9Sstevel@tonic-gate 	chkpt.sl_inos = UFSROOTINO;	/* in root inode */
356*7c478bd9Sstevel@tonic-gate 	chkpt.sl_firstrec = 1;
357*7c478bd9Sstevel@tonic-gate 	chkpt.sl_tapea = 0;
358*7c478bd9Sstevel@tonic-gate }
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate static void
361*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
362*7c478bd9Sstevel@tonic-gate bufclear(void)
363*7c478bd9Sstevel@tonic-gate #else
364*7c478bd9Sstevel@tonic-gate bufclear()
365*7c478bd9Sstevel@tonic-gate #endif
366*7c478bd9Sstevel@tonic-gate {
367*7c478bd9Sstevel@tonic-gate 	struct bdesc *bp;
368*7c478bd9Sstevel@tonic-gate 	int i;
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate 	for (i = 0, bp = bufp; i < NBUF * ntrec; i++, bp++)
371*7c478bd9Sstevel@tonic-gate 		bp->b_flags = BUF_EMPTY;
372*7c478bd9Sstevel@tonic-gate 	if ((caddr_t)current < shared ||
373*7c478bd9Sstevel@tonic-gate 	    (caddr_t)current > (shared + tapesize)) {
374*7c478bd9Sstevel@tonic-gate 		msg(gettext(
375*7c478bd9Sstevel@tonic-gate 	    "bufclear: current pointer out of range of shared memory\n"));
376*7c478bd9Sstevel@tonic-gate 		dumpabort();
377*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
378*7c478bd9Sstevel@tonic-gate 	}
379*7c478bd9Sstevel@tonic-gate 	if ((*current != NULL) &&
380*7c478bd9Sstevel@tonic-gate 	    (*current < &bufp[0] || *current > &bufp[NBUF*ntrec])) {
381*7c478bd9Sstevel@tonic-gate 		/* ANSI string catenation, to shut cstyle up */
382*7c478bd9Sstevel@tonic-gate 		msg(gettext("bufclear: current buffer pointer (0x%x) "
383*7c478bd9Sstevel@tonic-gate 			"out of range of buffer\naddresses (0x%x - 0x%x)\n"),
384*7c478bd9Sstevel@tonic-gate 		    *current, &bufp[0], &bufp[NBUF*ntrec]);
385*7c478bd9Sstevel@tonic-gate 		dumpabort();
386*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
387*7c478bd9Sstevel@tonic-gate 	}
388*7c478bd9Sstevel@tonic-gate 	*current = bufp;
389*7c478bd9Sstevel@tonic-gate }
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate /*
392*7c478bd9Sstevel@tonic-gate  * Start a process to collect information describing the dump.
393*7c478bd9Sstevel@tonic-gate  * This data takes two forms:
394*7c478bd9Sstevel@tonic-gate  *    the bitmap and directory information being written to
395*7c478bd9Sstevel@tonic-gate  *	the front of the tape (the "archive" file)
396*7c478bd9Sstevel@tonic-gate  *    information describing each directory and inode (to
397*7c478bd9Sstevel@tonic-gate  *	be included in the database tmp file)
398*7c478bd9Sstevel@tonic-gate  * Write the data to the files as it is received so huge file
399*7c478bd9Sstevel@tonic-gate  * systems don't cause dump to consume large amounts of memory.
400*7c478bd9Sstevel@tonic-gate  */
401*7c478bd9Sstevel@tonic-gate static pid_t
402*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
403*7c478bd9Sstevel@tonic-gate setuparchive(void)
404*7c478bd9Sstevel@tonic-gate #else
405*7c478bd9Sstevel@tonic-gate setuparchive()
406*7c478bd9Sstevel@tonic-gate #endif
407*7c478bd9Sstevel@tonic-gate {
408*7c478bd9Sstevel@tonic-gate 	struct slaves *slavep;
409*7c478bd9Sstevel@tonic-gate 	int cmd[2];
410*7c478bd9Sstevel@tonic-gate 	pid_t pid;
411*7c478bd9Sstevel@tonic-gate 	ssize_t size;
412*7c478bd9Sstevel@tonic-gate 	char *data;
413*7c478bd9Sstevel@tonic-gate 	char *errmsg;
414*7c478bd9Sstevel@tonic-gate 	int flags, saverr;
415*7c478bd9Sstevel@tonic-gate 	int punt = 0;
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate 	/*
418*7c478bd9Sstevel@tonic-gate 	 * Both the archive and database tmp files are
419*7c478bd9Sstevel@tonic-gate 	 * checkpointed by taking their current offsets
420*7c478bd9Sstevel@tonic-gate 	 * (sizes) after completing each volume.  Restoring
421*7c478bd9Sstevel@tonic-gate 	 * from a checkpoint involves truncating to the
422*7c478bd9Sstevel@tonic-gate 	 * checkpointed size.
423*7c478bd9Sstevel@tonic-gate 	 */
424*7c478bd9Sstevel@tonic-gate 	if (archive && !doingactive) {
425*7c478bd9Sstevel@tonic-gate 		/* It's allowed/expected to exist, so can't use O_EXCL */
426*7c478bd9Sstevel@tonic-gate 		archivefd = safe_file_open(archivefile, O_WRONLY, 0600);
427*7c478bd9Sstevel@tonic-gate 		if (archivefd < 0) {
428*7c478bd9Sstevel@tonic-gate 			saverr = errno;
429*7c478bd9Sstevel@tonic-gate 			msg(gettext("Cannot open archive file `%s': %s\n"),
430*7c478bd9Sstevel@tonic-gate 			    archivefile, strerror(saverr));
431*7c478bd9Sstevel@tonic-gate 			dumpabort();
432*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
433*7c478bd9Sstevel@tonic-gate 		}
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate 		if (lseek64(archivefd, lf_archoffset, 0) < 0) {
436*7c478bd9Sstevel@tonic-gate 			saverr = errno;
437*7c478bd9Sstevel@tonic-gate 			msg(gettext(
438*7c478bd9Sstevel@tonic-gate 				    "Cannot position archive file `%s' : %s\n"),
439*7c478bd9Sstevel@tonic-gate 			    archivefile, strerror(saverr));
440*7c478bd9Sstevel@tonic-gate 			dumpabort();
441*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
442*7c478bd9Sstevel@tonic-gate 		}
443*7c478bd9Sstevel@tonic-gate 		if (ftruncate64(archivefd, lf_archoffset) < 0) {
444*7c478bd9Sstevel@tonic-gate 			saverr = errno;
445*7c478bd9Sstevel@tonic-gate 			msg(gettext(
446*7c478bd9Sstevel@tonic-gate 				    "Cannot truncate archive file `%s' : %s\n"),
447*7c478bd9Sstevel@tonic-gate 			    archivefile, strerror(saverr));
448*7c478bd9Sstevel@tonic-gate 			dumpabort();
449*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
450*7c478bd9Sstevel@tonic-gate 		}
451*7c478bd9Sstevel@tonic-gate 	}
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 	if (pipe(cmd) < 0) {
454*7c478bd9Sstevel@tonic-gate 		saverr = errno;
455*7c478bd9Sstevel@tonic-gate 		msg(gettext("%s: %s error: %s\n"),
456*7c478bd9Sstevel@tonic-gate 		    "setuparchive", "pipe", strerror(saverr));
457*7c478bd9Sstevel@tonic-gate 		return (0);
458*7c478bd9Sstevel@tonic-gate 	}
459*7c478bd9Sstevel@tonic-gate 	sighold(SIGINT);
460*7c478bd9Sstevel@tonic-gate 	if ((pid = fork()) < 0) {
461*7c478bd9Sstevel@tonic-gate 		saverr = errno;
462*7c478bd9Sstevel@tonic-gate 		msg(gettext("%s: %s error: %s\n"),
463*7c478bd9Sstevel@tonic-gate 		    "setuparchive", "fork", strerror(saverr));
464*7c478bd9Sstevel@tonic-gate 		return (0);
465*7c478bd9Sstevel@tonic-gate 	}
466*7c478bd9Sstevel@tonic-gate 	if (pid > 0) {
467*7c478bd9Sstevel@tonic-gate 		sigrelse(SIGINT);
468*7c478bd9Sstevel@tonic-gate 		/* parent process */
469*7c478bd9Sstevel@tonic-gate 		(void) close(cmd[0]);
470*7c478bd9Sstevel@tonic-gate 		arch = cmd[1];
471*7c478bd9Sstevel@tonic-gate 		return (pid);
472*7c478bd9Sstevel@tonic-gate 	}
473*7c478bd9Sstevel@tonic-gate 	/*
474*7c478bd9Sstevel@tonic-gate 	 * child process
475*7c478bd9Sstevel@tonic-gate 	 */
476*7c478bd9Sstevel@tonic-gate 	(void) signal(SIGINT, SIG_IGN);		/* master handles this */
477*7c478bd9Sstevel@tonic-gate #ifdef TDEBUG
478*7c478bd9Sstevel@tonic-gate 	(void) sleep(4);	/* allow time for parent's message to get out */
479*7c478bd9Sstevel@tonic-gate 	/* XGETTEXT:  #ifdef TDEBUG only */
480*7c478bd9Sstevel@tonic-gate 	msg(gettext("Archiver has pid = %ld\n"), (long)getpid());
481*7c478bd9Sstevel@tonic-gate #endif
482*7c478bd9Sstevel@tonic-gate 	freeino();	/* release unneeded resources */
483*7c478bd9Sstevel@tonic-gate 	freetape();
484*7c478bd9Sstevel@tonic-gate 	for (slavep = &slaves[0]; slavep < &slaves[SLAVES]; slavep++) {
485*7c478bd9Sstevel@tonic-gate 		if (slavep->sl_slavefd != -1) {
486*7c478bd9Sstevel@tonic-gate 			(void) close(slavep->sl_slavefd);
487*7c478bd9Sstevel@tonic-gate 			slavep->sl_slavefd = -1;
488*7c478bd9Sstevel@tonic-gate 		}
489*7c478bd9Sstevel@tonic-gate 	}
490*7c478bd9Sstevel@tonic-gate 	(void) close(to);
491*7c478bd9Sstevel@tonic-gate 	(void) close(fi);
492*7c478bd9Sstevel@tonic-gate 	to = fi = -1;
493*7c478bd9Sstevel@tonic-gate 	(void) close(cmd[1]);
494*7c478bd9Sstevel@tonic-gate 	data = xmalloc(tp_bsize);
495*7c478bd9Sstevel@tonic-gate 	for (;;) {
496*7c478bd9Sstevel@tonic-gate 		size = atomic((int(*)())read, cmd[0], (char *)&flags,
497*7c478bd9Sstevel@tonic-gate 		    sizeof (flags));
498*7c478bd9Sstevel@tonic-gate 		if ((unsigned)size != sizeof (flags))
499*7c478bd9Sstevel@tonic-gate 			break;
500*7c478bd9Sstevel@tonic-gate 		size = atomic((int(*)())read, cmd[0], data, tp_bsize);
501*7c478bd9Sstevel@tonic-gate 		if (size == tp_bsize) {
502*7c478bd9Sstevel@tonic-gate 			if (archive && flags & BUF_ARCHIVE && !punt &&
503*7c478bd9Sstevel@tonic-gate 			    (size = write(archivefd, data, tp_bsize))
504*7c478bd9Sstevel@tonic-gate 			    != tp_bsize) {
505*7c478bd9Sstevel@tonic-gate 				struct stat64 stats;
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate 				if (size != -1) {
508*7c478bd9Sstevel@tonic-gate 					errmsg = strdup(gettext(
509*7c478bd9Sstevel@tonic-gate 					    "Output truncated"));
510*7c478bd9Sstevel@tonic-gate 					if (errmsg == NULL)
511*7c478bd9Sstevel@tonic-gate 						errmsg = "";
512*7c478bd9Sstevel@tonic-gate 				} else {
513*7c478bd9Sstevel@tonic-gate 					errmsg = strerror(errno);
514*7c478bd9Sstevel@tonic-gate 				}
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate 				if (fstat64(archivefd, &stats) < 0)
517*7c478bd9Sstevel@tonic-gate 				    stats.st_size = -1;
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 				/* cast to keep lint&printf happy */
520*7c478bd9Sstevel@tonic-gate 				msg(gettext(
521*7c478bd9Sstevel@tonic-gate 		    "Cannot write archive file `%s' at offset %lld: %s\n"),
522*7c478bd9Sstevel@tonic-gate 				    archivefile, (longlong_t)stats.st_size,
523*7c478bd9Sstevel@tonic-gate 				    errmsg);
524*7c478bd9Sstevel@tonic-gate 				msg(gettext(
525*7c478bd9Sstevel@tonic-gate 		    "Archive file will be deleted, dump will continue\n"));
526*7c478bd9Sstevel@tonic-gate 				punt++;
527*7c478bd9Sstevel@tonic-gate 				if ((size != -1) && (*errmsg != '\0')) {
528*7c478bd9Sstevel@tonic-gate 					free(errmsg);
529*7c478bd9Sstevel@tonic-gate 				}
530*7c478bd9Sstevel@tonic-gate 			}
531*7c478bd9Sstevel@tonic-gate 		} else {
532*7c478bd9Sstevel@tonic-gate 			break;
533*7c478bd9Sstevel@tonic-gate 		}
534*7c478bd9Sstevel@tonic-gate 	}
535*7c478bd9Sstevel@tonic-gate 	(void) close(cmd[0]);
536*7c478bd9Sstevel@tonic-gate 	if (archive) {
537*7c478bd9Sstevel@tonic-gate 		(void) close(archivefd);
538*7c478bd9Sstevel@tonic-gate 		archivefd = -1;
539*7c478bd9Sstevel@tonic-gate 	}
540*7c478bd9Sstevel@tonic-gate 	if (punt) {
541*7c478bd9Sstevel@tonic-gate 		(void) unlink(archivefile);
542*7c478bd9Sstevel@tonic-gate 		Exit(X_ABORT);
543*7c478bd9Sstevel@tonic-gate 	}
544*7c478bd9Sstevel@tonic-gate 	Exit(X_FINOK);
545*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
546*7c478bd9Sstevel@tonic-gate }
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate /*
549*7c478bd9Sstevel@tonic-gate  * Start a process to read the output buffers and write the data
550*7c478bd9Sstevel@tonic-gate  * to the output device.
551*7c478bd9Sstevel@tonic-gate  */
552*7c478bd9Sstevel@tonic-gate static pid_t
553*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
554*7c478bd9Sstevel@tonic-gate setupwriter(void)
555*7c478bd9Sstevel@tonic-gate #else
556*7c478bd9Sstevel@tonic-gate setupwriter()
557*7c478bd9Sstevel@tonic-gate #endif
558*7c478bd9Sstevel@tonic-gate {
559*7c478bd9Sstevel@tonic-gate 	struct slaves *slavep;
560*7c478bd9Sstevel@tonic-gate 	int cmd[2];
561*7c478bd9Sstevel@tonic-gate 	pid_t pid;
562*7c478bd9Sstevel@tonic-gate 	int saverr;
563*7c478bd9Sstevel@tonic-gate 
564*7c478bd9Sstevel@tonic-gate 	caught = 0;
565*7c478bd9Sstevel@tonic-gate 	if (pipe(cmd) < 0) {
566*7c478bd9Sstevel@tonic-gate 		saverr = errno;
567*7c478bd9Sstevel@tonic-gate 		msg(gettext("%s: %s error: %s\n"),
568*7c478bd9Sstevel@tonic-gate 			"setupwriter", "pipe", strerror(saverr));
569*7c478bd9Sstevel@tonic-gate 		return (0);
570*7c478bd9Sstevel@tonic-gate 	}
571*7c478bd9Sstevel@tonic-gate 	sighold(SIGINT);
572*7c478bd9Sstevel@tonic-gate 	if ((pid = fork()) < 0) {
573*7c478bd9Sstevel@tonic-gate 		saverr = errno;
574*7c478bd9Sstevel@tonic-gate 		msg(gettext("%s: %s error: %s\n"),
575*7c478bd9Sstevel@tonic-gate 			"setupwriter", "fork", strerror(saverr));
576*7c478bd9Sstevel@tonic-gate 		return (0);
577*7c478bd9Sstevel@tonic-gate 	}
578*7c478bd9Sstevel@tonic-gate 	if (pid > 0) {
579*7c478bd9Sstevel@tonic-gate 		/*
580*7c478bd9Sstevel@tonic-gate 		 * Parent process
581*7c478bd9Sstevel@tonic-gate 		 */
582*7c478bd9Sstevel@tonic-gate 		sigrelse(SIGINT);
583*7c478bd9Sstevel@tonic-gate 		(void) close(cmd[0]);
584*7c478bd9Sstevel@tonic-gate 		writer = cmd[1];
585*7c478bd9Sstevel@tonic-gate 		return (pid);
586*7c478bd9Sstevel@tonic-gate 	}
587*7c478bd9Sstevel@tonic-gate 	/*
588*7c478bd9Sstevel@tonic-gate 	 * Child (writer) process
589*7c478bd9Sstevel@tonic-gate 	 */
590*7c478bd9Sstevel@tonic-gate 	(void) signal(SIGINT, SIG_IGN);		/* master handles this */
591*7c478bd9Sstevel@tonic-gate #ifdef TDEBUG
592*7c478bd9Sstevel@tonic-gate 	(void) sleep(4);	/* allow time for parent's message to get out */
593*7c478bd9Sstevel@tonic-gate 	/* XGETTEXT:  #ifdef TDEBUG only */
594*7c478bd9Sstevel@tonic-gate 	msg(gettext("Writer has pid = %ld\n"), (long)getpid());
595*7c478bd9Sstevel@tonic-gate #endif
596*7c478bd9Sstevel@tonic-gate 	child_chdir();
597*7c478bd9Sstevel@tonic-gate 	freeino();	/* release unneeded resources */
598*7c478bd9Sstevel@tonic-gate 	for (slavep = &slaves[0]; slavep < &slaves[SLAVES]; slavep++) {
599*7c478bd9Sstevel@tonic-gate 		if (slavep->sl_slavefd != -1) {
600*7c478bd9Sstevel@tonic-gate 			(void) close(slavep->sl_slavefd);
601*7c478bd9Sstevel@tonic-gate 			slavep->sl_slavefd = -1;
602*7c478bd9Sstevel@tonic-gate 		}
603*7c478bd9Sstevel@tonic-gate 	}
604*7c478bd9Sstevel@tonic-gate 	(void) close(fi);
605*7c478bd9Sstevel@tonic-gate 	fi = -1;
606*7c478bd9Sstevel@tonic-gate 	(void) close(cmd[1]);
607*7c478bd9Sstevel@tonic-gate 	dowrite(cmd[0]);
608*7c478bd9Sstevel@tonic-gate 	if (arch >= 0) {
609*7c478bd9Sstevel@tonic-gate 		(void) close(arch);
610*7c478bd9Sstevel@tonic-gate 		arch = -1;
611*7c478bd9Sstevel@tonic-gate 	}
612*7c478bd9Sstevel@tonic-gate 	(void) close(cmd[0]);
613*7c478bd9Sstevel@tonic-gate 	Exit(X_FINOK);
614*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
615*7c478bd9Sstevel@tonic-gate }
616*7c478bd9Sstevel@tonic-gate 
617*7c478bd9Sstevel@tonic-gate void
618*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
619*7c478bd9Sstevel@tonic-gate spclrec(void)
620*7c478bd9Sstevel@tonic-gate #else
621*7c478bd9Sstevel@tonic-gate spclrec()
622*7c478bd9Sstevel@tonic-gate #endif
623*7c478bd9Sstevel@tonic-gate {
624*7c478bd9Sstevel@tonic-gate 	int s, i;
625*7c478bd9Sstevel@tonic-gate 	int32_t *ip;
626*7c478bd9Sstevel@tonic-gate 	int flags = BUF_SPCLREC;
627*7c478bd9Sstevel@tonic-gate 
628*7c478bd9Sstevel@tonic-gate 	if ((BIT(ino, shamap)) && (spcl.c_type == TS_INODE)) {
629*7c478bd9Sstevel@tonic-gate 		spcl.c_type = TS_ADDR;
630*7c478bd9Sstevel@tonic-gate 		/* LINTED: result fits in a short */
631*7c478bd9Sstevel@tonic-gate 		spcl.c_dinode.di_mode &= ~S_IFMT;
632*7c478bd9Sstevel@tonic-gate 		/* LINTED: result fits in a short */
633*7c478bd9Sstevel@tonic-gate 		spcl.c_dinode.di_mode |= IFSHAD;
634*7c478bd9Sstevel@tonic-gate 	}
635*7c478bd9Sstevel@tonic-gate 
636*7c478bd9Sstevel@tonic-gate 	/*
637*7c478bd9Sstevel@tonic-gate 	 * Only TS_INODEs should have short metadata, if this
638*7c478bd9Sstevel@tonic-gate 	 * isn't such a spclrec, clear the metadata flag and
639*7c478bd9Sstevel@tonic-gate 	 * the c_shadow contents.
640*7c478bd9Sstevel@tonic-gate 	 */
641*7c478bd9Sstevel@tonic-gate 	if (!(spcl.c_type == TS_INODE && (spcl.c_flags & DR_HASMETA))) {
642*7c478bd9Sstevel@tonic-gate 		spcl.c_flags &= ~DR_HASMETA;
643*7c478bd9Sstevel@tonic-gate 		bcopy(c_shadow_save, &(spcl.c_shadow),
644*7c478bd9Sstevel@tonic-gate 		    sizeof (spcl.c_shadow));
645*7c478bd9Sstevel@tonic-gate 	}
646*7c478bd9Sstevel@tonic-gate 
647*7c478bd9Sstevel@tonic-gate 	if (spcl.c_type == TS_END) {
648*7c478bd9Sstevel@tonic-gate 		spcl.c_count = 1;
649*7c478bd9Sstevel@tonic-gate 		spcl.c_flags |= DR_INODEINFO;
650*7c478bd9Sstevel@tonic-gate 		bcopy((char *)inos, (char *)spcl.c_inos, sizeof (inos));
651*7c478bd9Sstevel@tonic-gate 	} else if (spcl.c_type == TS_TAPE) {
652*7c478bd9Sstevel@tonic-gate 		spcl.c_flags |= DR_NEWHEADER;
653*7c478bd9Sstevel@tonic-gate 		if (doingactive)
654*7c478bd9Sstevel@tonic-gate 			spcl.c_flags |= DR_REDUMP;
655*7c478bd9Sstevel@tonic-gate 	} else if (spcl.c_type != TS_INODE)
656*7c478bd9Sstevel@tonic-gate 		flags = BUF_SPCLREC;
657*7c478bd9Sstevel@tonic-gate 	spcl.c_tapea = *tapea;
658*7c478bd9Sstevel@tonic-gate 	/* LINTED for now, max inode # is 2**31 (ufs max size is 4TB) */
659*7c478bd9Sstevel@tonic-gate 	spcl.c_inumber = (ino32_t)ino;
660*7c478bd9Sstevel@tonic-gate 	spcl.c_magic = (tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC;
661*7c478bd9Sstevel@tonic-gate 	spcl.c_checksum = 0;
662*7c478bd9Sstevel@tonic-gate 	ip = (int32_t *)&spcl;
663*7c478bd9Sstevel@tonic-gate 	s = CHECKSUM;
664*7c478bd9Sstevel@tonic-gate 	assert((tp_bsize % sizeof (*ip)) == 0);
665*7c478bd9Sstevel@tonic-gate 	i = tp_bsize / sizeof (*ip);
666*7c478bd9Sstevel@tonic-gate 	assert((i%8) == 0);
667*7c478bd9Sstevel@tonic-gate 	i /= 8;
668*7c478bd9Sstevel@tonic-gate 	do {
669*7c478bd9Sstevel@tonic-gate 		s -= *ip++; s -= *ip++; s -= *ip++; s -= *ip++;
670*7c478bd9Sstevel@tonic-gate 		s -= *ip++; s -= *ip++; s -= *ip++; s -= *ip++;
671*7c478bd9Sstevel@tonic-gate 	} while (--i > 0);
672*7c478bd9Sstevel@tonic-gate 	spcl.c_checksum = s;
673*7c478bd9Sstevel@tonic-gate 	taprec((uchar_t *)&spcl, flags, sizeof (spcl));
674*7c478bd9Sstevel@tonic-gate 	if (spcl.c_type == TS_END)
675*7c478bd9Sstevel@tonic-gate 		spcl.c_flags &= ~DR_INODEINFO;
676*7c478bd9Sstevel@tonic-gate 	else if (spcl.c_type == TS_TAPE)
677*7c478bd9Sstevel@tonic-gate 		spcl.c_flags &= ~(DR_NEWHEADER|DR_REDUMP|DR_TRUEINC);
678*7c478bd9Sstevel@tonic-gate }
679*7c478bd9Sstevel@tonic-gate 
680*7c478bd9Sstevel@tonic-gate /*
681*7c478bd9Sstevel@tonic-gate  * Fill appropriate buffer
682*7c478bd9Sstevel@tonic-gate  */
683*7c478bd9Sstevel@tonic-gate void
684*7c478bd9Sstevel@tonic-gate taprec(dp, flags, size)
685*7c478bd9Sstevel@tonic-gate 	uchar_t *dp;
686*7c478bd9Sstevel@tonic-gate 	int flags;
687*7c478bd9Sstevel@tonic-gate 	int size;
688*7c478bd9Sstevel@tonic-gate {
689*7c478bd9Sstevel@tonic-gate 	if (size > tp_bsize) {
690*7c478bd9Sstevel@tonic-gate 		msg(gettext(
691*7c478bd9Sstevel@tonic-gate 		    "taprec: Unexpected buffer size, expected %d, got %d.\n"),
692*7c478bd9Sstevel@tonic-gate 		    tp_bsize, size);
693*7c478bd9Sstevel@tonic-gate 		dumpabort();
694*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
695*7c478bd9Sstevel@tonic-gate 	}
696*7c478bd9Sstevel@tonic-gate 
697*7c478bd9Sstevel@tonic-gate 	while ((*current)->b_flags & BUF_FULL)
698*7c478bd9Sstevel@tonic-gate 		nap(10);
699*7c478bd9Sstevel@tonic-gate 
700*7c478bd9Sstevel@tonic-gate 	bcopy(dp, (*current)->b_data, (size_t)size);
701*7c478bd9Sstevel@tonic-gate 	if (size < tp_bsize) {
702*7c478bd9Sstevel@tonic-gate 		bzero((*current)->b_data + size, tp_bsize - size);
703*7c478bd9Sstevel@tonic-gate 	}
704*7c478bd9Sstevel@tonic-gate 
705*7c478bd9Sstevel@tonic-gate 	if (dumptoarchive)
706*7c478bd9Sstevel@tonic-gate 		flags |= BUF_ARCHIVE;
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate 	/* no locking as we assume only one reader and one writer active */
709*7c478bd9Sstevel@tonic-gate 	(*current)->b_flags = (flags | BUF_FULL);
710*7c478bd9Sstevel@tonic-gate 	if (++*current >= &bufp[NBUF*ntrec])
711*7c478bd9Sstevel@tonic-gate 		(*current) = &bufp[0];
712*7c478bd9Sstevel@tonic-gate 	(*tapea)++;
713*7c478bd9Sstevel@tonic-gate }
714*7c478bd9Sstevel@tonic-gate 
715*7c478bd9Sstevel@tonic-gate void
716*7c478bd9Sstevel@tonic-gate dmpblk(blkno, size, offset)
717*7c478bd9Sstevel@tonic-gate 	daddr32_t blkno;
718*7c478bd9Sstevel@tonic-gate 	size_t size;
719*7c478bd9Sstevel@tonic-gate 	off_t offset;
720*7c478bd9Sstevel@tonic-gate {
721*7c478bd9Sstevel@tonic-gate 	diskaddr_t dblkno;
722*7c478bd9Sstevel@tonic-gate 
723*7c478bd9Sstevel@tonic-gate 	assert((offset >> DEV_BSHIFT) <= INT32_MAX);
724*7c478bd9Sstevel@tonic-gate 	dblkno = fsbtodb(sblock, blkno) + (offset >> DEV_BSHIFT);
725*7c478bd9Sstevel@tonic-gate 	size = (size + DEV_BSIZE-1) & ~(DEV_BSIZE-1);
726*7c478bd9Sstevel@tonic-gate 	slp->sl_req->br_dblk = dblkno;
727*7c478bd9Sstevel@tonic-gate 	slp->sl_req->br_size = size;
728*7c478bd9Sstevel@tonic-gate 	if (dumptoarchive) {
729*7c478bd9Sstevel@tonic-gate 		/* LINTED: result fits in a short */
730*7c478bd9Sstevel@tonic-gate 		slp->sl_req->aflag |= BUF_ARCHIVE;
731*7c478bd9Sstevel@tonic-gate 	}
732*7c478bd9Sstevel@tonic-gate 	toslave((void(*)())0, ino);
733*7c478bd9Sstevel@tonic-gate }
734*7c478bd9Sstevel@tonic-gate 
735*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
736*7c478bd9Sstevel@tonic-gate static void
737*7c478bd9Sstevel@tonic-gate tperror(sig)
738*7c478bd9Sstevel@tonic-gate 	int	sig;
739*7c478bd9Sstevel@tonic-gate {
740*7c478bd9Sstevel@tonic-gate 	char buf[3000];
741*7c478bd9Sstevel@tonic-gate 
742*7c478bd9Sstevel@tonic-gate 	if (pipeout) {
743*7c478bd9Sstevel@tonic-gate 		msg(gettext("Write error on %s\n"), tape);
744*7c478bd9Sstevel@tonic-gate 		msg(gettext("Cannot recover\n"));
745*7c478bd9Sstevel@tonic-gate 		dumpabort();
746*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
747*7c478bd9Sstevel@tonic-gate 	}
748*7c478bd9Sstevel@tonic-gate 	if (!doingverify) {
749*7c478bd9Sstevel@tonic-gate 		broadcast(gettext("WRITE ERROR!\n"));
750*7c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf),
751*7c478bd9Sstevel@tonic-gate 		    gettext("Do you want to restart?: (\"yes\" or \"no\") "));
752*7c478bd9Sstevel@tonic-gate 		if (!query(buf)) {
753*7c478bd9Sstevel@tonic-gate 			dumpabort();
754*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
755*7c478bd9Sstevel@tonic-gate 		}
756*7c478bd9Sstevel@tonic-gate 		if (tapeout && (isrewind(to) || offline)) {
757*7c478bd9Sstevel@tonic-gate 			/* ANSI string catenation, to shut cstyle up */
758*7c478bd9Sstevel@tonic-gate 			msg(gettext("This tape will rewind.  After "
759*7c478bd9Sstevel@tonic-gate 				    "it is rewound,\nreplace the faulty tape "
760*7c478bd9Sstevel@tonic-gate 				    "with a new one;\nthis dump volume will "
761*7c478bd9Sstevel@tonic-gate 				    "be rewritten.\n"));
762*7c478bd9Sstevel@tonic-gate 		}
763*7c478bd9Sstevel@tonic-gate 	} else {
764*7c478bd9Sstevel@tonic-gate 		broadcast(gettext("TAPE VERIFICATION ERROR!\n"));
765*7c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), gettext(
766*7c478bd9Sstevel@tonic-gate 		    "Do you want to rewrite?: (\"yes\" or \"no\") "));
767*7c478bd9Sstevel@tonic-gate 		if (!query(buf)) {
768*7c478bd9Sstevel@tonic-gate 			dumpabort();
769*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
770*7c478bd9Sstevel@tonic-gate 		}
771*7c478bd9Sstevel@tonic-gate 		msg(gettext(
772*7c478bd9Sstevel@tonic-gate 			"This tape will be rewritten and then verified\n"));
773*7c478bd9Sstevel@tonic-gate 	}
774*7c478bd9Sstevel@tonic-gate 	killall();
775*7c478bd9Sstevel@tonic-gate 	trewind();
776*7c478bd9Sstevel@tonic-gate 	Exit(X_REWRITE);
777*7c478bd9Sstevel@tonic-gate }
778*7c478bd9Sstevel@tonic-gate 
779*7c478bd9Sstevel@tonic-gate /*
780*7c478bd9Sstevel@tonic-gate  * Called by master from pass() to send a request to dump files/blocks
781*7c478bd9Sstevel@tonic-gate  * to one of the slaves.  Slaves return whether the file was active
782*7c478bd9Sstevel@tonic-gate  * when it was being dumped.  The tape writer process sends checkpoint
783*7c478bd9Sstevel@tonic-gate  * info when it completes a volume.
784*7c478bd9Sstevel@tonic-gate  */
785*7c478bd9Sstevel@tonic-gate void
786*7c478bd9Sstevel@tonic-gate toslave(fn, inumber)
787*7c478bd9Sstevel@tonic-gate 	void	(*fn)();
788*7c478bd9Sstevel@tonic-gate 	ino_t	inumber;
789*7c478bd9Sstevel@tonic-gate {
790*7c478bd9Sstevel@tonic-gate 	int	wasactive;
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 	if (recsout >= SLAVES) {
793*7c478bd9Sstevel@tonic-gate 		if ((unsigned)atomic((int(*)())read, slp->sl_slavefd,
794*7c478bd9Sstevel@tonic-gate 		    (char *)&wasactive, sizeof (wasactive)) !=
795*7c478bd9Sstevel@tonic-gate 		    sizeof (wasactive)) {
796*7c478bd9Sstevel@tonic-gate 			cmdrderr();
797*7c478bd9Sstevel@tonic-gate 			dumpabort();
798*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
799*7c478bd9Sstevel@tonic-gate 		}
800*7c478bd9Sstevel@tonic-gate 		if (wasactive) {
801*7c478bd9Sstevel@tonic-gate 			active++;
802*7c478bd9Sstevel@tonic-gate 			msg(gettext(
803*7c478bd9Sstevel@tonic-gate 		"The file at inode `%lu' was active and will be recopied\n"),
804*7c478bd9Sstevel@tonic-gate 				slp->sl_req->ir_inumber);
805*7c478bd9Sstevel@tonic-gate 			/* LINTED: 32-bit to 8-bit assignment ok */
806*7c478bd9Sstevel@tonic-gate 			BIS(slp->sl_req->ir_inumber, activemap);
807*7c478bd9Sstevel@tonic-gate 		}
808*7c478bd9Sstevel@tonic-gate 	}
809*7c478bd9Sstevel@tonic-gate 	slp->sl_req->aflag = 0;
810*7c478bd9Sstevel@tonic-gate 	if (dumptoarchive) {
811*7c478bd9Sstevel@tonic-gate 		/* LINTED: result fits in a short */
812*7c478bd9Sstevel@tonic-gate 		slp->sl_req->aflag |= BUF_ARCHIVE;
813*7c478bd9Sstevel@tonic-gate 	}
814*7c478bd9Sstevel@tonic-gate 	if (fn)
815*7c478bd9Sstevel@tonic-gate 		(*fn)(inumber);
816*7c478bd9Sstevel@tonic-gate 
817*7c478bd9Sstevel@tonic-gate 	if (atomic((int(*)())write, slp->sl_slavefd, (char *)slp->sl_req,
818*7c478bd9Sstevel@tonic-gate 	    reqsiz) != reqsiz) {
819*7c478bd9Sstevel@tonic-gate 		cmdwrterr();
820*7c478bd9Sstevel@tonic-gate 		dumpabort();
821*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
822*7c478bd9Sstevel@tonic-gate 	}
823*7c478bd9Sstevel@tonic-gate 	++recsout;
824*7c478bd9Sstevel@tonic-gate 	nextslave();
825*7c478bd9Sstevel@tonic-gate }
826*7c478bd9Sstevel@tonic-gate 
827*7c478bd9Sstevel@tonic-gate void
828*7c478bd9Sstevel@tonic-gate dospcl(inumber)
829*7c478bd9Sstevel@tonic-gate 	ino_t	inumber;
830*7c478bd9Sstevel@tonic-gate {
831*7c478bd9Sstevel@tonic-gate 	/* LINTED for now, max inode # is 2**31 (ufs max size is 1TB) */
832*7c478bd9Sstevel@tonic-gate 	spcl.c_inumber = (ino32_t)inumber;
833*7c478bd9Sstevel@tonic-gate 	slp->sl_req->br_dblk = 0;
834*7c478bd9Sstevel@tonic-gate 	bcopy((char *)&spcl, (char *)slp->sl_req->br_spcl, tp_bsize);
835*7c478bd9Sstevel@tonic-gate }
836*7c478bd9Sstevel@tonic-gate 
837*7c478bd9Sstevel@tonic-gate static void
838*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
839*7c478bd9Sstevel@tonic-gate nextslave(void)
840*7c478bd9Sstevel@tonic-gate #else
841*7c478bd9Sstevel@tonic-gate nextslave()
842*7c478bd9Sstevel@tonic-gate #endif
843*7c478bd9Sstevel@tonic-gate {
844*7c478bd9Sstevel@tonic-gate 	if (++rotor >= SLAVES) {
845*7c478bd9Sstevel@tonic-gate 		rotor = 0;
846*7c478bd9Sstevel@tonic-gate 	}
847*7c478bd9Sstevel@tonic-gate 	slp = &slaves[rotor];
848*7c478bd9Sstevel@tonic-gate }
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate void
851*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
852*7c478bd9Sstevel@tonic-gate flushcmds(void)
853*7c478bd9Sstevel@tonic-gate #else
854*7c478bd9Sstevel@tonic-gate flushcmds()
855*7c478bd9Sstevel@tonic-gate #endif
856*7c478bd9Sstevel@tonic-gate {
857*7c478bd9Sstevel@tonic-gate 	int i;
858*7c478bd9Sstevel@tonic-gate 	int wasactive;
859*7c478bd9Sstevel@tonic-gate 
860*7c478bd9Sstevel@tonic-gate 	/*
861*7c478bd9Sstevel@tonic-gate 	 * Retrieve all slave status
862*7c478bd9Sstevel@tonic-gate 	 */
863*7c478bd9Sstevel@tonic-gate 	if (recsout < SLAVES) {
864*7c478bd9Sstevel@tonic-gate 		slp = slaves;
865*7c478bd9Sstevel@tonic-gate 		rotor = 0;
866*7c478bd9Sstevel@tonic-gate 	}
867*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < (recsout < SLAVES ? recsout : SLAVES); i++) {
868*7c478bd9Sstevel@tonic-gate 		if ((unsigned)atomic((int(*)())read, slp->sl_slavefd,
869*7c478bd9Sstevel@tonic-gate 		    (char *)&wasactive, sizeof (wasactive)) !=
870*7c478bd9Sstevel@tonic-gate 		    sizeof (wasactive)) {
871*7c478bd9Sstevel@tonic-gate 			cmdrderr();
872*7c478bd9Sstevel@tonic-gate 			dumpabort();
873*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
874*7c478bd9Sstevel@tonic-gate 		}
875*7c478bd9Sstevel@tonic-gate 		if (wasactive) {
876*7c478bd9Sstevel@tonic-gate 			active++;
877*7c478bd9Sstevel@tonic-gate 			msg(gettext(
878*7c478bd9Sstevel@tonic-gate 			    "inode %d was active and will be recopied\n"),
879*7c478bd9Sstevel@tonic-gate 				slp->sl_req->ir_inumber);
880*7c478bd9Sstevel@tonic-gate 			/* LINTED: 32-bit to 8-bit assignment ok */
881*7c478bd9Sstevel@tonic-gate 			BIS(slp->sl_req->ir_inumber, activemap);
882*7c478bd9Sstevel@tonic-gate 		}
883*7c478bd9Sstevel@tonic-gate 		nextslave();
884*7c478bd9Sstevel@tonic-gate 	}
885*7c478bd9Sstevel@tonic-gate }
886*7c478bd9Sstevel@tonic-gate 
887*7c478bd9Sstevel@tonic-gate void
888*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
889*7c478bd9Sstevel@tonic-gate flusht(void)
890*7c478bd9Sstevel@tonic-gate #else
891*7c478bd9Sstevel@tonic-gate flusht()
892*7c478bd9Sstevel@tonic-gate #endif
893*7c478bd9Sstevel@tonic-gate {
894*7c478bd9Sstevel@tonic-gate 	sigset_t block_set, oset;	/* hold SIGUSR1 and atomically sleep */
895*7c478bd9Sstevel@tonic-gate 
896*7c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&block_set);
897*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&block_set, SIGUSR1);
898*7c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &block_set, &oset);
899*7c478bd9Sstevel@tonic-gate 	(void) kill(writepid, SIGUSR1);	/* tell writer to flush */
900*7c478bd9Sstevel@tonic-gate 	(void) sigpause(SIGUSR1);	/* wait for SIGUSR1 from writer */
901*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
902*7c478bd9Sstevel@tonic-gate }
903*7c478bd9Sstevel@tonic-gate 
904*7c478bd9Sstevel@tonic-gate jmp_buf	checkpoint_buf;
905*7c478bd9Sstevel@tonic-gate 
906*7c478bd9Sstevel@tonic-gate /*
907*7c478bd9Sstevel@tonic-gate  * Roll forward to the next volume after receiving
908*7c478bd9Sstevel@tonic-gate  * an EOT signal from writer.  Get checkpoint data
909*7c478bd9Sstevel@tonic-gate  * from writer and return if done, otherwise fork
910*7c478bd9Sstevel@tonic-gate  * a new process and jump back to main state loop
911*7c478bd9Sstevel@tonic-gate  * to begin the next volume.  Installed as the master's
912*7c478bd9Sstevel@tonic-gate  * signal handler for SIGUSR1.
913*7c478bd9Sstevel@tonic-gate  */
914*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
915*7c478bd9Sstevel@tonic-gate static void
916*7c478bd9Sstevel@tonic-gate rollforward(sig)
917*7c478bd9Sstevel@tonic-gate 	int	sig;
918*7c478bd9Sstevel@tonic-gate {
919*7c478bd9Sstevel@tonic-gate 	int status;
920*7c478bd9Sstevel@tonic-gate 	(void) sighold(SIGUSR1);
921*7c478bd9Sstevel@tonic-gate 
922*7c478bd9Sstevel@tonic-gate 	/*
923*7c478bd9Sstevel@tonic-gate 	 * Writer sends us checkpoint information after
924*7c478bd9Sstevel@tonic-gate 	 * each volume.  A returned state of DS_DONE with no
925*7c478bd9Sstevel@tonic-gate 	 * unwritten (left-over) records differentiates a
926*7c478bd9Sstevel@tonic-gate 	 * clean flush from one in which EOT was encountered.
927*7c478bd9Sstevel@tonic-gate 	 */
928*7c478bd9Sstevel@tonic-gate 	if ((unsigned)atomic((int(*)())read, writer, (char *)&chkpt,
929*7c478bd9Sstevel@tonic-gate 	    sizeof (struct slaves)) != sizeof (struct slaves)) {
930*7c478bd9Sstevel@tonic-gate 		cmdrderr();
931*7c478bd9Sstevel@tonic-gate 		dumpabort();
932*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
933*7c478bd9Sstevel@tonic-gate 	}
934*7c478bd9Sstevel@tonic-gate 	if (atomic((int(*)())read, writer, (char *)&spcl,
935*7c478bd9Sstevel@tonic-gate 	    TP_BSIZE_MIN) != TP_BSIZE_MIN) {
936*7c478bd9Sstevel@tonic-gate 		cmdrderr();
937*7c478bd9Sstevel@tonic-gate 		dumpabort();
938*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
939*7c478bd9Sstevel@tonic-gate 	}
940*7c478bd9Sstevel@tonic-gate 	ino = chkpt.sl_inos - 1;
941*7c478bd9Sstevel@tonic-gate 	pos = chkpt.sl_offset;
942*7c478bd9Sstevel@tonic-gate 	leftover = chkpt.sl_count;
943*7c478bd9Sstevel@tonic-gate 	dumpstate = chkpt.sl_state;
944*7c478bd9Sstevel@tonic-gate 	blockswritten = ++chkpt.sl_tapea;
945*7c478bd9Sstevel@tonic-gate 
946*7c478bd9Sstevel@tonic-gate 	if (dumpstate == DS_DONE) {
947*7c478bd9Sstevel@tonic-gate 		if (archivepid) {
948*7c478bd9Sstevel@tonic-gate 			/*
949*7c478bd9Sstevel@tonic-gate 			 * If archiving (either archive or
950*7c478bd9Sstevel@tonic-gate 			 * database), signal the archiver
951*7c478bd9Sstevel@tonic-gate 			 * to finish up.  This must happen
952*7c478bd9Sstevel@tonic-gate 			 * before the writer exits in order
953*7c478bd9Sstevel@tonic-gate 			 * to avoid a race.
954*7c478bd9Sstevel@tonic-gate 			 */
955*7c478bd9Sstevel@tonic-gate 			(void) kill(archivepid, SIGUSR1);
956*7c478bd9Sstevel@tonic-gate 		}
957*7c478bd9Sstevel@tonic-gate 		(void) signal(SIGUSR1, SIG_IGN);
958*7c478bd9Sstevel@tonic-gate 		(void) sigrelse(SIGUSR1);
959*7c478bd9Sstevel@tonic-gate 		(void) kill(writepid, SIGUSR1);	/* tell writer to exit */
960*7c478bd9Sstevel@tonic-gate 
961*7c478bd9Sstevel@tonic-gate 		lf_archoffset = 0LL;
962*7c478bd9Sstevel@tonic-gate 		longjmp(checkpoint_buf, 1);
963*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
964*7c478bd9Sstevel@tonic-gate 	}
965*7c478bd9Sstevel@tonic-gate 
966*7c478bd9Sstevel@tonic-gate 	if (leftover) {
967*7c478bd9Sstevel@tonic-gate 		(void) memmove(spcl.c_addr,
968*7c478bd9Sstevel@tonic-gate 		    &spcl.c_addr[spcl.c_count-leftover], leftover);
969*7c478bd9Sstevel@tonic-gate 		bzero(&spcl.c_addr[leftover], TP_NINDIR-leftover);
970*7c478bd9Sstevel@tonic-gate 	}
971*7c478bd9Sstevel@tonic-gate 	if (writepid) {
972*7c478bd9Sstevel@tonic-gate 		(void) kill(writepid, SIGUSR1);	/* tell writer to exit */
973*7c478bd9Sstevel@tonic-gate 		(void) close(writer);
974*7c478bd9Sstevel@tonic-gate 		writer = -1;
975*7c478bd9Sstevel@tonic-gate 	}
976*7c478bd9Sstevel@tonic-gate 	if (archivepid) {
977*7c478bd9Sstevel@tonic-gate 		(void) waitpid(archivepid, &status, 0);	/* wait for archiver */
978*7c478bd9Sstevel@tonic-gate #ifdef TDEBUG
979*7c478bd9Sstevel@tonic-gate 
980*7c478bd9Sstevel@tonic-gate 		/* XGETTEXT:  #ifdef TDEBUG only */
981*7c478bd9Sstevel@tonic-gate 		msg(gettext("Archiver %ld returns with status %d\n"),
982*7c478bd9Sstevel@tonic-gate 		    (long)archivepid, status);
983*7c478bd9Sstevel@tonic-gate #endif
984*7c478bd9Sstevel@tonic-gate 		archivepid = 0;
985*7c478bd9Sstevel@tonic-gate 	}
986*7c478bd9Sstevel@tonic-gate 	/*
987*7c478bd9Sstevel@tonic-gate 	 * Checkpoint archive file
988*7c478bd9Sstevel@tonic-gate 	 */
989*7c478bd9Sstevel@tonic-gate 	if (!doingverify && archive) {
990*7c478bd9Sstevel@tonic-gate 		lf_archoffset = lseek64(archivefd, (off64_t)0, 2);
991*7c478bd9Sstevel@tonic-gate 		if (lf_archoffset < 0) {
992*7c478bd9Sstevel@tonic-gate 			int saverr = errno;
993*7c478bd9Sstevel@tonic-gate 			msg(gettext("Cannot position archive file `%s': %s\n"),
994*7c478bd9Sstevel@tonic-gate 				archivefile, strerror(saverr));
995*7c478bd9Sstevel@tonic-gate 			dumpabort();
996*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
997*7c478bd9Sstevel@tonic-gate 		}
998*7c478bd9Sstevel@tonic-gate 		(void) close(archivefd);
999*7c478bd9Sstevel@tonic-gate 		archivefd = -1;
1000*7c478bd9Sstevel@tonic-gate 	}
1001*7c478bd9Sstevel@tonic-gate 	resetino(ino);
1002*7c478bd9Sstevel@tonic-gate 
1003*7c478bd9Sstevel@tonic-gate 	if (dumpstate == DS_START) {
1004*7c478bd9Sstevel@tonic-gate 		msg(gettext(
1005*7c478bd9Sstevel@tonic-gate 			"Tape too short: changing volumes and restarting\n"));
1006*7c478bd9Sstevel@tonic-gate 		reset();
1007*7c478bd9Sstevel@tonic-gate 	}
1008*7c478bd9Sstevel@tonic-gate 
1009*7c478bd9Sstevel@tonic-gate 	if (!pipeout) {
1010*7c478bd9Sstevel@tonic-gate 		if (verify && !doingverify)
1011*7c478bd9Sstevel@tonic-gate 			trewind();
1012*7c478bd9Sstevel@tonic-gate 		else {
1013*7c478bd9Sstevel@tonic-gate 			close_rewind();
1014*7c478bd9Sstevel@tonic-gate 			changevol();
1015*7c478bd9Sstevel@tonic-gate 		}
1016*7c478bd9Sstevel@tonic-gate 	}
1017*7c478bd9Sstevel@tonic-gate 
1018*7c478bd9Sstevel@tonic-gate 	(void) sigrelse(SIGUSR1);
1019*7c478bd9Sstevel@tonic-gate 	otape(0);
1020*7c478bd9Sstevel@tonic-gate 	longjmp(checkpoint_buf, 1);
1021*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
1022*7c478bd9Sstevel@tonic-gate }
1023*7c478bd9Sstevel@tonic-gate 
1024*7c478bd9Sstevel@tonic-gate static void
1025*7c478bd9Sstevel@tonic-gate nap(ms)
1026*7c478bd9Sstevel@tonic-gate 	int ms;
1027*7c478bd9Sstevel@tonic-gate {
1028*7c478bd9Sstevel@tonic-gate 	struct timeval tv;
1029*7c478bd9Sstevel@tonic-gate 
1030*7c478bd9Sstevel@tonic-gate 	tv.tv_sec = ms / 1000;
1031*7c478bd9Sstevel@tonic-gate 	tv.tv_usec = (ms - tv.tv_sec * 1000) * 1000;
1032*7c478bd9Sstevel@tonic-gate 	(void) select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv);
1033*7c478bd9Sstevel@tonic-gate }
1034*7c478bd9Sstevel@tonic-gate 
1035*7c478bd9Sstevel@tonic-gate static jmp_buf alrm_buf;
1036*7c478bd9Sstevel@tonic-gate 
1037*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1038*7c478bd9Sstevel@tonic-gate static void
1039*7c478bd9Sstevel@tonic-gate alrm(sig)
1040*7c478bd9Sstevel@tonic-gate 	int	sig;
1041*7c478bd9Sstevel@tonic-gate {
1042*7c478bd9Sstevel@tonic-gate 	longjmp(alrm_buf, 1);
1043*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
1044*7c478bd9Sstevel@tonic-gate }
1045*7c478bd9Sstevel@tonic-gate 
1046*7c478bd9Sstevel@tonic-gate void
1047*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
1048*7c478bd9Sstevel@tonic-gate nextdevice(void)
1049*7c478bd9Sstevel@tonic-gate #else
1050*7c478bd9Sstevel@tonic-gate nextdevice()
1051*7c478bd9Sstevel@tonic-gate #endif
1052*7c478bd9Sstevel@tonic-gate {
1053*7c478bd9Sstevel@tonic-gate 	char	*cp;
1054*7c478bd9Sstevel@tonic-gate 
1055*7c478bd9Sstevel@tonic-gate 	if (host != NULL)	/* we set the host only once in ufsdump */
1056*7c478bd9Sstevel@tonic-gate 		return;
1057*7c478bd9Sstevel@tonic-gate 
1058*7c478bd9Sstevel@tonic-gate 	host = NULL;
1059*7c478bd9Sstevel@tonic-gate 	if (strchr(tape, ':')) {
1060*7c478bd9Sstevel@tonic-gate 		if (diskette) {
1061*7c478bd9Sstevel@tonic-gate 			msg(gettext("Cannot do remote dump to diskette\n"));
1062*7c478bd9Sstevel@tonic-gate 			Exit(X_ABORT);
1063*7c478bd9Sstevel@tonic-gate 		}
1064*7c478bd9Sstevel@tonic-gate 		host = tape;
1065*7c478bd9Sstevel@tonic-gate 		tape = strchr(host, ':');
1066*7c478bd9Sstevel@tonic-gate 		*tape++ = 0;
1067*7c478bd9Sstevel@tonic-gate 		cp = strchr(host, '@');	/* user@host? */
1068*7c478bd9Sstevel@tonic-gate 		if (cp != (char *)0)
1069*7c478bd9Sstevel@tonic-gate 			cp++;
1070*7c478bd9Sstevel@tonic-gate 		else
1071*7c478bd9Sstevel@tonic-gate 			cp = host;
1072*7c478bd9Sstevel@tonic-gate 	} else
1073*7c478bd9Sstevel@tonic-gate 		cp = spcl.c_host;
1074*7c478bd9Sstevel@tonic-gate 	/*
1075*7c478bd9Sstevel@tonic-gate 	 * dumpdev is provided for use in prompts and is of
1076*7c478bd9Sstevel@tonic-gate 	 * the form:
1077*7c478bd9Sstevel@tonic-gate 	 *	hostname:device
1078*7c478bd9Sstevel@tonic-gate 	 * sdumpdev is of the form:
1079*7c478bd9Sstevel@tonic-gate 	 *	hostname:device
1080*7c478bd9Sstevel@tonic-gate 	 * for remote devices, and simply:
1081*7c478bd9Sstevel@tonic-gate 	 *	device
1082*7c478bd9Sstevel@tonic-gate 	 * for local devices.
1083*7c478bd9Sstevel@tonic-gate 	 */
1084*7c478bd9Sstevel@tonic-gate 	if (dumpdev != (char *)NULL) {
1085*7c478bd9Sstevel@tonic-gate 		/* LINTED: dumpdev is not NULL */
1086*7c478bd9Sstevel@tonic-gate 		free(dumpdev);
1087*7c478bd9Sstevel@tonic-gate 	}
1088*7c478bd9Sstevel@tonic-gate 	/*LINTED [cast to smaller integer]*/
1089*7c478bd9Sstevel@tonic-gate 	dumpdev = xmalloc((size_t)((sizeof (spcl.c_host) + strlen(tape) + 2)));
1090*7c478bd9Sstevel@tonic-gate 	/* LINTED unsigned -> signed cast ok */
1091*7c478bd9Sstevel@tonic-gate 	(void) sprintf(dumpdev, "%.*s:%s", (int)sizeof (spcl.c_host), cp, tape);
1092*7c478bd9Sstevel@tonic-gate 	if (cp == spcl.c_host)
1093*7c478bd9Sstevel@tonic-gate 		sdumpdev = strchr(dumpdev, ':') + 1;
1094*7c478bd9Sstevel@tonic-gate 	else
1095*7c478bd9Sstevel@tonic-gate 		sdumpdev = dumpdev;
1096*7c478bd9Sstevel@tonic-gate }
1097*7c478bd9Sstevel@tonic-gate 
1098*7c478bd9Sstevel@tonic-gate /*
1099*7c478bd9Sstevel@tonic-gate  * Gross hack due to misfeature of mt tape driver that causes
1100*7c478bd9Sstevel@tonic-gate  * the device to rewind if we generate any signals.  Guess
1101*7c478bd9Sstevel@tonic-gate  * whether tape is rewind device or not -- for local devices
1102*7c478bd9Sstevel@tonic-gate  * we can just look at the minor number.  For rmt devices,
1103*7c478bd9Sstevel@tonic-gate  * make an educated guess.
1104*7c478bd9Sstevel@tonic-gate  */
1105*7c478bd9Sstevel@tonic-gate int
1106*7c478bd9Sstevel@tonic-gate isrewind(f)
1107*7c478bd9Sstevel@tonic-gate 	int	f;	/* fd, if local device */
1108*7c478bd9Sstevel@tonic-gate {
1109*7c478bd9Sstevel@tonic-gate 	struct stat64 sbuf;
1110*7c478bd9Sstevel@tonic-gate 	char    *c;
1111*7c478bd9Sstevel@tonic-gate 	int	unit;
1112*7c478bd9Sstevel@tonic-gate 	int	rewind;
1113*7c478bd9Sstevel@tonic-gate 
1114*7c478bd9Sstevel@tonic-gate 	if (host) {
1115*7c478bd9Sstevel@tonic-gate 		c = strrchr(tape, '/');
1116*7c478bd9Sstevel@tonic-gate 		if (c == NULL)
1117*7c478bd9Sstevel@tonic-gate 			c = tape;
1118*7c478bd9Sstevel@tonic-gate 		else
1119*7c478bd9Sstevel@tonic-gate 			c++;
1120*7c478bd9Sstevel@tonic-gate 		/*
1121*7c478bd9Sstevel@tonic-gate 		 * If the last component begins or ends with an 'n', it is
1122*7c478bd9Sstevel@tonic-gate 		 * assumed to be a non-rewind device.
1123*7c478bd9Sstevel@tonic-gate 		 */
1124*7c478bd9Sstevel@tonic-gate 		if (c[0] == 'n' || c[strlen(c)-1] == 'n')
1125*7c478bd9Sstevel@tonic-gate 			rewind = 0;
1126*7c478bd9Sstevel@tonic-gate 		else if ((strstr(tape, "mt") || strstr(tape, "st")) &&
1127*7c478bd9Sstevel@tonic-gate 		    sscanf(tape, "%*[a-zA-Z/]%d", &unit) == 1 &&
1128*7c478bd9Sstevel@tonic-gate 		    (unit & MT_NOREWIND))
1129*7c478bd9Sstevel@tonic-gate 			rewind = 0;
1130*7c478bd9Sstevel@tonic-gate 		else
1131*7c478bd9Sstevel@tonic-gate 			rewind = 1;
1132*7c478bd9Sstevel@tonic-gate 	} else {
1133*7c478bd9Sstevel@tonic-gate 		if (fstat64(f, &sbuf) < 0) {
1134*7c478bd9Sstevel@tonic-gate 			msg(gettext(
1135*7c478bd9Sstevel@tonic-gate 			    "Cannot obtain status of output device `%s'\n"),
1136*7c478bd9Sstevel@tonic-gate 				tape);
1137*7c478bd9Sstevel@tonic-gate 			dumpabort();
1138*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
1139*7c478bd9Sstevel@tonic-gate 		}
1140*7c478bd9Sstevel@tonic-gate 		rewind = minor(sbuf.st_rdev) & MT_NOREWIND ? 0 : 1;
1141*7c478bd9Sstevel@tonic-gate 	}
1142*7c478bd9Sstevel@tonic-gate 	return (rewind);
1143*7c478bd9Sstevel@tonic-gate }
1144*7c478bd9Sstevel@tonic-gate 
1145*7c478bd9Sstevel@tonic-gate static void
1146*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
1147*7c478bd9Sstevel@tonic-gate just_rewind(void)
1148*7c478bd9Sstevel@tonic-gate #else
1149*7c478bd9Sstevel@tonic-gate just_rewind()
1150*7c478bd9Sstevel@tonic-gate #endif
1151*7c478bd9Sstevel@tonic-gate {
1152*7c478bd9Sstevel@tonic-gate 	struct slaves *slavep;
1153*7c478bd9Sstevel@tonic-gate 	char *rewinding = gettext("Tape rewinding\n");
1154*7c478bd9Sstevel@tonic-gate 
1155*7c478bd9Sstevel@tonic-gate 	for (slavep = &slaves[0]; slavep < &slaves[SLAVES]; slavep++) {
1156*7c478bd9Sstevel@tonic-gate 		if (slavep->sl_slavepid > 0)	/* signal normal exit */
1157*7c478bd9Sstevel@tonic-gate 			(void) kill(slavep->sl_slavepid, SIGTERM);
1158*7c478bd9Sstevel@tonic-gate 		if (slavep->sl_slavefd >= 0) {
1159*7c478bd9Sstevel@tonic-gate 			(void) close(slavep->sl_slavefd);
1160*7c478bd9Sstevel@tonic-gate 			slavep->sl_slavefd = -1;
1161*7c478bd9Sstevel@tonic-gate 		}
1162*7c478bd9Sstevel@tonic-gate 	}
1163*7c478bd9Sstevel@tonic-gate 
1164*7c478bd9Sstevel@tonic-gate 	/* wait for any signals from slaves */
1165*7c478bd9Sstevel@tonic-gate 	while (waitpid(0, (int *)0, 0) >= 0)
1166*7c478bd9Sstevel@tonic-gate 		/*LINTED [empty body]*/
1167*7c478bd9Sstevel@tonic-gate 		continue;
1168*7c478bd9Sstevel@tonic-gate 
1169*7c478bd9Sstevel@tonic-gate 	if (pipeout)
1170*7c478bd9Sstevel@tonic-gate 		return;
1171*7c478bd9Sstevel@tonic-gate 
1172*7c478bd9Sstevel@tonic-gate 	if (doingverify) {
1173*7c478bd9Sstevel@tonic-gate 		/*
1174*7c478bd9Sstevel@tonic-gate 		 * Space to the end of the tape.
1175*7c478bd9Sstevel@tonic-gate 		 * Backup first in case we already read the EOF.
1176*7c478bd9Sstevel@tonic-gate 		 */
1177*7c478bd9Sstevel@tonic-gate 		if (host) {
1178*7c478bd9Sstevel@tonic-gate 			(void) rmtioctl(MTBSR, 1);
1179*7c478bd9Sstevel@tonic-gate 			if (rmtioctl(MTEOM, 1) < 0)
1180*7c478bd9Sstevel@tonic-gate 				(void) rmtioctl(MTFSF, 1);
1181*7c478bd9Sstevel@tonic-gate 		} else {
1182*7c478bd9Sstevel@tonic-gate 			static struct mtop bsr = { MTBSR, 1 };
1183*7c478bd9Sstevel@tonic-gate 			static struct mtop eom = { MTEOM, 1 };
1184*7c478bd9Sstevel@tonic-gate 			static struct mtop fsf = { MTFSF, 1 };
1185*7c478bd9Sstevel@tonic-gate 
1186*7c478bd9Sstevel@tonic-gate 			(void) ioctl(to, MTIOCTOP, &bsr);
1187*7c478bd9Sstevel@tonic-gate 			if (ioctl(to, MTIOCTOP, &eom) < 0)
1188*7c478bd9Sstevel@tonic-gate 				(void) ioctl(to, MTIOCTOP, &fsf);
1189*7c478bd9Sstevel@tonic-gate 		}
1190*7c478bd9Sstevel@tonic-gate 	}
1191*7c478bd9Sstevel@tonic-gate 
1192*7c478bd9Sstevel@tonic-gate 	/*
1193*7c478bd9Sstevel@tonic-gate 	 * Guess whether the tape is rewinding so we can tell
1194*7c478bd9Sstevel@tonic-gate 	 * the operator if it's going to take a long time.
1195*7c478bd9Sstevel@tonic-gate 	 */
1196*7c478bd9Sstevel@tonic-gate 	if (tapeout && isrewind(to)) {
1197*7c478bd9Sstevel@tonic-gate 		/* tape is probably rewinding */
1198*7c478bd9Sstevel@tonic-gate 		msg(rewinding);
1199*7c478bd9Sstevel@tonic-gate 	}
1200*7c478bd9Sstevel@tonic-gate }
1201*7c478bd9Sstevel@tonic-gate 
1202*7c478bd9Sstevel@tonic-gate void
1203*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
1204*7c478bd9Sstevel@tonic-gate trewind(void)
1205*7c478bd9Sstevel@tonic-gate #else
1206*7c478bd9Sstevel@tonic-gate trewind()
1207*7c478bd9Sstevel@tonic-gate #endif
1208*7c478bd9Sstevel@tonic-gate {
1209*7c478bd9Sstevel@tonic-gate 	(void) timeclock((time_t)0);
1210*7c478bd9Sstevel@tonic-gate 	if (offline && (!verify || doingverify)) {
1211*7c478bd9Sstevel@tonic-gate 		close_rewind();
1212*7c478bd9Sstevel@tonic-gate 	} else {
1213*7c478bd9Sstevel@tonic-gate 		just_rewind();
1214*7c478bd9Sstevel@tonic-gate 		if (host)
1215*7c478bd9Sstevel@tonic-gate 			rmtclose();
1216*7c478bd9Sstevel@tonic-gate 		else {
1217*7c478bd9Sstevel@tonic-gate 			(void) close(to);
1218*7c478bd9Sstevel@tonic-gate 			to = -1;
1219*7c478bd9Sstevel@tonic-gate 		}
1220*7c478bd9Sstevel@tonic-gate 	}
1221*7c478bd9Sstevel@tonic-gate }
1222*7c478bd9Sstevel@tonic-gate 
1223*7c478bd9Sstevel@tonic-gate void
1224*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
1225*7c478bd9Sstevel@tonic-gate close_rewind(void)
1226*7c478bd9Sstevel@tonic-gate #else
1227*7c478bd9Sstevel@tonic-gate close_rewind()
1228*7c478bd9Sstevel@tonic-gate #endif
1229*7c478bd9Sstevel@tonic-gate {
1230*7c478bd9Sstevel@tonic-gate 	char *rewinding = gettext("Tape rewinding\n");
1231*7c478bd9Sstevel@tonic-gate 
1232*7c478bd9Sstevel@tonic-gate 	(void) timeclock((time_t)0);
1233*7c478bd9Sstevel@tonic-gate 	just_rewind();
1234*7c478bd9Sstevel@tonic-gate 	/*
1235*7c478bd9Sstevel@tonic-gate 	 * The check in just_rewind won't catch the case in
1236*7c478bd9Sstevel@tonic-gate 	 * which the current volume is being taken off-line
1237*7c478bd9Sstevel@tonic-gate 	 * and is not mounted on a no-rewind device (and is
1238*7c478bd9Sstevel@tonic-gate 	 * not the last volume, which is not taken off-line).
1239*7c478bd9Sstevel@tonic-gate 	 */
1240*7c478bd9Sstevel@tonic-gate 	if (tapeout && !isrewind(to) && offline) {
1241*7c478bd9Sstevel@tonic-gate 		/* tape is probably rewinding */
1242*7c478bd9Sstevel@tonic-gate 		msg(rewinding);
1243*7c478bd9Sstevel@tonic-gate 	}
1244*7c478bd9Sstevel@tonic-gate 	if (host) {
1245*7c478bd9Sstevel@tonic-gate 		if (offline || autoload)
1246*7c478bd9Sstevel@tonic-gate 			(void) rmtioctl(MTOFFL, 0);
1247*7c478bd9Sstevel@tonic-gate 		rmtclose();
1248*7c478bd9Sstevel@tonic-gate 	} else {
1249*7c478bd9Sstevel@tonic-gate 		if (offline || autoload) {
1250*7c478bd9Sstevel@tonic-gate 			static struct mtop offl = { MTOFFL, 0 };
1251*7c478bd9Sstevel@tonic-gate 
1252*7c478bd9Sstevel@tonic-gate 			(void) ioctl(to, MTIOCTOP, &offl);
1253*7c478bd9Sstevel@tonic-gate 			if (diskette)
1254*7c478bd9Sstevel@tonic-gate 				(void) ioctl(to, FDEJECT, 0);
1255*7c478bd9Sstevel@tonic-gate 		}
1256*7c478bd9Sstevel@tonic-gate 		(void) close(to);
1257*7c478bd9Sstevel@tonic-gate 		to = -1;
1258*7c478bd9Sstevel@tonic-gate 	}
1259*7c478bd9Sstevel@tonic-gate }
1260*7c478bd9Sstevel@tonic-gate 
1261*7c478bd9Sstevel@tonic-gate void
1262*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
1263*7c478bd9Sstevel@tonic-gate changevol(void)
1264*7c478bd9Sstevel@tonic-gate #else
1265*7c478bd9Sstevel@tonic-gate changevol()
1266*7c478bd9Sstevel@tonic-gate #endif
1267*7c478bd9Sstevel@tonic-gate {
1268*7c478bd9Sstevel@tonic-gate 	char buf1[3000], buf2[3000];
1269*7c478bd9Sstevel@tonic-gate 	char volname[LBLSIZE+1];
1270*7c478bd9Sstevel@tonic-gate 
1271*7c478bd9Sstevel@tonic-gate 	/*CONSTANTCONDITION*/
1272*7c478bd9Sstevel@tonic-gate 	assert(sizeof (spcl.c_label) < sizeof (volname));
1273*7c478bd9Sstevel@tonic-gate 
1274*7c478bd9Sstevel@tonic-gate 	filenum = 1;
1275*7c478bd9Sstevel@tonic-gate 	nextdevice();
1276*7c478bd9Sstevel@tonic-gate 	(void) strcpy(spcl.c_label, tlabel);
1277*7c478bd9Sstevel@tonic-gate 	if (host) {
1278*7c478bd9Sstevel@tonic-gate 		char	*rhost = host;
1279*7c478bd9Sstevel@tonic-gate 		char	*cp = strchr(host, '@');
1280*7c478bd9Sstevel@tonic-gate 		if (cp == (char *)0)
1281*7c478bd9Sstevel@tonic-gate 			cp = host;
1282*7c478bd9Sstevel@tonic-gate 		else
1283*7c478bd9Sstevel@tonic-gate 			cp++;
1284*7c478bd9Sstevel@tonic-gate 
1285*7c478bd9Sstevel@tonic-gate 		if (rmthost(rhost, ntrec) == 0) {
1286*7c478bd9Sstevel@tonic-gate 			msg(gettext("Cannot connect to tape host `%s'\n"), cp);
1287*7c478bd9Sstevel@tonic-gate 			dumpabort();
1288*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
1289*7c478bd9Sstevel@tonic-gate 		}
1290*7c478bd9Sstevel@tonic-gate 		if (rhost != host)
1291*7c478bd9Sstevel@tonic-gate 			free(rhost);
1292*7c478bd9Sstevel@tonic-gate 	}
1293*7c478bd9Sstevel@tonic-gate 
1294*7c478bd9Sstevel@tonic-gate 	/*
1295*7c478bd9Sstevel@tonic-gate 	 * Make volume switching as automatic as possible
1296*7c478bd9Sstevel@tonic-gate 	 * while avoiding overwriting volumes.  We will
1297*7c478bd9Sstevel@tonic-gate 	 * switch automatically under the following condition:
1298*7c478bd9Sstevel@tonic-gate 	 *    1) The user specified autoloading from the
1299*7c478bd9Sstevel@tonic-gate 	 *	command line.
1300*7c478bd9Sstevel@tonic-gate 	 * At one time, we (in the guise of hsmdump) had the
1301*7c478bd9Sstevel@tonic-gate 	 * concept of a sequence of devices to rotate through,
1302*7c478bd9Sstevel@tonic-gate 	 * but that's never been a ufsdump feature.
1303*7c478bd9Sstevel@tonic-gate 	 */
1304*7c478bd9Sstevel@tonic-gate 	if (autoload) {
1305*7c478bd9Sstevel@tonic-gate 		int tries;
1306*7c478bd9Sstevel@tonic-gate 
1307*7c478bd9Sstevel@tonic-gate 		/*
1308*7c478bd9Sstevel@tonic-gate 		 * Stop the clock for throughput calculations.
1309*7c478bd9Sstevel@tonic-gate 		 */
1310*7c478bd9Sstevel@tonic-gate 		if ((telapsed != NULL) && (tstart_writing != NULL)) {
1311*7c478bd9Sstevel@tonic-gate 			*telapsed += time((time_t *)NULL) - *tstart_writing;
1312*7c478bd9Sstevel@tonic-gate 		}
1313*7c478bd9Sstevel@tonic-gate 
1314*7c478bd9Sstevel@tonic-gate 		(void) snprintf(volname, sizeof (volname), "#%d", tapeno+1);
1315*7c478bd9Sstevel@tonic-gate 		(void) snprintf(buf1, sizeof (buf1), gettext(
1316*7c478bd9Sstevel@tonic-gate 		    "Mounting volume %s on %s\n"), volname, dumpdev);
1317*7c478bd9Sstevel@tonic-gate 		msg(buf1);
1318*7c478bd9Sstevel@tonic-gate 		broadcast(buf1);
1319*7c478bd9Sstevel@tonic-gate 
1320*7c478bd9Sstevel@tonic-gate 		/*
1321*7c478bd9Sstevel@tonic-gate 		 * Wait for the tape to autoload.  Note that the delay
1322*7c478bd9Sstevel@tonic-gate 		 * period doesn't take into account however long it takes
1323*7c478bd9Sstevel@tonic-gate 		 * for the open to fail (measured at 21 seconds for an
1324*7c478bd9Sstevel@tonic-gate 		 * Exabyte 8200 under 2.7 on an Ultra 2).
1325*7c478bd9Sstevel@tonic-gate 		 */
1326*7c478bd9Sstevel@tonic-gate 		for (tries = 0; tries < autoload_tries; tries++) {
1327*7c478bd9Sstevel@tonic-gate 			if (host) {
1328*7c478bd9Sstevel@tonic-gate 				if (rmtopen(tape, O_RDONLY) >= 0) {
1329*7c478bd9Sstevel@tonic-gate 					rmtclose();
1330*7c478bd9Sstevel@tonic-gate 					return;
1331*7c478bd9Sstevel@tonic-gate 				}
1332*7c478bd9Sstevel@tonic-gate 			} else {
1333*7c478bd9Sstevel@tonic-gate 				int f, m;
1334*7c478bd9Sstevel@tonic-gate 
1335*7c478bd9Sstevel@tonic-gate 				m = (access(tape, F_OK) == 0) ? 0 : O_CREAT;
1336*7c478bd9Sstevel@tonic-gate 				if ((f = doingverify ?
1337*7c478bd9Sstevel@tonic-gate 				    safe_device_open(tape, O_RDONLY, 0600) :
1338*7c478bd9Sstevel@tonic-gate 				    safe_device_open(tape, O_RDONLY|m, 0600))
1339*7c478bd9Sstevel@tonic-gate 				    >= 0) {
1340*7c478bd9Sstevel@tonic-gate 					(void) close(f);
1341*7c478bd9Sstevel@tonic-gate 					return;
1342*7c478bd9Sstevel@tonic-gate 				}
1343*7c478bd9Sstevel@tonic-gate 			}
1344*7c478bd9Sstevel@tonic-gate 			(void) sleep(autoload_period);
1345*7c478bd9Sstevel@tonic-gate 		}
1346*7c478bd9Sstevel@tonic-gate 		/*
1347*7c478bd9Sstevel@tonic-gate 		 * Autoload timed out, ask the operator to do it.
1348*7c478bd9Sstevel@tonic-gate 		 * Note that query() will update *telapsed, and we
1349*7c478bd9Sstevel@tonic-gate 		 * shouldn't charge for the autoload time.  So, since
1350*7c478bd9Sstevel@tonic-gate 		 * we updated *telapsed ourselves above, we just set
1351*7c478bd9Sstevel@tonic-gate 		 * tstart_writing to the current time, and query()
1352*7c478bd9Sstevel@tonic-gate 		 * will end up making a null-effect change.  This,
1353*7c478bd9Sstevel@tonic-gate 		 * of course, assumes that our caller will be resetting
1354*7c478bd9Sstevel@tonic-gate 		 * *tstart_writing.  This is currently the case.
1355*7c478bd9Sstevel@tonic-gate 		 * If tstart_writing is NULL (should never happen),
1356*7c478bd9Sstevel@tonic-gate 		 * we're ok, since time(2) will accept a NULL pointer.
1357*7c478bd9Sstevel@tonic-gate 		 */
1358*7c478bd9Sstevel@tonic-gate 		(void) time(tstart_writing);
1359*7c478bd9Sstevel@tonic-gate 	}
1360*7c478bd9Sstevel@tonic-gate 
1361*7c478bd9Sstevel@tonic-gate 	if (strncmp(spcl.c_label, "none", 5)) {
1362*7c478bd9Sstevel@tonic-gate 		(void) strncpy(volname, spcl.c_label, sizeof (spcl.c_label));
1363*7c478bd9Sstevel@tonic-gate 		volname[sizeof (spcl.c_label)] = '\0';
1364*7c478bd9Sstevel@tonic-gate 	} else
1365*7c478bd9Sstevel@tonic-gate 		(void) snprintf(volname, sizeof (volname), "#%d", tapeno+1);
1366*7c478bd9Sstevel@tonic-gate 
1367*7c478bd9Sstevel@tonic-gate 	timeest(1, spcl.c_tapea);
1368*7c478bd9Sstevel@tonic-gate 	(void) snprintf(buf1, sizeof (buf1), gettext(
1369*7c478bd9Sstevel@tonic-gate 	    "Change Volumes: Mount volume `%s' on `%s'\n"), volname, dumpdev);
1370*7c478bd9Sstevel@tonic-gate 	msg(buf1);
1371*7c478bd9Sstevel@tonic-gate 	broadcast(gettext("CHANGE VOLUMES!\7\7\n"));
1372*7c478bd9Sstevel@tonic-gate 	(void) snprintf(buf1, sizeof (buf1), gettext(
1373*7c478bd9Sstevel@tonic-gate 	    "Is the new volume (%s) mounted on `%s' and ready to go?: %s"),
1374*7c478bd9Sstevel@tonic-gate 	    volname, dumpdev, gettext("(\"yes\" or \"no\") "));
1375*7c478bd9Sstevel@tonic-gate 	while (!query(buf1)) {
1376*7c478bd9Sstevel@tonic-gate 		(void) snprintf(buf2, sizeof (buf2), gettext(
1377*7c478bd9Sstevel@tonic-gate 		    "Do you want to abort dump?: (\"yes\" or \"no\") "));
1378*7c478bd9Sstevel@tonic-gate 		if (query(buf2)) {
1379*7c478bd9Sstevel@tonic-gate 			dumpabort();
1380*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
1381*7c478bd9Sstevel@tonic-gate 		}
1382*7c478bd9Sstevel@tonic-gate 	}
1383*7c478bd9Sstevel@tonic-gate }
1384*7c478bd9Sstevel@tonic-gate 
1385*7c478bd9Sstevel@tonic-gate /*
1386*7c478bd9Sstevel@tonic-gate  *	We implement taking and restoring checkpoints on the tape level.
1387*7c478bd9Sstevel@tonic-gate  *	When each tape is opened, a new process is created by forking; this
1388*7c478bd9Sstevel@tonic-gate  *	saves all of the necessary context in the parent.  The child
1389*7c478bd9Sstevel@tonic-gate  *	continues the dump; the parent waits around, saving the context.
1390*7c478bd9Sstevel@tonic-gate  *	If the child returns X_REWRITE, then it had problems writing that tape;
1391*7c478bd9Sstevel@tonic-gate  *	this causes the parent to fork again, duplicating the context, and
1392*7c478bd9Sstevel@tonic-gate  *	everything continues as if nothing had happened.
1393*7c478bd9Sstevel@tonic-gate  */
1394*7c478bd9Sstevel@tonic-gate 
1395*7c478bd9Sstevel@tonic-gate void
1396*7c478bd9Sstevel@tonic-gate otape(top)
1397*7c478bd9Sstevel@tonic-gate 	int top;
1398*7c478bd9Sstevel@tonic-gate {
1399*7c478bd9Sstevel@tonic-gate 	static struct mtget mt;
1400*7c478bd9Sstevel@tonic-gate 	char buf[3000];
1401*7c478bd9Sstevel@tonic-gate 	pid_t parentpid;
1402*7c478bd9Sstevel@tonic-gate 	pid_t childpid;
1403*7c478bd9Sstevel@tonic-gate 	pid_t waitproc;
1404*7c478bd9Sstevel@tonic-gate 	int status;
1405*7c478bd9Sstevel@tonic-gate 	struct sigvec sv, osv;
1406*7c478bd9Sstevel@tonic-gate 
1407*7c478bd9Sstevel@tonic-gate 	sv.sv_flags = SA_RESTART;
1408*7c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&sv.sa_mask);
1409*7c478bd9Sstevel@tonic-gate 	sv.sv_handler = SIG_IGN;
1410*7c478bd9Sstevel@tonic-gate 	(void) sigvec(SIGINT, &sv, (struct sigvec *)0);
1411*7c478bd9Sstevel@tonic-gate 
1412*7c478bd9Sstevel@tonic-gate 	parentpid = getpid();
1413*7c478bd9Sstevel@tonic-gate 
1414*7c478bd9Sstevel@tonic-gate 	if (verify) {
1415*7c478bd9Sstevel@tonic-gate 		if (doingverify)
1416*7c478bd9Sstevel@tonic-gate 			doingverify = 0;
1417*7c478bd9Sstevel@tonic-gate 		else
1418*7c478bd9Sstevel@tonic-gate 			Exit(X_VERIFY);
1419*7c478bd9Sstevel@tonic-gate 	}
1420*7c478bd9Sstevel@tonic-gate restore_check_point:
1421*7c478bd9Sstevel@tonic-gate 
1422*7c478bd9Sstevel@tonic-gate 	sv.sv_handler = interrupt;
1423*7c478bd9Sstevel@tonic-gate 	(void) sigvec(SIGINT, &sv, (struct sigvec *)0);
1424*7c478bd9Sstevel@tonic-gate 	(void) fflush(stderr);
1425*7c478bd9Sstevel@tonic-gate 	/*
1426*7c478bd9Sstevel@tonic-gate 	 *	All signals are inherited...
1427*7c478bd9Sstevel@tonic-gate 	 */
1428*7c478bd9Sstevel@tonic-gate 	sighold(SIGINT);
1429*7c478bd9Sstevel@tonic-gate 	childpid = fork();
1430*7c478bd9Sstevel@tonic-gate 	if (childpid < 0) {
1431*7c478bd9Sstevel@tonic-gate 		msg(gettext(
1432*7c478bd9Sstevel@tonic-gate 		    "Context-saving fork failed in parent %ld\n"),
1433*7c478bd9Sstevel@tonic-gate 			(long)parentpid);
1434*7c478bd9Sstevel@tonic-gate 		Exit(X_ABORT);
1435*7c478bd9Sstevel@tonic-gate 	}
1436*7c478bd9Sstevel@tonic-gate 	if (childpid != 0) {
1437*7c478bd9Sstevel@tonic-gate 		/*
1438*7c478bd9Sstevel@tonic-gate 		 *	PARENT:
1439*7c478bd9Sstevel@tonic-gate 		 *	save the context by waiting
1440*7c478bd9Sstevel@tonic-gate 		 *	until the child doing all of the work returns.
1441*7c478bd9Sstevel@tonic-gate 		 *	let the child catch user interrupts
1442*7c478bd9Sstevel@tonic-gate 		 */
1443*7c478bd9Sstevel@tonic-gate 		sv.sv_handler = SIG_IGN;
1444*7c478bd9Sstevel@tonic-gate 		(void) sigvec(SIGINT, &sv, (struct sigvec *)0);
1445*7c478bd9Sstevel@tonic-gate 		sigrelse(SIGINT);
1446*7c478bd9Sstevel@tonic-gate #ifdef TDEBUG
1447*7c478bd9Sstevel@tonic-gate 
1448*7c478bd9Sstevel@tonic-gate 		/* XGETTEXT:  #ifdef TDEBUG only */
1449*7c478bd9Sstevel@tonic-gate 		msg(gettext(
1450*7c478bd9Sstevel@tonic-gate 		    "Volume: %d; parent process: %ld child process %ld\n"),
1451*7c478bd9Sstevel@tonic-gate 			tapeno+1, (long)parentpid, (long)childpid);
1452*7c478bd9Sstevel@tonic-gate #endif /* TDEBUG */
1453*7c478bd9Sstevel@tonic-gate 		for (;;) {
1454*7c478bd9Sstevel@tonic-gate 			waitproc = waitpid(0, &status, 0);
1455*7c478bd9Sstevel@tonic-gate 			if (waitproc == childpid)
1456*7c478bd9Sstevel@tonic-gate 				break;
1457*7c478bd9Sstevel@tonic-gate 			msg(gettext(
1458*7c478bd9Sstevel@tonic-gate 	"Parent %ld waiting for child %ld had another child %ld return\n"),
1459*7c478bd9Sstevel@tonic-gate 			    (long)parentpid, (long)childpid, (long)waitproc);
1460*7c478bd9Sstevel@tonic-gate 		}
1461*7c478bd9Sstevel@tonic-gate 		if (WIFSIGNALED(status)) {
1462*7c478bd9Sstevel@tonic-gate 			msg(gettext("Process %ld killed by signal %d: %s\n"),
1463*7c478bd9Sstevel@tonic-gate 			    (long)childpid, WTERMSIG(status),
1464*7c478bd9Sstevel@tonic-gate 			    strsignal(WTERMSIG(status)));
1465*7c478bd9Sstevel@tonic-gate 			status = X_ABORT;
1466*7c478bd9Sstevel@tonic-gate 		} else
1467*7c478bd9Sstevel@tonic-gate 			status = WEXITSTATUS(status);
1468*7c478bd9Sstevel@tonic-gate #ifdef TDEBUG
1469*7c478bd9Sstevel@tonic-gate 		switch (status) {
1470*7c478bd9Sstevel@tonic-gate 		case X_FINOK:
1471*7c478bd9Sstevel@tonic-gate 			/* XGETTEXT:  #ifdef TDEBUG only */
1472*7c478bd9Sstevel@tonic-gate 			msg(gettext(
1473*7c478bd9Sstevel@tonic-gate 			    "Child %ld finishes X_FINOK\n"), (long)childpid);
1474*7c478bd9Sstevel@tonic-gate 			break;
1475*7c478bd9Sstevel@tonic-gate 		case X_ABORT:
1476*7c478bd9Sstevel@tonic-gate 			/* XGETTEXT:  #ifdef TDEBUG only */
1477*7c478bd9Sstevel@tonic-gate 			msg(gettext(
1478*7c478bd9Sstevel@tonic-gate 			    "Child %ld finishes X_ABORT\n"), (long)childpid);
1479*7c478bd9Sstevel@tonic-gate 			break;
1480*7c478bd9Sstevel@tonic-gate 		case X_REWRITE:
1481*7c478bd9Sstevel@tonic-gate 			/* XGETTEXT:  #ifdef TDEBUG only */
1482*7c478bd9Sstevel@tonic-gate 			msg(gettext(
1483*7c478bd9Sstevel@tonic-gate 			    "Child %ld finishes X_REWRITE\n"), (long)childpid);
1484*7c478bd9Sstevel@tonic-gate 			break;
1485*7c478bd9Sstevel@tonic-gate 		case X_RESTART:
1486*7c478bd9Sstevel@tonic-gate 			/* XGETTEXT:  #ifdef TDEBUG only */
1487*7c478bd9Sstevel@tonic-gate 			msg(gettext(
1488*7c478bd9Sstevel@tonic-gate 			    "Child %ld finishes X_RESTART\n"), (long)childpid);
1489*7c478bd9Sstevel@tonic-gate 			break;
1490*7c478bd9Sstevel@tonic-gate 		case X_VERIFY:
1491*7c478bd9Sstevel@tonic-gate 			/* XGETTEXT:  #ifdef TDEBUG only */
1492*7c478bd9Sstevel@tonic-gate 			msg(gettext(
1493*7c478bd9Sstevel@tonic-gate 			    "Child %ld finishes X_VERIFY\n"), (long)childpid);
1494*7c478bd9Sstevel@tonic-gate 			break;
1495*7c478bd9Sstevel@tonic-gate 		default:
1496*7c478bd9Sstevel@tonic-gate 			/* XGETTEXT:  #ifdef TDEBUG only */
1497*7c478bd9Sstevel@tonic-gate 			msg(gettext("Child %ld finishes unknown %d\n"),
1498*7c478bd9Sstevel@tonic-gate 			    (long)childpid, status);
1499*7c478bd9Sstevel@tonic-gate 			break;
1500*7c478bd9Sstevel@tonic-gate 		}
1501*7c478bd9Sstevel@tonic-gate #endif /* TDEBUG */
1502*7c478bd9Sstevel@tonic-gate 		switch (status) {
1503*7c478bd9Sstevel@tonic-gate 		case X_FINOK:
1504*7c478bd9Sstevel@tonic-gate 			/* wait for children */
1505*7c478bd9Sstevel@tonic-gate 			while (waitpid(0, (int *)0, 0) >= 0)
1506*7c478bd9Sstevel@tonic-gate 				/*LINTED [empty body]*/
1507*7c478bd9Sstevel@tonic-gate 				continue;
1508*7c478bd9Sstevel@tonic-gate 			Exit(X_FINOK);
1509*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
1510*7c478bd9Sstevel@tonic-gate 		case X_ABORT:
1511*7c478bd9Sstevel@tonic-gate 			Exit(X_ABORT);
1512*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
1513*7c478bd9Sstevel@tonic-gate 		case X_VERIFY:
1514*7c478bd9Sstevel@tonic-gate 			doingverify++;
1515*7c478bd9Sstevel@tonic-gate 			goto restore_check_point;
1516*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
1517*7c478bd9Sstevel@tonic-gate 		case X_REWRITE:
1518*7c478bd9Sstevel@tonic-gate 			doingverify = 0;
1519*7c478bd9Sstevel@tonic-gate 			changevol();
1520*7c478bd9Sstevel@tonic-gate 			goto restore_check_point;
1521*7c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
1522*7c478bd9Sstevel@tonic-gate 		case X_RESTART:
1523*7c478bd9Sstevel@tonic-gate 			doingverify = 0;
1524*7c478bd9Sstevel@tonic-gate 			if (!top) {
1525*7c478bd9Sstevel@tonic-gate 				Exit(X_RESTART);
1526*7c478bd9Sstevel@tonic-gate 			}
1527*7c478bd9Sstevel@tonic-gate 			if (!offline)
1528*7c478bd9Sstevel@tonic-gate 				autoload = 0;
1529*7c478bd9Sstevel@tonic-gate 			changevol();
1530*7c478bd9Sstevel@tonic-gate 			sv.sv_handler = interrupt;
1531*7c478bd9Sstevel@tonic-gate 			(void) sigvec(SIGINT, &sv, (struct sigvec *)0);
1532*7c478bd9Sstevel@tonic-gate 			return;
1533*7c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
1534*7c478bd9Sstevel@tonic-gate 		default:
1535*7c478bd9Sstevel@tonic-gate 			msg(gettext("Bad return code from dump: %d\n"), status);
1536*7c478bd9Sstevel@tonic-gate 			Exit(X_ABORT);
1537*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
1538*7c478bd9Sstevel@tonic-gate 		}
1539*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
1540*7c478bd9Sstevel@tonic-gate 	} else {	/* we are the child; just continue */
1541*7c478bd9Sstevel@tonic-gate 		child_chdir();
1542*7c478bd9Sstevel@tonic-gate 		sigrelse(SIGINT);
1543*7c478bd9Sstevel@tonic-gate #ifdef TDEBUG
1544*7c478bd9Sstevel@tonic-gate 		(void) sleep(4); /* time for parent's message to get out */
1545*7c478bd9Sstevel@tonic-gate 		/* XGETTEXT:  #ifdef TDEBUG only */
1546*7c478bd9Sstevel@tonic-gate 		msg(gettext(
1547*7c478bd9Sstevel@tonic-gate 		    "Child on Volume %d has parent %ld, my pid = %ld\n"),
1548*7c478bd9Sstevel@tonic-gate 			tapeno+1, (long)parentpid, (long)getpid());
1549*7c478bd9Sstevel@tonic-gate #endif
1550*7c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), gettext(
1551*7c478bd9Sstevel@tonic-gate "Cannot open `%s'.  Do you want to retry the open?: (\"yes\" or \"no\") "),
1552*7c478bd9Sstevel@tonic-gate 		    dumpdev);
1553*7c478bd9Sstevel@tonic-gate 		if (doingverify) {
1554*7c478bd9Sstevel@tonic-gate 			/* 1 for stdout */
1555*7c478bd9Sstevel@tonic-gate 			while ((to = host ? rmtopen(tape, O_RDONLY) :
1556*7c478bd9Sstevel@tonic-gate 			    pipeout ? 1 :
1557*7c478bd9Sstevel@tonic-gate 			    safe_device_open(tape, O_RDONLY, 0600)) < 0) {
1558*7c478bd9Sstevel@tonic-gate 				perror(tape);
1559*7c478bd9Sstevel@tonic-gate 				if (autoload) {
1560*7c478bd9Sstevel@tonic-gate 					if (!query_once(buf, 1)) {
1561*7c478bd9Sstevel@tonic-gate 						dumpabort();
1562*7c478bd9Sstevel@tonic-gate 						/*NOTREACHED*/
1563*7c478bd9Sstevel@tonic-gate 					}
1564*7c478bd9Sstevel@tonic-gate 				} else {
1565*7c478bd9Sstevel@tonic-gate 					if (!query(buf)) {
1566*7c478bd9Sstevel@tonic-gate 						dumpabort();
1567*7c478bd9Sstevel@tonic-gate 						/*NOTREACHED*/
1568*7c478bd9Sstevel@tonic-gate 					}
1569*7c478bd9Sstevel@tonic-gate 				}
1570*7c478bd9Sstevel@tonic-gate 			}
1571*7c478bd9Sstevel@tonic-gate 
1572*7c478bd9Sstevel@tonic-gate 			/*
1573*7c478bd9Sstevel@tonic-gate 			 * If we're using the non-rewinding tape device,
1574*7c478bd9Sstevel@tonic-gate 			 * the tape will be left positioned after the
1575*7c478bd9Sstevel@tonic-gate 			 * EOF mark.  We need to back up to the beginning
1576*7c478bd9Sstevel@tonic-gate 			 * of this tape file (cross two tape marks in the
1577*7c478bd9Sstevel@tonic-gate 			 * reverse direction and one in the forward
1578*7c478bd9Sstevel@tonic-gate 			 * direction) before the verify pass.
1579*7c478bd9Sstevel@tonic-gate 			 */
1580*7c478bd9Sstevel@tonic-gate 			if (host) {
1581*7c478bd9Sstevel@tonic-gate 				if (rmtioctl(MTBSF, 2) >= 0)
1582*7c478bd9Sstevel@tonic-gate 					(void) rmtioctl(MTFSF, 1);
1583*7c478bd9Sstevel@tonic-gate 				else
1584*7c478bd9Sstevel@tonic-gate 					(void) rmtioctl(MTNBSF, 1);
1585*7c478bd9Sstevel@tonic-gate 			} else {
1586*7c478bd9Sstevel@tonic-gate 				static struct mtop bsf = { MTBSF, 2 };
1587*7c478bd9Sstevel@tonic-gate 				static struct mtop fsf = { MTFSF, 1 };
1588*7c478bd9Sstevel@tonic-gate 				static struct mtop nbsf = { MTNBSF, 1 };
1589*7c478bd9Sstevel@tonic-gate 
1590*7c478bd9Sstevel@tonic-gate 				if (ioctl(to, MTIOCTOP, &bsf) >= 0)
1591*7c478bd9Sstevel@tonic-gate 					(void) ioctl(to, MTIOCTOP, &fsf);
1592*7c478bd9Sstevel@tonic-gate 				else
1593*7c478bd9Sstevel@tonic-gate 					(void) ioctl(to, MTIOCTOP, &nbsf);
1594*7c478bd9Sstevel@tonic-gate 			}
1595*7c478bd9Sstevel@tonic-gate 		} else {
1596*7c478bd9Sstevel@tonic-gate 			/*
1597*7c478bd9Sstevel@tonic-gate 			 * XXX Add logic to test for "tape" being a
1598*7c478bd9Sstevel@tonic-gate 			 * XXX device or a non-existent file.
1599*7c478bd9Sstevel@tonic-gate 			 * Current behaviour is that it must exist,
1600*7c478bd9Sstevel@tonic-gate 			 * and we over-write whatever's there.
1601*7c478bd9Sstevel@tonic-gate 			 * This can be bad if tape == "/etc/passwd".
1602*7c478bd9Sstevel@tonic-gate 			 */
1603*7c478bd9Sstevel@tonic-gate 			if (!pipeout && doposition && (tapeno == 0)) {
1604*7c478bd9Sstevel@tonic-gate 				positiontape(buf);
1605*7c478bd9Sstevel@tonic-gate 				if (setjmp(alrm_buf)) {
1606*7c478bd9Sstevel@tonic-gate 					/*
1607*7c478bd9Sstevel@tonic-gate 					 * The tape is rewinding;
1608*7c478bd9Sstevel@tonic-gate 					 * we're screwed.
1609*7c478bd9Sstevel@tonic-gate 					 */
1610*7c478bd9Sstevel@tonic-gate 				    msg(gettext(
1611*7c478bd9Sstevel@tonic-gate 			    "Cannot position tape using rewind device!\n"));
1612*7c478bd9Sstevel@tonic-gate 				    dumpabort();
1613*7c478bd9Sstevel@tonic-gate 				    /*NOTREACHED*/
1614*7c478bd9Sstevel@tonic-gate 				} else {
1615*7c478bd9Sstevel@tonic-gate 					sv.sv_handler = alrm;
1616*7c478bd9Sstevel@tonic-gate 					(void) sigvec(SIGALRM, &sv, &osv);
1617*7c478bd9Sstevel@tonic-gate 					(void) alarm(15);
1618*7c478bd9Sstevel@tonic-gate 				}
1619*7c478bd9Sstevel@tonic-gate 				while ((to = host ? rmtopen(tape, O_WRONLY) :
1620*7c478bd9Sstevel@tonic-gate 				    safe_device_open(tape, O_WRONLY, 0600)) < 0)
1621*7c478bd9Sstevel@tonic-gate 					(void) sleep(10);
1622*7c478bd9Sstevel@tonic-gate 				(void) alarm(0);
1623*7c478bd9Sstevel@tonic-gate 				(void) sigvec(SIGALRM, &osv,
1624*7c478bd9Sstevel@tonic-gate 				    (struct sigvec *)0);
1625*7c478bd9Sstevel@tonic-gate 			} else {
1626*7c478bd9Sstevel@tonic-gate 				int m;
1627*7c478bd9Sstevel@tonic-gate 				m = (access(tape, F_OK) == 0) ? 0 : O_CREAT;
1628*7c478bd9Sstevel@tonic-gate 				/*
1629*7c478bd9Sstevel@tonic-gate 				 * Only verify the tape label if label
1630*7c478bd9Sstevel@tonic-gate 				 * verification is on and we are at BOT
1631*7c478bd9Sstevel@tonic-gate 				 */
1632*7c478bd9Sstevel@tonic-gate 				if (pipeout)
1633*7c478bd9Sstevel@tonic-gate 					to = 1;
1634*7c478bd9Sstevel@tonic-gate 				else while ((to = host ?
1635*7c478bd9Sstevel@tonic-gate 				    rmtopen(tape, O_WRONLY) :
1636*7c478bd9Sstevel@tonic-gate 				    safe_device_open(tape, O_WRONLY|m, 0600))
1637*7c478bd9Sstevel@tonic-gate 				    < 0)
1638*7c478bd9Sstevel@tonic-gate 					if (!query_once(buf, 1)) {
1639*7c478bd9Sstevel@tonic-gate 						dumpabort();
1640*7c478bd9Sstevel@tonic-gate 						/*NOTREACHED*/
1641*7c478bd9Sstevel@tonic-gate 					}
1642*7c478bd9Sstevel@tonic-gate 			}
1643*7c478bd9Sstevel@tonic-gate 		}
1644*7c478bd9Sstevel@tonic-gate 		if (!pipeout) {
1645*7c478bd9Sstevel@tonic-gate 			tapeout = host ? rmtstatus(&mt) >= 0 :
1646*7c478bd9Sstevel@tonic-gate 			    ioctl(to, MTIOCGET, &mt) >= 0;	/* set state */
1647*7c478bd9Sstevel@tonic-gate 			/*
1648*7c478bd9Sstevel@tonic-gate 			 * Make sure the tape is positioned
1649*7c478bd9Sstevel@tonic-gate 			 * where it is supposed to be
1650*7c478bd9Sstevel@tonic-gate 			 */
1651*7c478bd9Sstevel@tonic-gate 			if (tapeout && (tapeno > 0) &&
1652*7c478bd9Sstevel@tonic-gate 			    (mt.mt_fileno != (filenum-1))) {
1653*7c478bd9Sstevel@tonic-gate 				(void) snprintf(buf, sizeof (buf), gettext(
1654*7c478bd9Sstevel@tonic-gate 				    "Warning - tape positioning error!\n\
1655*7c478bd9Sstevel@tonic-gate \t%s current file %ld, should be %ld\n"),
1656*7c478bd9Sstevel@tonic-gate 				    tape, mt.mt_fileno+1, filenum);
1657*7c478bd9Sstevel@tonic-gate 				msg(buf);
1658*7c478bd9Sstevel@tonic-gate 				dumpailing();
1659*7c478bd9Sstevel@tonic-gate 			}
1660*7c478bd9Sstevel@tonic-gate 		}
1661*7c478bd9Sstevel@tonic-gate 		tapeno++;		/* current tape sequence */
1662*7c478bd9Sstevel@tonic-gate 		if (tapeno < TP_NINOS)
1663*7c478bd9Sstevel@tonic-gate 			inos[tapeno] = chkpt.sl_inos;
1664*7c478bd9Sstevel@tonic-gate 		spcl.c_firstrec = chkpt.sl_firstrec;
1665*7c478bd9Sstevel@tonic-gate 		spcl.c_tapea = (*tapea) = chkpt.sl_tapea;
1666*7c478bd9Sstevel@tonic-gate 		spcl.c_volume++;
1667*7c478bd9Sstevel@tonic-gate 
1668*7c478bd9Sstevel@tonic-gate 		enslave();	/* Share tape buffers with slaves */
1669*7c478bd9Sstevel@tonic-gate 
1670*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1671*7c478bd9Sstevel@tonic-gate 		if (xflag) {
1672*7c478bd9Sstevel@tonic-gate 			/* XGETTEXT:  #ifdef DEBUG only */
1673*7c478bd9Sstevel@tonic-gate 			msg(gettext("Checkpoint state:\n"));
1674*7c478bd9Sstevel@tonic-gate 			msg("    blockswritten %u\n", blockswritten);
1675*7c478bd9Sstevel@tonic-gate 			msg("    ino %u\n", ino);
1676*7c478bd9Sstevel@tonic-gate 			msg("    pos %u\n", pos);
1677*7c478bd9Sstevel@tonic-gate 			msg("    left %u\n", leftover);
1678*7c478bd9Sstevel@tonic-gate 			msg("    tapea %u\n", (*tapea));
1679*7c478bd9Sstevel@tonic-gate 			msg("    state %d\n", dumpstate);
1680*7c478bd9Sstevel@tonic-gate 		}
1681*7c478bd9Sstevel@tonic-gate #endif
1682*7c478bd9Sstevel@tonic-gate 		spcl.c_type = TS_TAPE;
1683*7c478bd9Sstevel@tonic-gate 		spcl.c_tpbsize = tp_bsize;
1684*7c478bd9Sstevel@tonic-gate 		if (leftover == 0) {
1685*7c478bd9Sstevel@tonic-gate 			spcl.c_count = 0;
1686*7c478bd9Sstevel@tonic-gate 			spclrec();
1687*7c478bd9Sstevel@tonic-gate 			newtape = 0;
1688*7c478bd9Sstevel@tonic-gate 		} else
1689*7c478bd9Sstevel@tonic-gate 			newtape++;	/* new volume indication */
1690*7c478bd9Sstevel@tonic-gate 		if (doingverify) {
1691*7c478bd9Sstevel@tonic-gate 			msg(gettext("Starting verify pass\n"));
1692*7c478bd9Sstevel@tonic-gate 		} else if (tapeno > 1) {
1693*7c478bd9Sstevel@tonic-gate 			msg(gettext(
1694*7c478bd9Sstevel@tonic-gate 			    "Volume %d begins with blocks from inode %lu\n"),
1695*7c478bd9Sstevel@tonic-gate 				tapeno, chkpt.sl_inos);
1696*7c478bd9Sstevel@tonic-gate 		}
1697*7c478bd9Sstevel@tonic-gate 		(void) timeclock((time_t)1);
1698*7c478bd9Sstevel@tonic-gate 		(void) time(tstart_writing);
1699*7c478bd9Sstevel@tonic-gate 		timeest(0, spcl.c_tapea);
1700*7c478bd9Sstevel@tonic-gate 	}
1701*7c478bd9Sstevel@tonic-gate }
1702*7c478bd9Sstevel@tonic-gate 
1703*7c478bd9Sstevel@tonic-gate void
1704*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
1705*7c478bd9Sstevel@tonic-gate dumpabort(void)
1706*7c478bd9Sstevel@tonic-gate #else
1707*7c478bd9Sstevel@tonic-gate dumpabort()
1708*7c478bd9Sstevel@tonic-gate #endif
1709*7c478bd9Sstevel@tonic-gate {
1710*7c478bd9Sstevel@tonic-gate 
1711*7c478bd9Sstevel@tonic-gate 	if (master && master != getpid())
1712*7c478bd9Sstevel@tonic-gate 		/*
1713*7c478bd9Sstevel@tonic-gate 		 * signal master to call dumpabort
1714*7c478bd9Sstevel@tonic-gate 		 */
1715*7c478bd9Sstevel@tonic-gate 		(void) kill(master, SIGTERM);
1716*7c478bd9Sstevel@tonic-gate 	else {
1717*7c478bd9Sstevel@tonic-gate 		killall();
1718*7c478bd9Sstevel@tonic-gate 
1719*7c478bd9Sstevel@tonic-gate 		if (archivefile)
1720*7c478bd9Sstevel@tonic-gate 			(void) unlink(archivefile);
1721*7c478bd9Sstevel@tonic-gate 		msg(gettext("The ENTIRE dump is aborted.\n"));
1722*7c478bd9Sstevel@tonic-gate 	}
1723*7c478bd9Sstevel@tonic-gate 	Exit(X_ABORT);
1724*7c478bd9Sstevel@tonic-gate }
1725*7c478bd9Sstevel@tonic-gate 
1726*7c478bd9Sstevel@tonic-gate void
1727*7c478bd9Sstevel@tonic-gate dumpailing(void)
1728*7c478bd9Sstevel@tonic-gate {
1729*7c478bd9Sstevel@tonic-gate 
1730*7c478bd9Sstevel@tonic-gate 	broadcast(gettext("DUMP IS AILING!\n"));
1731*7c478bd9Sstevel@tonic-gate 	if (!query(gettext(
1732*7c478bd9Sstevel@tonic-gate 	    "Do you want to attempt to continue? (\"yes\" or \"no\") "))) {
1733*7c478bd9Sstevel@tonic-gate 		dumpabort();
1734*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
1735*7c478bd9Sstevel@tonic-gate 	}
1736*7c478bd9Sstevel@tonic-gate }
1737*7c478bd9Sstevel@tonic-gate 
1738*7c478bd9Sstevel@tonic-gate void
1739*7c478bd9Sstevel@tonic-gate Exit(status)
1740*7c478bd9Sstevel@tonic-gate {
1741*7c478bd9Sstevel@tonic-gate 	/*
1742*7c478bd9Sstevel@tonic-gate 	 * Clean up message system
1743*7c478bd9Sstevel@tonic-gate 	 */
1744*7c478bd9Sstevel@tonic-gate #ifdef TDEBUG
1745*7c478bd9Sstevel@tonic-gate 
1746*7c478bd9Sstevel@tonic-gate 	/* XGETTEXT:  #ifdef TDEBUG only */
1747*7c478bd9Sstevel@tonic-gate 	msg(gettext("pid = %ld exits with status %d\n"),
1748*7c478bd9Sstevel@tonic-gate 		(long)getpid(), status);
1749*7c478bd9Sstevel@tonic-gate #endif /* TDEBUG */
1750*7c478bd9Sstevel@tonic-gate 	exit(status);
1751*7c478bd9Sstevel@tonic-gate }
1752*7c478bd9Sstevel@tonic-gate 
1753*7c478bd9Sstevel@tonic-gate static void
1754*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
1755*7c478bd9Sstevel@tonic-gate killall(void)
1756*7c478bd9Sstevel@tonic-gate #else
1757*7c478bd9Sstevel@tonic-gate killall()
1758*7c478bd9Sstevel@tonic-gate #endif
1759*7c478bd9Sstevel@tonic-gate {
1760*7c478bd9Sstevel@tonic-gate 	struct slaves *slavep;
1761*7c478bd9Sstevel@tonic-gate 
1762*7c478bd9Sstevel@tonic-gate 	for (slavep = &slaves[0]; slavep < &slaves[SLAVES]; slavep++)
1763*7c478bd9Sstevel@tonic-gate 		if (slavep->sl_slavepid > 0) {
1764*7c478bd9Sstevel@tonic-gate 			(void) kill(slavep->sl_slavepid, SIGKILL);
1765*7c478bd9Sstevel@tonic-gate #ifdef TDEBUG
1766*7c478bd9Sstevel@tonic-gate 
1767*7c478bd9Sstevel@tonic-gate 			/* XGETTEXT:  #ifdef TDEBUG only */
1768*7c478bd9Sstevel@tonic-gate 			msg(gettext("Slave child %ld killed\n"),
1769*7c478bd9Sstevel@tonic-gate 				(long)slavep->sl_slavepid);
1770*7c478bd9Sstevel@tonic-gate #endif
1771*7c478bd9Sstevel@tonic-gate 		}
1772*7c478bd9Sstevel@tonic-gate 	if (writepid) {
1773*7c478bd9Sstevel@tonic-gate 		(void) kill(writepid, SIGKILL);
1774*7c478bd9Sstevel@tonic-gate #ifdef TDEBUG
1775*7c478bd9Sstevel@tonic-gate 
1776*7c478bd9Sstevel@tonic-gate 		/* XGETTEXT:  #ifdef TDEBUG only */
1777*7c478bd9Sstevel@tonic-gate 		msg(gettext("Writer child %ld killed\n"), (long)writepid);
1778*7c478bd9Sstevel@tonic-gate #endif
1779*7c478bd9Sstevel@tonic-gate 	}
1780*7c478bd9Sstevel@tonic-gate 	if (archivepid) {
1781*7c478bd9Sstevel@tonic-gate 		(void) kill(archivepid, SIGKILL);
1782*7c478bd9Sstevel@tonic-gate #ifdef TDEBUG
1783*7c478bd9Sstevel@tonic-gate 
1784*7c478bd9Sstevel@tonic-gate 		/* XGETTEXT:  #ifdef TDEBUG only */
1785*7c478bd9Sstevel@tonic-gate 		msg(gettext("Archiver child %ld killed\n"), (long)archivepid);
1786*7c478bd9Sstevel@tonic-gate #endif
1787*7c478bd9Sstevel@tonic-gate 	}
1788*7c478bd9Sstevel@tonic-gate }
1789*7c478bd9Sstevel@tonic-gate 
1790*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1791*7c478bd9Sstevel@tonic-gate static void
1792*7c478bd9Sstevel@tonic-gate proceed(sig)
1793*7c478bd9Sstevel@tonic-gate 	int	sig;
1794*7c478bd9Sstevel@tonic-gate {
1795*7c478bd9Sstevel@tonic-gate 	caught++;
1796*7c478bd9Sstevel@tonic-gate }
1797*7c478bd9Sstevel@tonic-gate 
1798*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1799*7c478bd9Sstevel@tonic-gate static void
1800*7c478bd9Sstevel@tonic-gate die(sig)
1801*7c478bd9Sstevel@tonic-gate 	int	sig;
1802*7c478bd9Sstevel@tonic-gate {
1803*7c478bd9Sstevel@tonic-gate 	Exit(X_FINOK);
1804*7c478bd9Sstevel@tonic-gate }
1805*7c478bd9Sstevel@tonic-gate 
1806*7c478bd9Sstevel@tonic-gate static void
1807*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
1808*7c478bd9Sstevel@tonic-gate enslave(void)
1809*7c478bd9Sstevel@tonic-gate #else
1810*7c478bd9Sstevel@tonic-gate enslave()
1811*7c478bd9Sstevel@tonic-gate #endif
1812*7c478bd9Sstevel@tonic-gate {
1813*7c478bd9Sstevel@tonic-gate 	int cmd[2];			/* file descriptors */
1814*7c478bd9Sstevel@tonic-gate 	int i;
1815*7c478bd9Sstevel@tonic-gate 	struct sigvec sv;
1816*7c478bd9Sstevel@tonic-gate 	struct slaves *slavep;
1817*7c478bd9Sstevel@tonic-gate 	int saverr;
1818*7c478bd9Sstevel@tonic-gate 
1819*7c478bd9Sstevel@tonic-gate 	sv.sv_flags = SA_RESTART;
1820*7c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&sv.sa_mask);
1821*7c478bd9Sstevel@tonic-gate 	master = getpid();
1822*7c478bd9Sstevel@tonic-gate 	/*
1823*7c478bd9Sstevel@tonic-gate 	 * slave sends SIGTERM on dumpabort
1824*7c478bd9Sstevel@tonic-gate 	 */
1825*7c478bd9Sstevel@tonic-gate 	sv.sv_handler = (void(*)(int))dumpabort;
1826*7c478bd9Sstevel@tonic-gate 	(void) sigvec(SIGTERM, &sv, (struct sigvec *)0);
1827*7c478bd9Sstevel@tonic-gate 	sv.sv_handler = tperror;
1828*7c478bd9Sstevel@tonic-gate 	(void) sigvec(SIGUSR2, &sv, (struct sigvec *)0);
1829*7c478bd9Sstevel@tonic-gate 	sv.sv_handler = proceed;
1830*7c478bd9Sstevel@tonic-gate 	(void) sigvec(SIGUSR1, &sv, (struct sigvec *)0);
1831*7c478bd9Sstevel@tonic-gate 	totalrecsout += recsout;
1832*7c478bd9Sstevel@tonic-gate 	caught = 0;
1833*7c478bd9Sstevel@tonic-gate 	recsout = 0;
1834*7c478bd9Sstevel@tonic-gate 	rotor = 0;
1835*7c478bd9Sstevel@tonic-gate 	bufclear();
1836*7c478bd9Sstevel@tonic-gate 	for (slavep = &slaves[0]; slavep < &slaves[SLAVES]; slavep++)
1837*7c478bd9Sstevel@tonic-gate 		slavep->sl_slavefd = -1;
1838*7c478bd9Sstevel@tonic-gate 	archivefd = arch = writer = -1;
1839*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < SLAVES; i++) {
1840*7c478bd9Sstevel@tonic-gate 		if (pipe(cmd) < 0) {
1841*7c478bd9Sstevel@tonic-gate 			saverr = errno;
1842*7c478bd9Sstevel@tonic-gate 			msg(gettext(
1843*7c478bd9Sstevel@tonic-gate 			    "Cannot create pipe for slave process: %s\n"),
1844*7c478bd9Sstevel@tonic-gate 			    strerror(saverr));
1845*7c478bd9Sstevel@tonic-gate 			dumpabort();
1846*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
1847*7c478bd9Sstevel@tonic-gate 		}
1848*7c478bd9Sstevel@tonic-gate 		sighold(SIGUSR2);
1849*7c478bd9Sstevel@tonic-gate 		sighold(SIGINT);
1850*7c478bd9Sstevel@tonic-gate 		sighold(SIGTERM);
1851*7c478bd9Sstevel@tonic-gate 		if ((slaves[i].sl_slavepid = fork()) < 0) {
1852*7c478bd9Sstevel@tonic-gate 			saverr = errno;
1853*7c478bd9Sstevel@tonic-gate 			msg(gettext("Cannot create slave process: %s\n"),
1854*7c478bd9Sstevel@tonic-gate 			    strerror(saverr));
1855*7c478bd9Sstevel@tonic-gate 			dumpabort();
1856*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
1857*7c478bd9Sstevel@tonic-gate 		}
1858*7c478bd9Sstevel@tonic-gate 		slaves[i].sl_slavefd = cmd[1];
1859*7c478bd9Sstevel@tonic-gate 		if (slaves[i].sl_slavepid == 0) {   /* Slave starts up here */
1860*7c478bd9Sstevel@tonic-gate 			pid_t next;		    /* pid of neighbor */
1861*7c478bd9Sstevel@tonic-gate 
1862*7c478bd9Sstevel@tonic-gate 			sv.sv_handler = SIG_DFL;
1863*7c478bd9Sstevel@tonic-gate 			(void) sigvec(SIGUSR2, &sv, (struct sigvec *)0);
1864*7c478bd9Sstevel@tonic-gate 			sv.sv_handler = SIG_IGN;	/* master handler INT */
1865*7c478bd9Sstevel@tonic-gate 			(void) sigvec(SIGINT, &sv, (struct sigvec *)0);
1866*7c478bd9Sstevel@tonic-gate 			sv.sv_handler = die;		/* normal slave exit */
1867*7c478bd9Sstevel@tonic-gate 			(void) sigvec(SIGTERM, &sv, (struct sigvec *)0);
1868*7c478bd9Sstevel@tonic-gate 
1869*7c478bd9Sstevel@tonic-gate 			child_chdir();
1870*7c478bd9Sstevel@tonic-gate 			sigrelse(SIGUSR2);
1871*7c478bd9Sstevel@tonic-gate 			sigrelse(SIGINT);
1872*7c478bd9Sstevel@tonic-gate 			sigrelse(SIGTERM);
1873*7c478bd9Sstevel@tonic-gate 
1874*7c478bd9Sstevel@tonic-gate 			freeino();	/* release unneeded resources */
1875*7c478bd9Sstevel@tonic-gate #ifdef TDEBUG
1876*7c478bd9Sstevel@tonic-gate 		(void) sleep(4); /* time for parent's message to get out */
1877*7c478bd9Sstevel@tonic-gate 		/* XGETTEXT:  #ifdef TDEBUG only */
1878*7c478bd9Sstevel@tonic-gate 		msg(gettext("Neighbor has pid = %ld\n"), (long)getpid());
1879*7c478bd9Sstevel@tonic-gate #endif
1880*7c478bd9Sstevel@tonic-gate 			/* Closes cmd[1] as a side-effect */
1881*7c478bd9Sstevel@tonic-gate 			for (slavep = &slaves[0];
1882*7c478bd9Sstevel@tonic-gate 			    slavep < &slaves[SLAVES];
1883*7c478bd9Sstevel@tonic-gate 			    slavep++)
1884*7c478bd9Sstevel@tonic-gate 				if (slavep->sl_slavefd >= 0) {
1885*7c478bd9Sstevel@tonic-gate 					(void) close(slavep->sl_slavefd);
1886*7c478bd9Sstevel@tonic-gate 					slavep->sl_slavefd = -1;
1887*7c478bd9Sstevel@tonic-gate 				}
1888*7c478bd9Sstevel@tonic-gate 			(void) close(to);
1889*7c478bd9Sstevel@tonic-gate 			(void) close(fi);	    /* Need our own seek ptr */
1890*7c478bd9Sstevel@tonic-gate 			to = -1;
1891*7c478bd9Sstevel@tonic-gate 
1892*7c478bd9Sstevel@tonic-gate 			fi = open(disk, O_RDONLY);
1893*7c478bd9Sstevel@tonic-gate 
1894*7c478bd9Sstevel@tonic-gate 			if (fi < 0) {
1895*7c478bd9Sstevel@tonic-gate 				saverr = errno;
1896*7c478bd9Sstevel@tonic-gate 				msg(gettext(
1897*7c478bd9Sstevel@tonic-gate 				    "Cannot open dump device `%s': %s\n"),
1898*7c478bd9Sstevel@tonic-gate 					disk, strerror(saverr));
1899*7c478bd9Sstevel@tonic-gate 				dumpabort();
1900*7c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
1901*7c478bd9Sstevel@tonic-gate 			}
1902*7c478bd9Sstevel@tonic-gate 
1903*7c478bd9Sstevel@tonic-gate 			if ((unsigned)atomic((int(*)())read, cmd[0],
1904*7c478bd9Sstevel@tonic-gate 			    (char *)&next, sizeof (next)) != sizeof (next)) {
1905*7c478bd9Sstevel@tonic-gate 				cmdrderr();
1906*7c478bd9Sstevel@tonic-gate 				dumpabort();
1907*7c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
1908*7c478bd9Sstevel@tonic-gate 			}
1909*7c478bd9Sstevel@tonic-gate 			dumpoffline(cmd[0], next, i);
1910*7c478bd9Sstevel@tonic-gate 			Exit(X_FINOK);
1911*7c478bd9Sstevel@tonic-gate 		}
1912*7c478bd9Sstevel@tonic-gate 		/* Parent continues here */
1913*7c478bd9Sstevel@tonic-gate 		sigrelse(SIGUSR2);
1914*7c478bd9Sstevel@tonic-gate 		sigrelse(SIGINT);
1915*7c478bd9Sstevel@tonic-gate 		sigrelse(SIGTERM);
1916*7c478bd9Sstevel@tonic-gate 		(void) close(cmd[0]);
1917*7c478bd9Sstevel@tonic-gate 	}
1918*7c478bd9Sstevel@tonic-gate 
1919*7c478bd9Sstevel@tonic-gate 	if (archive) {
1920*7c478bd9Sstevel@tonic-gate 		archivepid = setuparchive();
1921*7c478bd9Sstevel@tonic-gate 		if (!archivepid) {
1922*7c478bd9Sstevel@tonic-gate 			dumpabort();
1923*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
1924*7c478bd9Sstevel@tonic-gate 		}
1925*7c478bd9Sstevel@tonic-gate 	}
1926*7c478bd9Sstevel@tonic-gate 
1927*7c478bd9Sstevel@tonic-gate 	writepid = setupwriter();
1928*7c478bd9Sstevel@tonic-gate 	if (!writepid) {
1929*7c478bd9Sstevel@tonic-gate 		dumpabort();
1930*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
1931*7c478bd9Sstevel@tonic-gate 	}
1932*7c478bd9Sstevel@tonic-gate 
1933*7c478bd9Sstevel@tonic-gate 	if (arch >= 0) {
1934*7c478bd9Sstevel@tonic-gate 		(void) close(arch);		/* only writer has this open */
1935*7c478bd9Sstevel@tonic-gate 		arch = -1;
1936*7c478bd9Sstevel@tonic-gate 	}
1937*7c478bd9Sstevel@tonic-gate 
1938*7c478bd9Sstevel@tonic-gate 	/* Tell each slave who follows it */
1939*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < SLAVES; i++) {
1940*7c478bd9Sstevel@tonic-gate 		if ((unsigned)atomic((int(*)())write, slaves[i].sl_slavefd,
1941*7c478bd9Sstevel@tonic-gate 		    (char *)&(slaves[(i + 1) % SLAVES].sl_slavepid),
1942*7c478bd9Sstevel@tonic-gate 		    sizeof (int)) != sizeof (int)) {
1943*7c478bd9Sstevel@tonic-gate 			cmdwrterr();
1944*7c478bd9Sstevel@tonic-gate 			dumpabort();
1945*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
1946*7c478bd9Sstevel@tonic-gate 		}
1947*7c478bd9Sstevel@tonic-gate 	}
1948*7c478bd9Sstevel@tonic-gate 	sv.sv_handler = rollforward;		/* rcvd from writer on EOT */
1949*7c478bd9Sstevel@tonic-gate 	(void) sigvec(SIGUSR1, &sv, (struct sigvec *)0);
1950*7c478bd9Sstevel@tonic-gate 	slp = slaves;
1951*7c478bd9Sstevel@tonic-gate 	(void) kill(slp->sl_slavepid, SIGUSR1);
1952*7c478bd9Sstevel@tonic-gate 	master = 0;
1953*7c478bd9Sstevel@tonic-gate }
1954*7c478bd9Sstevel@tonic-gate 
1955*7c478bd9Sstevel@tonic-gate static void
1956*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
1957*7c478bd9Sstevel@tonic-gate wait_our_turn(void)
1958*7c478bd9Sstevel@tonic-gate #else
1959*7c478bd9Sstevel@tonic-gate wait_our_turn()
1960*7c478bd9Sstevel@tonic-gate #endif
1961*7c478bd9Sstevel@tonic-gate {
1962*7c478bd9Sstevel@tonic-gate 	(void) sighold(SIGUSR1);
1963*7c478bd9Sstevel@tonic-gate 
1964*7c478bd9Sstevel@tonic-gate 	if (!caught) {
1965*7c478bd9Sstevel@tonic-gate #ifdef INSTRUMENT
1966*7c478bd9Sstevel@tonic-gate 		(*idle)++;
1967*7c478bd9Sstevel@tonic-gate #endif
1968*7c478bd9Sstevel@tonic-gate 		(void) sigpause(SIGUSR1);
1969*7c478bd9Sstevel@tonic-gate 	}
1970*7c478bd9Sstevel@tonic-gate 	caught = 0;
1971*7c478bd9Sstevel@tonic-gate 	(void) sigrelse(SIGUSR1);
1972*7c478bd9Sstevel@tonic-gate }
1973*7c478bd9Sstevel@tonic-gate 
1974*7c478bd9Sstevel@tonic-gate static void
1975*7c478bd9Sstevel@tonic-gate dumpoffline(cmd, next, mynum)
1976*7c478bd9Sstevel@tonic-gate 	int cmd;
1977*7c478bd9Sstevel@tonic-gate 	pid_t next;
1978*7c478bd9Sstevel@tonic-gate 	int mynum;
1979*7c478bd9Sstevel@tonic-gate {
1980*7c478bd9Sstevel@tonic-gate 	struct req *p = slaves[mynum].sl_req;
1981*7c478bd9Sstevel@tonic-gate 	ulong_t i;
1982*7c478bd9Sstevel@tonic-gate 	uchar_t *cp;
1983*7c478bd9Sstevel@tonic-gate 	uchar_t *blkbuf;
1984*7c478bd9Sstevel@tonic-gate 	int notactive = 0;
1985*7c478bd9Sstevel@tonic-gate 
1986*7c478bd9Sstevel@tonic-gate 	blkbuf = xmalloc(sblock->fs_bsize);
1987*7c478bd9Sstevel@tonic-gate 
1988*7c478bd9Sstevel@tonic-gate 	/*CONSTANTCONDITION*/
1989*7c478bd9Sstevel@tonic-gate 	assert(sizeof (spcl) == TP_BSIZE_MIN);
1990*7c478bd9Sstevel@tonic-gate 
1991*7c478bd9Sstevel@tonic-gate 	while (atomic((int(*)())read, cmd, (char *)p, reqsiz) == reqsiz) {
1992*7c478bd9Sstevel@tonic-gate 		if (p->br_dblk) {
1993*7c478bd9Sstevel@tonic-gate 			bread(p->br_dblk, (uchar_t *)blkbuf, p->br_size);
1994*7c478bd9Sstevel@tonic-gate 		} else {
1995*7c478bd9Sstevel@tonic-gate 			bcopy((char *)p->br_spcl, (char *)&spcl,
1996*7c478bd9Sstevel@tonic-gate 			    sizeof (spcl));
1997*7c478bd9Sstevel@tonic-gate 			ino = spcl.c_inumber;
1998*7c478bd9Sstevel@tonic-gate 		}
1999*7c478bd9Sstevel@tonic-gate 		dumptoarchive = p->aflag & BUF_ARCHIVE;
2000*7c478bd9Sstevel@tonic-gate 		wait_our_turn();
2001*7c478bd9Sstevel@tonic-gate 		if (p->br_dblk) {
2002*7c478bd9Sstevel@tonic-gate 			for (i = p->br_size, cp = blkbuf;
2003*7c478bd9Sstevel@tonic-gate 			    i > 0;
2004*7c478bd9Sstevel@tonic-gate 			    /* LINTED character pointers aren't signed */
2005*7c478bd9Sstevel@tonic-gate 			    cp += i > tp_bsize ? tp_bsize : i,
2006*7c478bd9Sstevel@tonic-gate 			    i -= i > tp_bsize ? tp_bsize : i) {
2007*7c478bd9Sstevel@tonic-gate 				/* LINTED unsigned to signed conversion ok */
2008*7c478bd9Sstevel@tonic-gate 				taprec(cp, 0, i > tp_bsize ? tp_bsize : (int)i);
2009*7c478bd9Sstevel@tonic-gate 			}
2010*7c478bd9Sstevel@tonic-gate 		} else
2011*7c478bd9Sstevel@tonic-gate 			spclrec();
2012*7c478bd9Sstevel@tonic-gate 		(void) kill(next, SIGUSR1);	/* Next slave's turn */
2013*7c478bd9Sstevel@tonic-gate 		/*
2014*7c478bd9Sstevel@tonic-gate 		 * Note that we lie about file activity since we don't
2015*7c478bd9Sstevel@tonic-gate 		 * check for it.
2016*7c478bd9Sstevel@tonic-gate 		 */
2017*7c478bd9Sstevel@tonic-gate 		if ((unsigned)atomic((int(*)())write, cmd, (char *)&notactive,
2018*7c478bd9Sstevel@tonic-gate 		    sizeof (notactive)) != sizeof (notactive)) {
2019*7c478bd9Sstevel@tonic-gate 			cmdwrterr();
2020*7c478bd9Sstevel@tonic-gate 			dumpabort();
2021*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
2022*7c478bd9Sstevel@tonic-gate 		}
2023*7c478bd9Sstevel@tonic-gate 	}
2024*7c478bd9Sstevel@tonic-gate 
2025*7c478bd9Sstevel@tonic-gate 	free(blkbuf);
2026*7c478bd9Sstevel@tonic-gate }
2027*7c478bd9Sstevel@tonic-gate 
2028*7c478bd9Sstevel@tonic-gate static int count;		/* tape blocks written since last spclrec */
2029*7c478bd9Sstevel@tonic-gate 
2030*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2031*7c478bd9Sstevel@tonic-gate static void
2032*7c478bd9Sstevel@tonic-gate onxfsz(sig)
2033*7c478bd9Sstevel@tonic-gate 	int	sig;
2034*7c478bd9Sstevel@tonic-gate {
2035*7c478bd9Sstevel@tonic-gate 	msg(gettext("File size limit exceeded writing output volume %d\n"),
2036*7c478bd9Sstevel@tonic-gate 	    tapeno);
2037*7c478bd9Sstevel@tonic-gate 	(void) kill(master, SIGUSR2);
2038*7c478bd9Sstevel@tonic-gate 	Exit(X_REWRITE);
2039*7c478bd9Sstevel@tonic-gate }
2040*7c478bd9Sstevel@tonic-gate 
2041*7c478bd9Sstevel@tonic-gate static long	lastnonaddr;		/* last DS_{INODE,CLRI,BITS} written */
2042*7c478bd9Sstevel@tonic-gate static long	lastnonaddrm;		/* and the mode thereof */
2043*7c478bd9Sstevel@tonic-gate /*
2044*7c478bd9Sstevel@tonic-gate  * dowrite -- the main body of the output writer process
2045*7c478bd9Sstevel@tonic-gate  */
2046*7c478bd9Sstevel@tonic-gate static void
2047*7c478bd9Sstevel@tonic-gate dowrite(cmd)
2048*7c478bd9Sstevel@tonic-gate 	int	cmd;
2049*7c478bd9Sstevel@tonic-gate {
2050*7c478bd9Sstevel@tonic-gate 	struct bdesc *last =
2051*7c478bd9Sstevel@tonic-gate 	    &bufp[(NBUF*ntrec)-1];		/* last buffer in pool */
2052*7c478bd9Sstevel@tonic-gate 	struct bdesc *bp = bufp;		/* current buf in tape block */
2053*7c478bd9Sstevel@tonic-gate 	struct bdesc *begin = bufp;		/* first buf of tape block */
2054*7c478bd9Sstevel@tonic-gate 	struct bdesc *end = bufp + (ntrec-1);	/* last buf of tape block */
2055*7c478bd9Sstevel@tonic-gate 	int siz;				/* bytes written (block) */
2056*7c478bd9Sstevel@tonic-gate 	int trecs;				/* records written (block)  */
2057*7c478bd9Sstevel@tonic-gate 	long asize = 0;				/* number of 0.1" units... */
2058*7c478bd9Sstevel@tonic-gate 						/* ...written on current tape */
2059*7c478bd9Sstevel@tonic-gate 	char *tp, *rbuf = NULL;
2060*7c478bd9Sstevel@tonic-gate 	char *recmap = spcl.c_addr;		/* current tape record map */
2061*7c478bd9Sstevel@tonic-gate 	char *endmp;				/* end of valid map data */
2062*7c478bd9Sstevel@tonic-gate 	char *mp;				/* current map entry */
2063*7c478bd9Sstevel@tonic-gate 	union u_spcl *sp;
2064*7c478bd9Sstevel@tonic-gate 
2065*7c478bd9Sstevel@tonic-gate 	(void) signal(SIGXFSZ, onxfsz);
2066*7c478bd9Sstevel@tonic-gate 
2067*7c478bd9Sstevel@tonic-gate 	bzero((char *)&spcl, sizeof (spcl));
2068*7c478bd9Sstevel@tonic-gate 	count = 0;
2069*7c478bd9Sstevel@tonic-gate 
2070*7c478bd9Sstevel@tonic-gate 	if (doingverify) {
2071*7c478bd9Sstevel@tonic-gate 		rbuf = (char *)malloc((uint_t)writesize);
2072*7c478bd9Sstevel@tonic-gate 		if (rbuf == 0) {
2073*7c478bd9Sstevel@tonic-gate 			/* Restart from checkpoint */
2074*7c478bd9Sstevel@tonic-gate 			(void) kill(master, SIGUSR2);
2075*7c478bd9Sstevel@tonic-gate 			Exit(X_REWRITE);
2076*7c478bd9Sstevel@tonic-gate 		}
2077*7c478bd9Sstevel@tonic-gate 	}
2078*7c478bd9Sstevel@tonic-gate 
2079*7c478bd9Sstevel@tonic-gate 	for (;;) {
2080*7c478bd9Sstevel@tonic-gate 		/* START: wait until all buffers in tape block are full */
2081*7c478bd9Sstevel@tonic-gate 		if ((bp->b_flags & BUF_FULL) == 0) {
2082*7c478bd9Sstevel@tonic-gate 			if (caught) {		/* master signalled flush */
2083*7c478bd9Sstevel@tonic-gate 				(void) sighold(SIGUSR1);
2084*7c478bd9Sstevel@tonic-gate 				caught = 0;
2085*7c478bd9Sstevel@tonic-gate 				/* signal ready */
2086*7c478bd9Sstevel@tonic-gate 				(void) kill(master, SIGUSR1);
2087*7c478bd9Sstevel@tonic-gate 				chkpt.sl_count = 0;	/* signal not at EOT */
2088*7c478bd9Sstevel@tonic-gate 				checkpoint(bp-1, cmd);	/* send data */
2089*7c478bd9Sstevel@tonic-gate 				(void) sigpause(SIGUSR1);
2090*7c478bd9Sstevel@tonic-gate 				break;
2091*7c478bd9Sstevel@tonic-gate 			}
2092*7c478bd9Sstevel@tonic-gate #ifdef INSTRUMENT
2093*7c478bd9Sstevel@tonic-gate 			(*readmissp)++;
2094*7c478bd9Sstevel@tonic-gate #endif
2095*7c478bd9Sstevel@tonic-gate 			nap(50);
2096*7c478bd9Sstevel@tonic-gate 			continue;
2097*7c478bd9Sstevel@tonic-gate 		}
2098*7c478bd9Sstevel@tonic-gate 		if (bp < end) {
2099*7c478bd9Sstevel@tonic-gate 			bp++;
2100*7c478bd9Sstevel@tonic-gate 			continue;
2101*7c478bd9Sstevel@tonic-gate 		}
2102*7c478bd9Sstevel@tonic-gate 		/* END: wait until all buffers in tape block are full */
2103*7c478bd9Sstevel@tonic-gate 
2104*7c478bd9Sstevel@tonic-gate 		tp = begin->b_data;
2105*7c478bd9Sstevel@tonic-gate 		(void) sighold(SIGUSR1);
2106*7c478bd9Sstevel@tonic-gate 		if (host) {
2107*7c478bd9Sstevel@tonic-gate 			if (!doingverify)
2108*7c478bd9Sstevel@tonic-gate 				siz = rmtwrite(tp, writesize);
2109*7c478bd9Sstevel@tonic-gate 			else if ((siz = rmtread(rbuf, writesize)) ==
2110*7c478bd9Sstevel@tonic-gate 			    writesize && bcmp(rbuf, tp, writesize))
2111*7c478bd9Sstevel@tonic-gate 				siz = -1;
2112*7c478bd9Sstevel@tonic-gate 		} else {
2113*7c478bd9Sstevel@tonic-gate 			if (!doingverify)
2114*7c478bd9Sstevel@tonic-gate 				siz = write(to, tp, writesize);
2115*7c478bd9Sstevel@tonic-gate 			else if ((siz = read(to, rbuf, writesize)) ==
2116*7c478bd9Sstevel@tonic-gate 			    writesize && bcmp(rbuf, tp, writesize))
2117*7c478bd9Sstevel@tonic-gate 				siz = -1;
2118*7c478bd9Sstevel@tonic-gate 			if (siz < 0 && diskette && errno == ENOSPC)
2119*7c478bd9Sstevel@tonic-gate 				siz = 0;	/* really EOF */
2120*7c478bd9Sstevel@tonic-gate 		}
2121*7c478bd9Sstevel@tonic-gate 		(void) sigrelse(SIGUSR1);
2122*7c478bd9Sstevel@tonic-gate 		if (siz < 0 ||
2123*7c478bd9Sstevel@tonic-gate 		    (pipeout && siz != writesize)) {
2124*7c478bd9Sstevel@tonic-gate 			char buf[3000];
2125*7c478bd9Sstevel@tonic-gate 
2126*7c478bd9Sstevel@tonic-gate 			/*
2127*7c478bd9Sstevel@tonic-gate 			 * Isn't i18n wonderful?
2128*7c478bd9Sstevel@tonic-gate 			 */
2129*7c478bd9Sstevel@tonic-gate 			if (doingverify) {
2130*7c478bd9Sstevel@tonic-gate 				if (diskette)
2131*7c478bd9Sstevel@tonic-gate 					(void) snprintf(buf, sizeof (buf),
2132*7c478bd9Sstevel@tonic-gate 					    gettext(
2133*7c478bd9Sstevel@tonic-gate 		    "Verification error %ld blocks into diskette %d\n"),
2134*7c478bd9Sstevel@tonic-gate 					    asize * 2, tapeno);
2135*7c478bd9Sstevel@tonic-gate 				else if (tapeout)
2136*7c478bd9Sstevel@tonic-gate 					(void) snprintf(buf, sizeof (buf),
2137*7c478bd9Sstevel@tonic-gate 					    gettext(
2138*7c478bd9Sstevel@tonic-gate 		    "Verification error %ld feet into tape %d\n"),
2139*7c478bd9Sstevel@tonic-gate 					    (cartridge ? asize/tracks :
2140*7c478bd9Sstevel@tonic-gate 						asize)/120L,
2141*7c478bd9Sstevel@tonic-gate 					    tapeno);
2142*7c478bd9Sstevel@tonic-gate 				else
2143*7c478bd9Sstevel@tonic-gate 					(void) snprintf(buf, sizeof (buf),
2144*7c478bd9Sstevel@tonic-gate 					    gettext(
2145*7c478bd9Sstevel@tonic-gate 		    "Verification error %ld blocks into volume %d\n"),
2146*7c478bd9Sstevel@tonic-gate 					    asize * 2, tapeno);
2147*7c478bd9Sstevel@tonic-gate 
2148*7c478bd9Sstevel@tonic-gate 			} else {
2149*7c478bd9Sstevel@tonic-gate 				if (diskette)
2150*7c478bd9Sstevel@tonic-gate 					(void) snprintf(buf, sizeof (buf),
2151*7c478bd9Sstevel@tonic-gate 					    gettext(
2152*7c478bd9Sstevel@tonic-gate 			"Write error %ld blocks into diskette %d\n"),
2153*7c478bd9Sstevel@tonic-gate 					    asize * 2, tapeno);
2154*7c478bd9Sstevel@tonic-gate 				else if (tapeout)
2155*7c478bd9Sstevel@tonic-gate 					(void) snprintf(buf, sizeof (buf),
2156*7c478bd9Sstevel@tonic-gate 					    gettext(
2157*7c478bd9Sstevel@tonic-gate 			"Write error %ld feet into tape %d\n"),
2158*7c478bd9Sstevel@tonic-gate 					    (cartridge ? asize/tracks :
2159*7c478bd9Sstevel@tonic-gate 						asize)/120L, tapeno);
2160*7c478bd9Sstevel@tonic-gate 				else
2161*7c478bd9Sstevel@tonic-gate 					(void) snprintf(buf, sizeof (buf),
2162*7c478bd9Sstevel@tonic-gate 					    gettext(
2163*7c478bd9Sstevel@tonic-gate 			"Write error %ld blocks into volume %d\n"),
2164*7c478bd9Sstevel@tonic-gate 					    asize * 2, tapeno);
2165*7c478bd9Sstevel@tonic-gate 			}
2166*7c478bd9Sstevel@tonic-gate 
2167*7c478bd9Sstevel@tonic-gate 			msg(buf);
2168*7c478bd9Sstevel@tonic-gate 			/* Restart from checkpoint */
2169*7c478bd9Sstevel@tonic-gate #ifdef TDEBUG
2170*7c478bd9Sstevel@tonic-gate 
2171*7c478bd9Sstevel@tonic-gate 			/* XGETTEXT:  #ifdef TDEBUG only */
2172*7c478bd9Sstevel@tonic-gate 			msg(gettext("sending SIGUSR2 to pid %ld\n"), master);
2173*7c478bd9Sstevel@tonic-gate #endif
2174*7c478bd9Sstevel@tonic-gate 			(void) kill(master, SIGUSR2);
2175*7c478bd9Sstevel@tonic-gate 			Exit(X_REWRITE);
2176*7c478bd9Sstevel@tonic-gate 		}
2177*7c478bd9Sstevel@tonic-gate 		trecs = siz / tp_bsize;
2178*7c478bd9Sstevel@tonic-gate 		if (diskette)
2179*7c478bd9Sstevel@tonic-gate 			asize += trecs;	/* asize == blocks written */
2180*7c478bd9Sstevel@tonic-gate 		else
2181*7c478bd9Sstevel@tonic-gate 			asize += (siz/density + tenthsperirg);
2182*7c478bd9Sstevel@tonic-gate 		if (trecs)
2183*7c478bd9Sstevel@tonic-gate 			chkpt.sl_firstrec++;
2184*7c478bd9Sstevel@tonic-gate 		for (bp = begin; bp < begin + trecs; bp++) {
2185*7c478bd9Sstevel@tonic-gate 			if ((arch >= 0) && (bp->b_flags & BUF_ARCHIVE)) {
2186*7c478bd9Sstevel@tonic-gate 				if ((unsigned)atomic((int(*)())write, arch,
2187*7c478bd9Sstevel@tonic-gate 				    (char *)&bp->b_flags, sizeof (bp->b_flags))
2188*7c478bd9Sstevel@tonic-gate 				    != sizeof (bp->b_flags)) {
2189*7c478bd9Sstevel@tonic-gate 					cmdwrterr();
2190*7c478bd9Sstevel@tonic-gate 					dumpabort();
2191*7c478bd9Sstevel@tonic-gate 					/*NOTREACHED*/
2192*7c478bd9Sstevel@tonic-gate 				}
2193*7c478bd9Sstevel@tonic-gate 				if (atomic((int(*)())write, arch, bp->b_data,
2194*7c478bd9Sstevel@tonic-gate 				    tp_bsize) != tp_bsize) {
2195*7c478bd9Sstevel@tonic-gate 					cmdwrterr();
2196*7c478bd9Sstevel@tonic-gate 					dumpabort();
2197*7c478bd9Sstevel@tonic-gate 					/*NOTREACHED*/
2198*7c478bd9Sstevel@tonic-gate 				}
2199*7c478bd9Sstevel@tonic-gate 			}
2200*7c478bd9Sstevel@tonic-gate 			if (bp->b_flags & BUF_SPCLREC) {
2201*7c478bd9Sstevel@tonic-gate 				/*LINTED [bp->b_data is aligned]*/
2202*7c478bd9Sstevel@tonic-gate 				sp = (union u_spcl *)bp->b_data;
2203*7c478bd9Sstevel@tonic-gate 				if (sp->s_spcl.c_type != TS_ADDR) {
2204*7c478bd9Sstevel@tonic-gate 					lastnonaddr = sp->s_spcl.c_type;
2205*7c478bd9Sstevel@tonic-gate 					lastnonaddrm =
2206*7c478bd9Sstevel@tonic-gate 						sp->s_spcl.c_dinode.di_mode;
2207*7c478bd9Sstevel@tonic-gate 					if (sp->s_spcl.c_type != TS_TAPE)
2208*7c478bd9Sstevel@tonic-gate 						chkpt.sl_offset = 0;
2209*7c478bd9Sstevel@tonic-gate 				}
2210*7c478bd9Sstevel@tonic-gate 				chkpt.sl_count = sp->s_spcl.c_count;
2211*7c478bd9Sstevel@tonic-gate 				bcopy((char *)sp,
2212*7c478bd9Sstevel@tonic-gate 					(char *)&spcl, sizeof (spcl));
2213*7c478bd9Sstevel@tonic-gate 				mp = recmap;
2214*7c478bd9Sstevel@tonic-gate 				endmp = &recmap[spcl.c_count];
2215*7c478bd9Sstevel@tonic-gate 				count = 0;
2216*7c478bd9Sstevel@tonic-gate 			} else {
2217*7c478bd9Sstevel@tonic-gate 				chkpt.sl_offset++;
2218*7c478bd9Sstevel@tonic-gate 				chkpt.sl_count--;
2219*7c478bd9Sstevel@tonic-gate 				count++;
2220*7c478bd9Sstevel@tonic-gate 				mp++;
2221*7c478bd9Sstevel@tonic-gate 			}
2222*7c478bd9Sstevel@tonic-gate 			/*
2223*7c478bd9Sstevel@tonic-gate 			 * Adjust for contiguous hole
2224*7c478bd9Sstevel@tonic-gate 			 */
2225*7c478bd9Sstevel@tonic-gate 			for (; mp < endmp; mp++) {
2226*7c478bd9Sstevel@tonic-gate 				if (*mp)
2227*7c478bd9Sstevel@tonic-gate 					break;
2228*7c478bd9Sstevel@tonic-gate 				chkpt.sl_offset++;
2229*7c478bd9Sstevel@tonic-gate 				chkpt.sl_count--;
2230*7c478bd9Sstevel@tonic-gate 			}
2231*7c478bd9Sstevel@tonic-gate 		}
2232*7c478bd9Sstevel@tonic-gate 		/*
2233*7c478bd9Sstevel@tonic-gate 		 * Check for end of tape
2234*7c478bd9Sstevel@tonic-gate 		 */
2235*7c478bd9Sstevel@tonic-gate 		if (trecs < ntrec ||
2236*7c478bd9Sstevel@tonic-gate 		    (!pipeout && tsize > 0 && asize > tsize)) {
2237*7c478bd9Sstevel@tonic-gate 			if (tapeout)
2238*7c478bd9Sstevel@tonic-gate 				msg(gettext("End-of-tape detected\n"));
2239*7c478bd9Sstevel@tonic-gate 			else
2240*7c478bd9Sstevel@tonic-gate 				msg(gettext("End-of-file detected\n"));
2241*7c478bd9Sstevel@tonic-gate 			(void) sighold(SIGUSR1);
2242*7c478bd9Sstevel@tonic-gate 			caught = 0;
2243*7c478bd9Sstevel@tonic-gate 			(void) kill(master, SIGUSR1);	/* signal EOT */
2244*7c478bd9Sstevel@tonic-gate 			checkpoint(--bp, cmd);	/* send checkpoint data */
2245*7c478bd9Sstevel@tonic-gate 			(void) sigpause(SIGUSR1);
2246*7c478bd9Sstevel@tonic-gate 			break;
2247*7c478bd9Sstevel@tonic-gate 		}
2248*7c478bd9Sstevel@tonic-gate 		for (bp = begin; bp <= end; bp++)
2249*7c478bd9Sstevel@tonic-gate 			bp->b_flags = BUF_EMPTY;
2250*7c478bd9Sstevel@tonic-gate 		if (end + ntrec > last) {
2251*7c478bd9Sstevel@tonic-gate 			bp = begin = bufp;
2252*7c478bd9Sstevel@tonic-gate 			timeest(0, spcl.c_tapea);
2253*7c478bd9Sstevel@tonic-gate 		} else
2254*7c478bd9Sstevel@tonic-gate 			bp = begin = end+1;
2255*7c478bd9Sstevel@tonic-gate 		end = begin + (ntrec-1);
2256*7c478bd9Sstevel@tonic-gate 	}
2257*7c478bd9Sstevel@tonic-gate 
2258*7c478bd9Sstevel@tonic-gate 	if (rbuf != NULL)
2259*7c478bd9Sstevel@tonic-gate 		free(rbuf);
2260*7c478bd9Sstevel@tonic-gate }
2261*7c478bd9Sstevel@tonic-gate 
2262*7c478bd9Sstevel@tonic-gate /*
2263*7c478bd9Sstevel@tonic-gate  * Send checkpoint info back to master.  This information
2264*7c478bd9Sstevel@tonic-gate  * consists of the current inode number, number of logical
2265*7c478bd9Sstevel@tonic-gate  * blocks written for that inode (or bitmap), the last logical
2266*7c478bd9Sstevel@tonic-gate  * block number written, the number of logical blocks written
2267*7c478bd9Sstevel@tonic-gate  * to this volume, the current dump state, and the current
2268*7c478bd9Sstevel@tonic-gate  * special record map.
2269*7c478bd9Sstevel@tonic-gate  */
2270*7c478bd9Sstevel@tonic-gate static void
2271*7c478bd9Sstevel@tonic-gate checkpoint(bp, cmd)
2272*7c478bd9Sstevel@tonic-gate 	struct bdesc *bp;
2273*7c478bd9Sstevel@tonic-gate 	int	cmd;
2274*7c478bd9Sstevel@tonic-gate {
2275*7c478bd9Sstevel@tonic-gate 	int	state, type;
2276*7c478bd9Sstevel@tonic-gate 	ino_t	ino;
2277*7c478bd9Sstevel@tonic-gate 
2278*7c478bd9Sstevel@tonic-gate 	if (++bp >= &bufp[NBUF*ntrec])
2279*7c478bd9Sstevel@tonic-gate 		bp = bufp;
2280*7c478bd9Sstevel@tonic-gate 
2281*7c478bd9Sstevel@tonic-gate 	/*
2282*7c478bd9Sstevel@tonic-gate 	 * If we are dumping files and the record following
2283*7c478bd9Sstevel@tonic-gate 	 * the last written to tape is a special record, use
2284*7c478bd9Sstevel@tonic-gate 	 * it to get an accurate indication of current state.
2285*7c478bd9Sstevel@tonic-gate 	 */
2286*7c478bd9Sstevel@tonic-gate 	if ((bp->b_flags & BUF_SPCLREC) && (bp->b_flags & BUF_FULL) &&
2287*7c478bd9Sstevel@tonic-gate 	    lastnonaddr == TS_INODE) {
2288*7c478bd9Sstevel@tonic-gate 		/*LINTED [bp->b_data is aligned]*/
2289*7c478bd9Sstevel@tonic-gate 		union u_spcl *nextspcl = (union u_spcl *)bp->b_data;
2290*7c478bd9Sstevel@tonic-gate 
2291*7c478bd9Sstevel@tonic-gate 		if (nextspcl->s_spcl.c_type == TS_INODE) {
2292*7c478bd9Sstevel@tonic-gate 			chkpt.sl_offset = 0;
2293*7c478bd9Sstevel@tonic-gate 			chkpt.sl_count = 0;
2294*7c478bd9Sstevel@tonic-gate 		} else if (nextspcl->s_spcl.c_type == TS_END) {
2295*7c478bd9Sstevel@tonic-gate 			chkpt.sl_offset = 0;
2296*7c478bd9Sstevel@tonic-gate 			chkpt.sl_count = 1;	/* EOT indicator */
2297*7c478bd9Sstevel@tonic-gate 		}
2298*7c478bd9Sstevel@tonic-gate 		ino = nextspcl->s_spcl.c_inumber;
2299*7c478bd9Sstevel@tonic-gate 		type = nextspcl->s_spcl.c_type;
2300*7c478bd9Sstevel@tonic-gate 	} else {
2301*7c478bd9Sstevel@tonic-gate 		/*
2302*7c478bd9Sstevel@tonic-gate 		 * If not, use what we have.
2303*7c478bd9Sstevel@tonic-gate 		 */
2304*7c478bd9Sstevel@tonic-gate 		ino = spcl.c_inumber;
2305*7c478bd9Sstevel@tonic-gate 		type = spcl.c_type;
2306*7c478bd9Sstevel@tonic-gate 	}
2307*7c478bd9Sstevel@tonic-gate 
2308*7c478bd9Sstevel@tonic-gate 	switch (type) {		/* set output state */
2309*7c478bd9Sstevel@tonic-gate 	case TS_ADDR:
2310*7c478bd9Sstevel@tonic-gate 		switch (lastnonaddr) {
2311*7c478bd9Sstevel@tonic-gate 		case TS_INODE:
2312*7c478bd9Sstevel@tonic-gate 		case TS_TAPE:
2313*7c478bd9Sstevel@tonic-gate 			if ((lastnonaddrm & IFMT) == IFDIR ||
2314*7c478bd9Sstevel@tonic-gate 			    (lastnonaddrm & IFMT) == IFATTRDIR)
2315*7c478bd9Sstevel@tonic-gate 				state = DS_DIRS;
2316*7c478bd9Sstevel@tonic-gate 			else
2317*7c478bd9Sstevel@tonic-gate 				state = DS_FILES;
2318*7c478bd9Sstevel@tonic-gate 			break;
2319*7c478bd9Sstevel@tonic-gate 		case TS_CLRI:
2320*7c478bd9Sstevel@tonic-gate 			state = DS_CLRI;
2321*7c478bd9Sstevel@tonic-gate 			break;
2322*7c478bd9Sstevel@tonic-gate 		case TS_BITS:
2323*7c478bd9Sstevel@tonic-gate 			state = DS_BITS;
2324*7c478bd9Sstevel@tonic-gate 			break;
2325*7c478bd9Sstevel@tonic-gate 		}
2326*7c478bd9Sstevel@tonic-gate 		break;
2327*7c478bd9Sstevel@tonic-gate 	case TS_INODE:
2328*7c478bd9Sstevel@tonic-gate 		if ((spcl.c_dinode.di_mode & IFMT) == IFDIR ||
2329*7c478bd9Sstevel@tonic-gate 		    (spcl.c_dinode.di_mode & IFMT) == IFATTRDIR)
2330*7c478bd9Sstevel@tonic-gate 			state = DS_DIRS;
2331*7c478bd9Sstevel@tonic-gate 		else
2332*7c478bd9Sstevel@tonic-gate 			state = DS_FILES;
2333*7c478bd9Sstevel@tonic-gate 		break;
2334*7c478bd9Sstevel@tonic-gate 	case 0:			/* EOT on 1st record */
2335*7c478bd9Sstevel@tonic-gate 	case TS_TAPE:
2336*7c478bd9Sstevel@tonic-gate 		state = DS_START;
2337*7c478bd9Sstevel@tonic-gate 		ino = UFSROOTINO;
2338*7c478bd9Sstevel@tonic-gate 		break;
2339*7c478bd9Sstevel@tonic-gate 	case TS_CLRI:
2340*7c478bd9Sstevel@tonic-gate 		state = DS_CLRI;
2341*7c478bd9Sstevel@tonic-gate 		break;
2342*7c478bd9Sstevel@tonic-gate 	case TS_BITS:
2343*7c478bd9Sstevel@tonic-gate 		state = DS_BITS;
2344*7c478bd9Sstevel@tonic-gate 		break;
2345*7c478bd9Sstevel@tonic-gate 	case TS_END:
2346*7c478bd9Sstevel@tonic-gate 		if (spcl.c_type == TS_END)
2347*7c478bd9Sstevel@tonic-gate 			state = DS_DONE;
2348*7c478bd9Sstevel@tonic-gate 		else
2349*7c478bd9Sstevel@tonic-gate 			state = DS_END;
2350*7c478bd9Sstevel@tonic-gate 		break;
2351*7c478bd9Sstevel@tonic-gate 	}
2352*7c478bd9Sstevel@tonic-gate 
2353*7c478bd9Sstevel@tonic-gate 	/*
2354*7c478bd9Sstevel@tonic-gate 	 * Checkpoint info to be processed by rollforward():
2355*7c478bd9Sstevel@tonic-gate 	 *	The inode with which the next volume should begin
2356*7c478bd9Sstevel@tonic-gate 	 *	The last inode number on this volume
2357*7c478bd9Sstevel@tonic-gate 	 *	The last logical block number on this volume
2358*7c478bd9Sstevel@tonic-gate 	 *	The current output state
2359*7c478bd9Sstevel@tonic-gate 	 *	The offset within the current inode (already in sl_offset)
2360*7c478bd9Sstevel@tonic-gate 	 *	The number of records left from last spclrec (in sl_count)
2361*7c478bd9Sstevel@tonic-gate 	 *	The physical block the next vol begins with (in sl_firstrec)
2362*7c478bd9Sstevel@tonic-gate 	 */
2363*7c478bd9Sstevel@tonic-gate 	chkpt.sl_inos = ino;
2364*7c478bd9Sstevel@tonic-gate 	chkpt.sl_tapea = spcl.c_tapea + count;
2365*7c478bd9Sstevel@tonic-gate 	chkpt.sl_state = state;
2366*7c478bd9Sstevel@tonic-gate 
2367*7c478bd9Sstevel@tonic-gate 	if ((unsigned)atomic((int(*)())write, cmd, (char *)&chkpt,
2368*7c478bd9Sstevel@tonic-gate 	    sizeof (chkpt)) != sizeof (chkpt)) {
2369*7c478bd9Sstevel@tonic-gate 		cmdwrterr();
2370*7c478bd9Sstevel@tonic-gate 		dumpabort();
2371*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
2372*7c478bd9Sstevel@tonic-gate 	}
2373*7c478bd9Sstevel@tonic-gate 	if ((unsigned)atomic((int(*)())write, cmd, (char *)&spcl,
2374*7c478bd9Sstevel@tonic-gate 	    sizeof (spcl)) != sizeof (spcl)) {
2375*7c478bd9Sstevel@tonic-gate 		cmdwrterr();
2376*7c478bd9Sstevel@tonic-gate 		dumpabort();
2377*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
2378*7c478bd9Sstevel@tonic-gate 	}
2379*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
2380*7c478bd9Sstevel@tonic-gate 	if (xflag) {
2381*7c478bd9Sstevel@tonic-gate 		/* XGETTEXT:  #ifdef DEBUG only */
2382*7c478bd9Sstevel@tonic-gate 		msg(gettext("sent chkpt to master:\n"));
2383*7c478bd9Sstevel@tonic-gate 		msg("    ino %u\n", chkpt.sl_inos);
2384*7c478bd9Sstevel@tonic-gate 		msg("    1strec %u\n", chkpt.sl_firstrec);
2385*7c478bd9Sstevel@tonic-gate 		msg("    lastrec %u\n", chkpt.sl_tapea);
2386*7c478bd9Sstevel@tonic-gate 		msg("    written %u\n", chkpt.sl_offset);
2387*7c478bd9Sstevel@tonic-gate 		msg("    left %u\n", chkpt.sl_count);
2388*7c478bd9Sstevel@tonic-gate 		msg("    state %d\n", chkpt.sl_state);
2389*7c478bd9Sstevel@tonic-gate 	}
2390*7c478bd9Sstevel@tonic-gate #endif
2391*7c478bd9Sstevel@tonic-gate }
2392*7c478bd9Sstevel@tonic-gate 
2393*7c478bd9Sstevel@tonic-gate /*
2394*7c478bd9Sstevel@tonic-gate  * Since a read from a pipe may not return all we asked for,
2395*7c478bd9Sstevel@tonic-gate  * or a write may not write all we ask if we get a signal,
2396*7c478bd9Sstevel@tonic-gate  * loop until the count is satisfied (or error).
2397*7c478bd9Sstevel@tonic-gate  */
2398*7c478bd9Sstevel@tonic-gate static ssize_t
2399*7c478bd9Sstevel@tonic-gate atomic(func, fd, buf, count)
2400*7c478bd9Sstevel@tonic-gate 	int (*func)(), fd, count;
2401*7c478bd9Sstevel@tonic-gate 	char *buf;
2402*7c478bd9Sstevel@tonic-gate {
2403*7c478bd9Sstevel@tonic-gate 	ssize_t got = 0, need = count;
2404*7c478bd9Sstevel@tonic-gate 
2405*7c478bd9Sstevel@tonic-gate 	/* don't inherit random value if immediately get zero back from func */
2406*7c478bd9Sstevel@tonic-gate 	errno = 0;
2407*7c478bd9Sstevel@tonic-gate 	while (need > 0) {
2408*7c478bd9Sstevel@tonic-gate 		got = (*func)(fd, buf, MIN(need, 4096));
2409*7c478bd9Sstevel@tonic-gate 		if (got < 0 && errno == EINTR)
2410*7c478bd9Sstevel@tonic-gate 			continue;
2411*7c478bd9Sstevel@tonic-gate 		if (got <= 0)
2412*7c478bd9Sstevel@tonic-gate 			break;
2413*7c478bd9Sstevel@tonic-gate 		buf += got;
2414*7c478bd9Sstevel@tonic-gate 		need -= got;
2415*7c478bd9Sstevel@tonic-gate 	}
2416*7c478bd9Sstevel@tonic-gate 	/* if we got what was asked for, return count, else failure (got) */
2417*7c478bd9Sstevel@tonic-gate 	return ((need != 0) ? got : count);
2418*7c478bd9Sstevel@tonic-gate }
2419*7c478bd9Sstevel@tonic-gate 
2420*7c478bd9Sstevel@tonic-gate void
2421*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
2422*7c478bd9Sstevel@tonic-gate positiontape(char *msgbuf)
2423*7c478bd9Sstevel@tonic-gate #else
2424*7c478bd9Sstevel@tonic-gate positiontape(msgbuf)
2425*7c478bd9Sstevel@tonic-gate 	char *msgbuf;
2426*7c478bd9Sstevel@tonic-gate #endif
2427*7c478bd9Sstevel@tonic-gate {
2428*7c478bd9Sstevel@tonic-gate 	/* Static as never change, no need to waste stack space */
2429*7c478bd9Sstevel@tonic-gate 	static struct mtget mt;
2430*7c478bd9Sstevel@tonic-gate 	static struct mtop rew = { MTREW, 1 };
2431*7c478bd9Sstevel@tonic-gate 	static struct mtop fsf = { MTFSF, 1 };
2432*7c478bd9Sstevel@tonic-gate 	char *info = strdup(gettext("Positioning `%s' to file %ld\n"));
2433*7c478bd9Sstevel@tonic-gate 	char *fail = strdup(gettext("Cannot position tape to file %d\n"));
2434*7c478bd9Sstevel@tonic-gate 	int m;
2435*7c478bd9Sstevel@tonic-gate 
2436*7c478bd9Sstevel@tonic-gate 	/* gettext()'s return value is volatile, hence the strdup()s */
2437*7c478bd9Sstevel@tonic-gate 
2438*7c478bd9Sstevel@tonic-gate 	m = (access(tape, F_OK) == 0) ? 0 : O_CREAT;
2439*7c478bd9Sstevel@tonic-gate 
2440*7c478bd9Sstevel@tonic-gate 	/*
2441*7c478bd9Sstevel@tonic-gate 	 * To avoid writing tape marks at inappropriate places, we open the
2442*7c478bd9Sstevel@tonic-gate 	 * device read-only, position it, close it, and reopen it for writing.
2443*7c478bd9Sstevel@tonic-gate 	 */
2444*7c478bd9Sstevel@tonic-gate 	while ((to = host ? rmtopen(tape, O_RDONLY) :
2445*7c478bd9Sstevel@tonic-gate 	    safe_device_open(tape, O_RDONLY|m, 0600)) < 0) {
2446*7c478bd9Sstevel@tonic-gate 		if (autoload) {
2447*7c478bd9Sstevel@tonic-gate 			if (!query_once(msgbuf, 1)) {
2448*7c478bd9Sstevel@tonic-gate 				dumpabort();
2449*7c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
2450*7c478bd9Sstevel@tonic-gate 			}
2451*7c478bd9Sstevel@tonic-gate 		} else {
2452*7c478bd9Sstevel@tonic-gate 			if (!query(msgbuf)) {
2453*7c478bd9Sstevel@tonic-gate 				dumpabort();
2454*7c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
2455*7c478bd9Sstevel@tonic-gate 			}
2456*7c478bd9Sstevel@tonic-gate 		}
2457*7c478bd9Sstevel@tonic-gate 	}
2458*7c478bd9Sstevel@tonic-gate 
2459*7c478bd9Sstevel@tonic-gate 	if (host) {
2460*7c478bd9Sstevel@tonic-gate 		if (rmtstatus(&mt) >= 0 &&
2461*7c478bd9Sstevel@tonic-gate 		    rmtioctl(MTREW, 1) >= 0 &&
2462*7c478bd9Sstevel@tonic-gate 		    filenum > 1) {
2463*7c478bd9Sstevel@tonic-gate 			msg(info, dumpdev, filenum);
2464*7c478bd9Sstevel@tonic-gate 			if (rmtioctl(MTFSF, filenum-1) < 0) {
2465*7c478bd9Sstevel@tonic-gate 				msg(fail, filenum);
2466*7c478bd9Sstevel@tonic-gate 				dumpabort();
2467*7c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
2468*7c478bd9Sstevel@tonic-gate 			}
2469*7c478bd9Sstevel@tonic-gate 		}
2470*7c478bd9Sstevel@tonic-gate 		rmtclose();
2471*7c478bd9Sstevel@tonic-gate 	} else {
2472*7c478bd9Sstevel@tonic-gate 		if (ioctl(to, MTIOCGET, &mt) >= 0 &&
2473*7c478bd9Sstevel@tonic-gate 		    ioctl(to, MTIOCTOP, &rew) >= 0 &&
2474*7c478bd9Sstevel@tonic-gate 		    filenum > 1) {
2475*7c478bd9Sstevel@tonic-gate 			msg(info, dumpdev, filenum);
2476*7c478bd9Sstevel@tonic-gate 			fsf.mt_count = filenum - 1;
2477*7c478bd9Sstevel@tonic-gate 			if (ioctl(to, MTIOCTOP, &fsf) < 0) {
2478*7c478bd9Sstevel@tonic-gate 				msg(fail, filenum);
2479*7c478bd9Sstevel@tonic-gate 				dumpabort();
2480*7c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
2481*7c478bd9Sstevel@tonic-gate 			}
2482*7c478bd9Sstevel@tonic-gate 		}
2483*7c478bd9Sstevel@tonic-gate 		(void) close(to);
2484*7c478bd9Sstevel@tonic-gate 		to = -1;
2485*7c478bd9Sstevel@tonic-gate 	}
2486*7c478bd9Sstevel@tonic-gate 
2487*7c478bd9Sstevel@tonic-gate 	free(info);
2488*7c478bd9Sstevel@tonic-gate 	free(fail);
2489*7c478bd9Sstevel@tonic-gate }
2490*7c478bd9Sstevel@tonic-gate 
2491*7c478bd9Sstevel@tonic-gate static void
2492*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
2493*7c478bd9Sstevel@tonic-gate cmdwrterr(void)
2494*7c478bd9Sstevel@tonic-gate #else
2495*7c478bd9Sstevel@tonic-gate cmdwrterr()
2496*7c478bd9Sstevel@tonic-gate #endif
2497*7c478bd9Sstevel@tonic-gate {
2498*7c478bd9Sstevel@tonic-gate 	int saverr = errno;
2499*7c478bd9Sstevel@tonic-gate 	msg(gettext("Error writing command pipe: %s\n"), strerror(saverr));
2500*7c478bd9Sstevel@tonic-gate }
2501*7c478bd9Sstevel@tonic-gate 
2502*7c478bd9Sstevel@tonic-gate static void
2503*7c478bd9Sstevel@tonic-gate #ifdef __STDC__
2504*7c478bd9Sstevel@tonic-gate cmdrderr(void)
2505*7c478bd9Sstevel@tonic-gate #else
2506*7c478bd9Sstevel@tonic-gate cmdrderr()
2507*7c478bd9Sstevel@tonic-gate #endif
2508*7c478bd9Sstevel@tonic-gate {
2509*7c478bd9Sstevel@tonic-gate 	int saverr = errno;
2510*7c478bd9Sstevel@tonic-gate 	msg(gettext("Error reading command pipe: %s\n"), strerror(saverr));
2511*7c478bd9Sstevel@tonic-gate }
2512