GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/dump/tape.c Lines: 0 370 0.0 %
Date: 2017-11-07 Branches: 0 208 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: tape.c,v 1.43 2015/08/20 22:02:20 deraadt Exp $	*/
2
/*	$NetBSD: tape.c,v 1.11 1997/06/05 11:13:26 lukem Exp $	*/
3
4
/*-
5
 * Copyright (c) 1980, 1991, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
#include <sys/param.h>	/* MAXBSIZE DEV_BSIZE */
34
#include <sys/socket.h>
35
#include <sys/time.h>
36
#include <sys/wait.h>
37
#include <sys/stat.h>
38
#include <ufs/ffs/fs.h>
39
#include <ufs/ufs/dinode.h>
40
41
#include <protocols/dumprestore.h>
42
43
#include <errno.h>
44
#include <fcntl.h>
45
#include <signal.h>
46
#include <stdio.h>
47
#include <stdlib.h>
48
#include <string.h>
49
#include <time.h>
50
#include <unistd.h>
51
#include <limits.h>
52
53
#include "dump.h"
54
#include "pathnames.h"
55
56
#define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
57
58
int	writesize;		/* size of malloc()ed buffer for tape */
59
int64_t	lastspclrec = -1;	/* tape block number of last written header */
60
int	trecno = 0;		/* next record to write in current block */
61
extern	int64_t blocksperfile;	/* number of blocks per output file */
62
int64_t	blocksthisvol;		/* number of blocks on current output file */
63
extern	int ntrec;		/* blocking factor on tape */
64
extern	int cartridge;
65
extern	char *host;
66
char	*nexttape;
67
68
static	ssize_t atomic(ssize_t (*)(int, void *, size_t), int, char *, int);
69
static	void doslave(int, int);
70
static	void enslave(void);
71
static	void flushtape(void);
72
static	void killall(void);
73
static	void rollforward(void);
74
75
void	tperror(int signo);
76
void	sigpipe(int signo);
77
void	proceed(int signo);
78
79
/*
80
 * Concurrent dump mods (Caltech) - disk block reading and tape writing
81
 * are exported to several slave processes.  While one slave writes the
82
 * tape, the others read disk blocks; they pass control of the tape in
83
 * a ring via signals. The parent process traverses the filesystem and
84
 * sends writeheader()'s and lists of daddr's to the slaves via pipes.
85
 * The following structure defines the instruction packets sent to slaves.
86
 */
