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