87
struct req {
88
	daddr_t dblk;
89
	int count;
90
};
91
int reqsiz;
92
93
#define SLAVES 3		/* 1 slave writing, 1 reading, 1 for slack */
94
struct slave {
95
	int64_t tapea;		/* header number at start of this chunk */
96
	int64_t firstrec;	/* record number of this block */
97
	int count;		/* count to next header (used for TS_TAPE */
98
				/* after EOT) */
99
	int inode;		/* inode that we are currently dealing with */
100
	int fd;			/* FD for this slave */
101
	pid_t pid;		/* PID for this slave */
102
	int sent;		/* 1 == we've sent this slave requests */
103
	char (*tblock)[TP_BSIZE]; /* buffer for data blocks */
104
	struct req *req;	/* buffer for requests */
105
} slaves[SLAVES+1];
106
struct slave *slp;
107
108
char	(*nextblock)[TP_BSIZE];
109
110
static time_t tstart_volume;	/* time of volume start */
111
static int64_t tapea_volume;	/* value of spcl.c_tapea at volume start */
112
113
pid_t master;		/* pid of master, for sending error signals */
114
int tenths;		/* length of tape used per block written */
115
static volatile sig_atomic_t caught;	/* have we caught the signal to proceed? */
116
117
int
118
alloctape(void)
119
{
120
	int pgoff = getpagesize() - 1;
121
	char *buf;
122
	int i;
123
124
	writesize = ntrec * TP_BSIZE;
125
	reqsiz = (ntrec + 1) * sizeof(struct req);
126
	/*
127
	 * CDC 92181's and 92185's make 0.8" gaps in 1600-bpi start/stop mode
128
	 * (see DEC TU80 User's Guide).  The shorter gaps of 6250-bpi require
129
	 * repositioning after stopping, i.e, streaming mode, where the gap is
130
	 * variable, 0.30" to 0.45".  The gap is maximal when the tape stops.
131
	 */
132
	if (blocksperfile == 0 && !unlimited)
133
		tenths = writesize / density +
134
		    (cartridge ? 16 : density == 625 ? 5 : 8);
135
	/*
136
	 * Allocate tape buffer contiguous with the array of instruction
137
	 * packets, so flushtape() can write them together with one write().
138
	 * Align tape buffer on page boundary to speed up tape write().
139
	 */
140
	for (i = 0; i <= SLAVES; i++) {
141
		buf = malloc((unsigned)(reqsiz + writesize + pgoff + TP_BSIZE));
142
		if (buf == NULL)
143
			return(0);
144
		slaves[i].tblock = (char (*)[TP_BSIZE])
145
		    (((long)&buf[ntrec + 1] + pgoff) &~ pgoff);
146
		slaves[i].req = (struct req *)slaves[i].tblock - ntrec - 1;
147
	}
148
	slp = &slaves[0];
149
	slp->count = 1;
150
	slp->tapea = 0;
151
	slp->firstrec = 0;
152
	nextblock = slp->tblock;
153
	return(1);
154
}
155
156
void
157
writerec(char *dp, int isspcl)
158
{
159
160
	slp->req[trecno].dblk = 0;
161
	slp->req[trecno].count = 1;
162
	*(union u_spcl *)(*(nextblock)++) = *(union u_spcl *)dp;
163
	if (isspcl)
164
		lastspclrec = spcl.c_tapea;
165
	trecno++;
166
	spcl.c_tapea++;
167
	if (trecno >= ntrec)
168
		flushtape();
169
}
170
171
void
172
dumpblock(daddr_t blkno, int size)
173
{
174
	int avail, tpblks;
175
	daddr_t dblkno;
176
177
	dblkno = fsbtodb(sblock, blkno);
178
	tpblks = size >> tp_bshift;
179
	while ((avail = MINIMUM(tpblks, ntrec - trecno)) > 0) {
180
		slp->req[trecno].dblk = dblkno;
181
		slp->req[trecno].count = avail;
182
		trecno += avail;
183
		spcl.c_tapea += avail;
184
		if (trecno >= ntrec)
185
			flushtape();
186
		dblkno += avail << (tp_bshift - (ffs(DEV_BSIZE) - 1));
187
		tpblks -= avail;
188
	}
189
}
190
191
int	nogripe = 0;
192
193
/* ARGSUSED */
194
void
195
tperror(int signo)
196
{
197
	/* XXX - signal races */
198
199
	if (pipeout) {
200
		msg("write error on %s\n", tape);
201
		quit("Cannot recover\n");
202
		/* NOTREACHED */
203
	}
204
	msg("write error %lld blocks into volume %d\n",
205
	    (long long)blocksthisvol, tapeno);
206
	broadcast("DUMP WRITE ERROR!\n");
207
	if (!query("Do you want to restart?"))
208
		dumpabort(0);
209
	msg("Closing this volume.  Prepare to restart with new media;\n");
210
	msg("this dump volume will be rewritten.\n");
211
	killall();
212
	nogripe = 1;
213
	close_rewind();
214
	Exit(X_REWRITE);
215
}
216
217
/* ARGSUSED */
218
void
219
sigpipe(int signo)
220
{
221
222
	quit("Broken pipe\n");
223
}
224
225
/*
226
 * do_stats --
227
 *	Update xferrate stats
228
 */
229
time_t
230
do_stats(void)
231
{
232
	time_t tnow, ttaken;
233
	int64_t blocks;
234
235
	(void)time(&tnow);
236
	ttaken = tnow - tstart_volume;
237
	blocks = spcl.c_tapea - tapea_volume;
238
	msg("Volume %d completed at: %s", tapeno, ctime(&tnow));
239
	if (ttaken > 0) {
240
		msg("Volume %d took %lld:%02lld:%02lld\n", tapeno,
241
		    (long long)ttaken / 3600, ((long long)ttaken % 3600) / 60,
242
		    (long long)ttaken % 60);
243
		blocks /= ttaken;
244
		msg("Volume %d transfer rate: %lld KB/s\n", tapeno, blocks);
245
		xferrate += blocks;
246
	}
247
	return(tnow);
248
}
249
250
/*
251
 * statussig --
252
 *	information message upon receipt of SIGINFO
253
 *	(derived from optr.c::timeest())
254
 * XXX not safe
255
 */
256
/* ARGSUSED */
257
void
258
statussig(int signo)
259
{
260
	time_t	tnow, deltat;
261
	char	msgbuf[128];
262
	int save_errno = errno;
263
264
	if (blockswritten < 500)
265
		return;
266
	(void) time(&tnow);
267
	deltat = tstart_writing - tnow + (1.0 * (tnow - tstart_writing))
268
		/ blockswritten * tapesize;
269
	(void)snprintf(msgbuf, sizeof(msgbuf),
270
	    "dump: %s %3.2f%% done at %lld KB/s, finished in %d:%02d\n",
271
	    tape, (blockswritten * 100.0) / tapesize,
272
	    (spcl.c_tapea - tapea_volume) / (tnow - tstart_volume),
273
	    (int)(deltat / 3600), (int)((deltat % 3600) / 60));
274
	write(STDERR_FILENO, msgbuf, strlen(msgbuf));
275
	errno = save_errno;
276
}
277
278
static void
279
flushtape(void)
280
{
281
	int i, blks, got;
282
	int64_t lastfirstrec;
283
284
	int siz = (char *)nextblock - (char *)slp->req;
285
286
	slp->req[trecno].count = 0;			/* Sentinel */
287
288
	if (atomic((ssize_t (*)(int, void *, size_t))write, slp->fd,
289
	    (char *)slp->req, siz) != siz)
290
		quit("error writing command pipe: %s\n", strerror(errno));
291
	slp->sent = 1; /* we sent a request, read the response later */
292
293
	lastfirstrec = slp->firstrec;
294
295
	if (++slp >= &slaves[SLAVES])
296
		slp = &slaves[0];
297
298
	/* Read results back from next slave */
299
	if (slp->sent) {
300
		if (atomic(read, slp->fd, (char *)&got, sizeof(got))
301
		    != sizeof(got)) {
302
			perror("  DUMP: error reading command pipe in master");
303
			dumpabort(0);
304
		}
305
		slp->sent = 0;
306
307
		/* Check for end of tape */
308
		if (got < writesize) {
309
			msg("End of tape detected\n");
310
311
			/*
312
			 * Drain the results, don't care what the values were.
313
			 * If we read them here then trewind won't...
314
			 */
315
			for (i = 0; i < SLAVES; i++) {
316
				if (slaves[i].sent) {
317
					if (atomic(read, slaves[i].fd,
318
					    (char *)&got, sizeof(got))
319
					    != sizeof(got)) {
320
						perror("  DUMP: error reading command pipe in master");
321
						dumpabort(0);
322
					}
323
					slaves[i].sent = 0;
324
				}
325
			}
326
327
			close_rewind();
328
			rollforward();
329
			return;
330
		}
331
	}
332
333
	blks = 0;
334
	if (spcl.c_type != TS_END) {
335
		for (i = 0; i < spcl.c_count; i++)
336
			if (spcl.c_addr[i] != 0)
337
				blks++;
338
	}
339
	slp->count = lastspclrec + blks + 1 - spcl.c_tapea;
340
	slp->tapea = spcl.c_tapea;
341
	slp->firstrec = lastfirstrec + ntrec;
342
	slp->inode = curino;
343
	nextblock = slp->tblock;
344
	trecno = 0;
345
	asize += tenths;
346
	blockswritten += ntrec;
347
	blocksthisvol += ntrec;
348
	if (!pipeout && !unlimited && (blocksperfile ?
349
	    (blocksthisvol >= blocksperfile) : (asize > tsize))) {
350
		close_rewind();
351
		startnewtape(0);
352
	}
353
	timeest();
354
}
355
356
void
357
trewind(void)
358
{
359
	struct stat sb;
360
	int f, got;
361
362
	for (f = 0; f < SLAVES; f++) {
363
		/*
364
		 * Drain the results, but unlike EOT we DO (or should) care
365
		 * what the return values were, since if we detect EOT after
366
		 * we think we've written the last blocks to the tape anyway,
367
		 * we have to replay those blocks with rollforward.
368
		 *
369
		 * fixme: punt for now.
370
		 */
371
		if (slaves[f].sent) {
372
			if (atomic(read, slaves[f].fd, (char *)&got, sizeof(got))
373
			    != sizeof(got)) {
374
				perror("  DUMP: error reading command pipe in master");
375
				dumpabort(0);
376
			}
377
			slaves[f].sent = 0;
378
			if (got != writesize) {
379
				msg("EOT detected in last 2 tape records!\n");
380
				msg("Use a longer tape, decrease the size estimate\n");
381
				quit("or use no size estimate at all.\n");
382
			}
383
		}
384
		(void) close(slaves[f].fd);
385
	}
386
	while (wait((int *)NULL) >= 0)	/* wait for any signals from slaves */
387
		/* void */;
388
389
	if (pipeout)
390
		return;
391
392
	msg("Closing %s\n", tape);
393
394
#ifdef RDUMP
395
	if (host) {
396
		rmtclose();
397
		while (rmtopen(tape, O_RDONLY) < 0)
398
			sleep(10);
399
		rmtclose();
400
		return;
401
	}
402
#endif
403
	/*
404
	 * st(4) says: "Bit 1 of the minor number specifies whether an eject is
405
	 * attempted when the device is closed.  When it is set, the device
406
	 * will attempt to eject its media on close ...".
407
	 *
408
	 * If the tape has been ejected, looping on open() will generate 'Media
409
	 * not present' errors until a tape is loaded. Once loaded the tape
410
	 * will be immediately ejected as a result of the second close().
411
	 *
412
	 * So if the tape will be ejected, just close and return.
413
	 */
414
	if ((fstat(tapefd, &sb) == 0) && (minor(sb.st_rdev) & 0x02)) {
415
		(void) close(tapefd);
416
		return;
417
	}
418
419
	(void) close(tapefd);
420
	while ((f = open(tape, O_RDONLY)) < 0)
421
		sleep (10);
422
	(void) close(f);
423
}
424
425
void
426
close_rewind(void)
427
{
428
	trewind();
429
	(void)do_stats();
430
	if (nexttape)
431
		return;
432
	if (!nogripe) {
433
		msg("Change Volumes: Mount volume #%d\n", tapeno+1);
434
		broadcast("CHANGE DUMP VOLUMES!\7\7\n");
435
	}
436
	while (!query("Is the new volume mounted and ready to go?"))
437
		if (query("Do you want to abort?")) {
438
			dumpabort(0);
439
			/*NOTREACHED*/
440
		}
441
}
442
443
void
444
rollforward(void)
445
{
446
	struct req *p, *q, *prev;
447
	struct slave *tslp;
448
	int i, size, got;
449
	int64_t savedtapea;
450
	union u_spcl *ntb, *otb;
451
	tslp = &slaves[SLAVES];
452
	ntb = (union u_spcl *)tslp->tblock[1];
453
454
	/*
455
	 * Each of the N slaves should have requests that need to
456
	 * be replayed on the next tape.  Use the extra slave buffers
457
	 * (slaves[SLAVES]) to construct request lists to be sent to
458
	 * each slave in turn.
459
	 */
460
	for (i = 0; i < SLAVES; i++) {
461
		q = &tslp->req[1];
462
		otb = (union u_spcl *)slp->tblock;
463
464
		/*
465
		 * For each request in the current slave, copy it to tslp.
466
		 */
467
468
		prev = NULL;
469
		for (p = slp->req; p->count > 0; p += p->count) {
470
			*q = *p;
471
			if (p->dblk == 0)
472
				*ntb++ = *otb++; /* copy the datablock also */
473
			prev = q;
474
			q += q->count;
475
		}
476
		if (prev == NULL)
477
			quit("rollforward: protocol botch\n");
478
		if (prev->dblk != 0)
479
			prev->count -= 1;
480
		else
481
			ntb--;
482
		q -= 1;
483
		q->count = 0;
484
		q = &tslp->req[0];
485
		if (i == 0) {
486
			q->dblk = 0;
487
			q->count = 1;
488
			trecno = 0;
489
			nextblock = tslp->tblock;
490
			savedtapea = spcl.c_tapea;
491
			spcl.c_tapea = slp->tapea;
492
			startnewtape(0);
493
			spcl.c_tapea = savedtapea;
494
			lastspclrec = savedtapea - 1;
495
		}
496
		size = (char *)ntb - (char *)q;
497
		if (atomic((ssize_t (*)(int, void *, size_t))write,
498
		    slp->fd, (char *)q, size) != size) {
499
			perror("  DUMP: error writing command pipe");
500
			dumpabort(0);
501
		}
502
		slp->sent = 1;
503
		if (++slp >= &slaves[SLAVES])
504
			slp = &slaves[0];
505
506
		q->count = 1;
507
508
		if (prev->dblk != 0) {
509
			/*
510
			 * If the last one was a disk block, make the
511
			 * first of this one be the last bit of that disk
512
			 * block...
513
			 */
514
			q->dblk = prev->dblk +
515
				prev->count * (TP_BSIZE / DEV_BSIZE);
516
			ntb = (union u_spcl *)tslp->tblock;
517
		} else {
518
			/*
519
			 * It wasn't a disk block.  Copy the data to its
520
			 * new location in the buffer.
521
			 */
522
			q->dblk = 0;
523
			*((union u_spcl *)tslp->tblock) = *ntb;
524
			ntb = (union u_spcl *)tslp->tblock[1];
525
		}
526
	}
527
	slp->req[0] = *q;
528
	nextblock = slp->tblock;
529
	if (q->dblk == 0)
530
		nextblock++;
531
	trecno = 1;
532
533
	/*
534
	 * Clear the first slaves' response.  One hopes that it
535
	 * worked ok, otherwise the tape is much too short!
536
	 */
537
	if (slp->sent) {
538
		if (atomic(read, slp->fd, (char *)&got, sizeof(got))
539
		    != sizeof(got)) {
540
			perror("  DUMP: error reading command pipe in master");
541
			dumpabort(0);
542
		}
543
		slp->sent = 0;
544
545
		if (got != writesize) {
546
			quit("EOT detected at start of the tape!\n");
547
		}
548
	}
549
}
550
551
/*
552
 * We implement taking and restoring checkpoints on the tape level.
553
 * When each tape is opened, a new process is created by forking; this
554
 * saves all of the necessary context in the parent.  The child
555
 * continues the dump; the parent waits around, saving the context.
556
 * If the child returns X_REWRITE, then it had problems writing that tape;
557
 * this causes the parent to fork again, duplicating the context, and
558
 * everything continues as if nothing had happened.
559
 */
560
void
561
startnewtape(int top)
562
{
563
	pid_t	parentpid;
564
	pid_t	childpid;
565
	int	status;
566
	pid_t	waitingpid;
567
	char	*p;
568
	sig_t	interrupt_save;
569
570
	interrupt_save = signal(SIGINT, SIG_IGN);
571
	parentpid = getpid();
572
	tapea_volume = spcl.c_tapea;
573
	(void)time(&tstart_volume);
574
575
restore_check_point:
576
	(void)signal(SIGINT, interrupt_save);
577
	/*
578
	 *	All signals are inherited...
579
	 */
580
	childpid = fork();
581
	if (childpid < 0) {
582
		msg("Context save fork fails in parent %d\n", parentpid);
583
		Exit(X_ABORT);
584
	}
585
	if (childpid != 0) {
586
		/*
587
		 *	PARENT:
588
		 *	save the context by waiting
589
		 *	until the child doing all of the work returns.
590
		 *	don't catch the interrupt
591
		 */
592
		signal(SIGINT, SIG_IGN);
593
#ifdef TDEBUG
594
		msg("Tape: %d; parent process: %d child process %d\n",
595
			tapeno+1, parentpid, childpid);
596
#endif /* TDEBUG */
597
		while ((waitingpid = wait(&status)) != childpid)
598
			msg("Parent %d waiting for child %d has another child %d return\n",
599
				parentpid, childpid, waitingpid);
600
		if (status & 0xFF) {
601
			msg("Child %d returns LOB status %o\n",
602
				childpid, status&0xFF);
603
		}
604
		status = (status >> 8) & 0xFF;
605
#ifdef TDEBUG
606
		switch(status) {
607
			case X_FINOK:
608
				msg("Child %d finishes X_FINOK\n", childpid);
609
				break;
610
			case X_ABORT:
611
				msg("Child %d finishes X_ABORT\n", childpid);
612
				break;
613
			case X_REWRITE:
614
				msg("Child %d finishes X_REWRITE\n", childpid);
615
				break;
616
			default:
617
				msg("Child %d finishes unknown %d\n",
618
					childpid, status);
619
				break;
620
		}
621
#endif /* TDEBUG */
622
		switch(status) {
623
			case X_FINOK:
624
				Exit(X_FINOK);
625
				break;
626
			case X_ABORT:
627
				Exit(X_ABORT);
628
				break;
629
			case X_REWRITE:
630
				goto restore_check_point;
631
			default:
632
				msg("Bad return code from dump: %d\n", status);
633
				Exit(X_ABORT);
634
		}
635
		/*NOTREACHED*/
636
	} else {	/* we are the child; just continue */
637
#ifdef TDEBUG
638
		sleep(4);	/* allow time for parent's message to get out */
639
		msg("Child on Tape %d has parent %d, my pid = %d\n",
640
			tapeno+1, parentpid, getpid());
641
#endif /* TDEBUG */
642
		/*
643
		 * If we have a name like "/dev/rst0,/dev/rst1",
644
		 * use the name before the comma first, and save
645
		 * the remaining names for subsequent volumes.
646
		 */
647
		tapeno++;               /* current tape sequence */
648
		if (nexttape || strchr(tape, ',')) {
649
			if (nexttape && *nexttape)
650
				tape = nexttape;
651
			if ((p = strchr(tape, ',')) != NULL) {
652
				*p = '\0';
653
				nexttape = p + 1;
654
			} else
655
				nexttape = NULL;
656
			msg("Dumping volume %d on %s\n", tapeno, tape);
657
		}
658
#ifdef RDUMP
659
		while ((tapefd = (host ? rmtopen(tape, O_WRONLY|O_CREAT) :
660
			pipeout ? 1 : open(tape, O_WRONLY|O_CREAT, 0666))) < 0)
661
#else
662
		while ((tapefd = (pipeout ? 1 :
663
				  open(tape, O_WRONLY|O_CREAT, 0666))) < 0)
664
#endif
665
		    {
666
			msg("Cannot open output \"%s\".\n", tape);
667
			if (!query("Do you want to retry the open?"))
668
				dumpabort(0);
669
		}
670
671
		enslave();  /* Share open tape file descriptor with slaves */
672
673
		asize = 0;
674
		blocksthisvol = 0;
675
		if (top)
676
			newtape++;		/* new tape signal */
677
		spcl.c_count = slp->count;
678
		/*
679
		 * measure firstrec in TP_BSIZE units since restore doesn't
680
		 * know the correct ntrec value...
681
		 */
682
		spcl.c_firstrec = slp->firstrec;
683
		spcl.c_volume++;
684
		spcl.c_type = TS_TAPE;
685
		if (sblock->fs_magic != FS_UFS2_MAGIC)
686
			spcl.c_flags |= DR_NEWHEADER;
687
		writeheader((ino_t)slp->inode);
688
		if (sblock->fs_magic != FS_UFS2_MAGIC)
689
			spcl.c_flags &=~ DR_NEWHEADER;
690
		msg("Volume %d started at: %s", tapeno, ctime(&tstart_volume));
691
		if (tapeno > 1)
692
			msg("Volume %d begins with blocks from inode %llu\n",
693
			    tapeno, (unsigned long long)slp->inode);
694
	}
695
}
696
697
/* ARGSUSED */
698
void
699
dumpabort(int signo)
700
{
701
702
	if (master != 0 && master != getpid())
703
		/* Signals master to call dumpabort */
704
		(void) kill(master, SIGTERM);
705
	else {
706
		killall();
707
		msg("The ENTIRE dump is aborted.\n");
708
	}
709
#ifdef RDUMP
710
	rmtclose();
711
#endif
712
	Exit(X_ABORT);
713
}
714
715
__dead void
716
Exit(int status)
717
{
718
719
#ifdef TDEBUG
720
	msg("pid = %d exits with status %d\n", getpid(), status);
721
#endif /* TDEBUG */
722
	exit(status);
723
}
724
725
/*
726
 * proceed - handler for SIGUSR2, used to synchronize IO between the slaves.
727
 */
728
/* ARGSUSED */
729
void
730
proceed(int signo)
731
{
732
	caught++;
733
}
734
735
void
736
enslave(void)
737
{
738
	int cmd[2];
739
	int i, j;
740
741
	master = getpid();
742
743
	signal(SIGTERM, dumpabort);  /* Slave sends SIGTERM on dumpabort() */
744
	signal(SIGPIPE, sigpipe);
745
	signal(SIGUSR1, tperror);    /* Slave sends SIGUSR1 on tape errors */
746
	signal(SIGUSR2, proceed);    /* Slave sends SIGUSR2 to next slave */
747
748
	for (i = 0; i < SLAVES; i++) {
749
		if (i == slp - &slaves[0]) {
750
			caught = 1;
751
		} else {
752
			caught = 0;
753
		}
754
755
		if (socketpair(AF_UNIX, SOCK_STREAM, 0, cmd) < 0 ||
756
		    (slaves[i].pid = fork()) < 0)
757
			quit("too many slaves, %d (recompile smaller): %s\n",
758
			    i, strerror(errno));
759
760
		slaves[i].fd = cmd[1];
761
		slaves[i].sent = 0;
762
		if (slaves[i].pid == 0) { 	    /* Slave starts up here */
763
			for (j = 0; j <= i; j++)
764
			        (void) close(slaves[j].fd);
765
			signal(SIGINT, SIG_IGN);    /* Master handles this */
766
			signal(SIGINFO, SIG_IGN);
767
			doslave(cmd[0], i);
768
			Exit(X_FINOK);
769
		}
770
	}
771
772
	for (i = 0; i < SLAVES; i++)
773
		(void) atomic((ssize_t (*)(int, void *, size_t))write,
774
		    slaves[i].fd, (char *) &slaves[(i + 1) % SLAVES].pid,
775
		    sizeof(slaves[0].pid));
776
	master = 0;
777
}
778
779
void
780
killall(void)
781
{
782
	int i;
783
784
	for (i = 0; i < SLAVES; i++)
785
		if (slaves[i].pid > 0) {
786
			(void) kill(slaves[i].pid, SIGKILL);
787
			slaves[i].pid = 0;
788
		}
789
}
790
791
/*
792
 * Synchronization - each process has a lockfile, and shares file
793
 * descriptors to the following process's lockfile.  When our write
794
 * completes, we release our lock on the following process's lock-
795
 * file, allowing the following process to lock it and proceed. We
796
 * get the lock back for the next cycle by swapping descriptors.
797
 */
798
static void
799
doslave(int cmd, int slave_number)
800
{
801
	int nread, nextslave, size, wrote = 0, eot_count;
802
	sigset_t nsigset, osigset;
803
804
	/*
805
	 * Need our own seek pointer.
806
	 */
807
	(void) close(diskfd);
808
	if ((diskfd = open(disk, O_RDONLY)) < 0)
809
		quit("slave couldn't reopen disk: %s\n", strerror(errno));
810
811
	/*
812
	 * Need the pid of the next slave in the loop...
813
	 */
814
	if ((nread = atomic(read, cmd, (char *)&nextslave, sizeof(nextslave)))
815
	    != sizeof(nextslave)) {
816
		quit("master/slave protocol botched - didn't get pid of next slave.\n");
817
	}
818
819
	/*
820
	 * Get list of blocks to dump, read the blocks into tape buffer
821
	 */
822
	while ((nread = atomic(read, cmd, (char *)slp->req, reqsiz)) == reqsiz) {
823
		struct req *p = slp->req;
824
825
		for (trecno = 0; trecno < ntrec;
826
		     trecno += p->count, p += p->count) {
827
			if (p->dblk) {
828
				bread(p->dblk, slp->tblock[trecno],
829
					p->count * TP_BSIZE);
830
			} else {
831
				if (p->count != 1 || atomic(read, cmd,
832
				    (char *)slp->tblock[trecno],
833
				    TP_BSIZE) != TP_BSIZE)
834
				       quit("master/slave protocol botched.\n");
835
			}
836
		}
837
838
		sigemptyset(&nsigset);
839
		sigaddset(&nsigset, SIGUSR2);
840
		sigprocmask(SIG_BLOCK, &nsigset, &osigset);
841
		while (!caught)
842
			sigsuspend(&osigset);
843
		caught = 0;
844
		sigprocmask(SIG_SETMASK, &osigset, NULL);
845
846
		/* Try to write the data... */
847
		eot_count = 0;
848
		size = 0;
849
850
		while (eot_count < 10 && size < writesize) {
851
#ifdef RDUMP
852
			if (host)
853
				wrote = rmtwrite(slp->tblock[0]+size,
854
				    writesize-size);
855
			else
856
#endif
857
				wrote = write(tapefd, slp->tblock[0]+size,
858
				    writesize-size);
859
#ifdef WRITEDEBUG
860
			printf("slave %d wrote %d\n", slave_number, wrote);
861
#endif
862
			if (wrote < 0)
863
				break;
864
			if (wrote == 0)
865
				eot_count++;
866
			size += wrote;
867
		}
868
869
#ifdef WRITEDEBUG
870
		if (size != writesize)
871
		 printf("slave %d only wrote %d out of %d bytes and gave up.\n",
872
		     slave_number, size, writesize);
873
#endif
874
875
		if (eot_count > 0)
876
			size = 0;
877
878
		/*
879
		 * Handle ENOSPC as an EOT condition
880
		 */
881
		if (wrote < 0 && errno == ENOSPC) {
882
			wrote = 0;
883
			eot_count++;
884
		}
885
886
		if (size < 0) {
887
			(void) kill(master, SIGUSR1);
888
			sigemptyset(&nsigset);
889
			for (;;)
890
				sigsuspend(&nsigset);
891
		} else {
892
			/*
893
			 * pass size of write back to master
894
			 * (for EOT handling)
895
			 */
896
			(void) atomic((ssize_t (*)(int, void *, size_t))write,
897
			    cmd, (char *)&size, sizeof(size));
898
		}
899
900
		/*
901
		 * If partial write, don't want next slave to go.
902
		 * Also jolts him awake.
903
		 */
904
		(void) kill(nextslave, SIGUSR2);
905
	}
906
	if (nread != 0)
907
		quit("error reading command pipe: %s\n", strerror(errno));
908
}
909
910
/*
911
 * Since a read from a pipe may not return all we asked for,
912
 * or a write may not write all we ask if we get a signal,
913
 * loop until the count is satisfied (or error).
914
 */
915
static ssize_t
916
atomic(ssize_t (*func)(int, void *, size_t), int fd, char *buf, int count)
917
{
918
	ssize_t got, need = count;
919
920
	while ((got = (*func)(fd, buf, need)) > 0 && (need -= got) > 0)
921
		buf += got;
922
	return (got < 0 ? got : count - need);
923
}