]> git.wh0rd.org - dump.git/blob - dump/tape.c
Fix SYS_clone on s390
[dump.git] / dump / tape.c
1 /*
2 * Ported to Linux's Second Extended File System as part of the
3 * dump and restore backup suit
4 * Remy Card <card@Linux.EU.Org>, 1994-1997
5 * Stelian Pop <stelian@popies.net>, 1999-2000
6 * Stelian Pop <stelian@popies.net> - AlcĂ´ve <www.alcove.com>, 2000-2002
7 */
8
9 /*-
10 * Copyright (c) 1980, 1991, 1993
11 * The Regents of the University of California. All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38 #ifndef lint
39 static const char rcsid[] =
40 "$Id: tape.c,v 1.92 2011/05/20 09:48:40 stelian Exp $";
41 #endif /* not lint */
42
43 #include <config.h>
44 #include <compatlfs.h>
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <setjmp.h>
48 #include <signal.h>
49 #include <stdio.h>
50 #include <compaterr.h>
51 #include <system.h>
52 #ifdef __STDC__
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56 #else
57 int write(), read();
58 #endif
59
60 #ifdef __linux__
61 #include <sys/types.h>
62 #include <sys/time.h>
63 #include <sys/ioctl.h>
64 #include <sys/mount.h> /* for definition of BLKFLSBUF */
65 #ifndef BLKFLSBUF /* last resort... */
66 #define BLKFLSBUF _IO(0x12, 97) /* Flush buffer cache. */
67 #endif
68 #include <time.h>
69 #endif
70 #include <sys/param.h>
71 #include <sys/socket.h>
72 #include <sys/wait.h>
73 #include <sys/mtio.h>
74 #ifdef __linux__
75 #ifdef HAVE_EXT2FS_EXT2_FS_H
76 #include <ext2fs/ext2_fs.h>
77 #else
78 #include <linux/ext2_fs.h>
79 #endif
80 #include <ext2fs/ext2fs.h>
81 #include <sys/stat.h>
82 #include <bsdcompat.h>
83 #elif defined sunos
84 #include <sys/vnode.h>
85
86 #include <ufs/fs.h>
87 #include <ufs/inode.h>
88 #else
89 #include <ufs/ufs/dinode.h>
90 #include <ufs/ffs/fs.h>
91 #endif /* __linux__ */
92
93 #include <protocols/dumprestore.h>
94
95 #ifdef HAVE_ZLIB
96 #include <zlib.h>
97 #endif /* HAVE_ZLIB */
98
99 #ifdef HAVE_BZLIB
100 #include <bzlib.h>
101 #endif /* HAVE_BZLIB */
102
103 #ifdef HAVE_LZO
104 #include <minilzo.h>
105 #endif /* HAVE_LZO */
106
107 #include "dump.h"
108
109 int writesize; /* size of malloc()ed buffer for tape */
110 long lastspclrec = -1; /* tape block number of last written header */
111 int trecno = 0; /* next record to write in current block */
112 extern long *blocksperfiles; /* number of blocks per output file(s) */
113 long blocksperfiles_current; /* current position in blocksperfiles */
114 long blocksthisvol; /* number of blocks on current output file */
115 extern int ntrec; /* blocking factor on tape */
116 extern int cartridge;
117 char *nexttape;
118 extern pid_t rshpid;
119 int eot_code = 1;
120 long long tapea_bytes = 0; /* bytes_written at start of current volume */
121 static int magtapeout; /* output is really a tape */
122
123 static ssize_t dump_atomic_read __P((int, char *, size_t));
124 static ssize_t dump_atomic_write __P((int, const char *, size_t));
125 #ifdef WRITEDEBUG
126 static void doslave __P((int, int, int));
127 #else
128 static void doslave __P((int, int));
129 #endif
130 static void enslave __P((void));
131 static void flushtape __P((void));
132 static void killall __P((void));
133 static void rollforward __P((void));
134 #ifdef USE_QFA
135 static int GetTapePos __P((long long *));
136 static int MkTapeString __P((struct s_spcl *, long long));
137 #define FILESQFAPOS 20
138 #endif
139
140 /*
141 * Concurrent dump mods (Caltech) - disk block reading and tape writing
142 * are exported to several slave processes. While one slave writes the
143 * tape, the others read disk blocks; they pass control of the tape in
144 * a ring via signals. The parent process traverses the filesystem and
145 * sends writeheader()'s and lists of daddr's to the slaves via pipes.
146 * The following structure defines the instruction packets sent to slaves.
147 */
148 struct req {
149 ext2_loff_t dblk;
150 int count;
151 };
152 int reqsiz;
153
154 struct slave_results {
155 ssize_t unclen; /* uncompressed length */
156 ssize_t clen; /* compressed length */
157 };
158
159 #define SLAVES 3 /* 1 slave writing, 1 reading, 1 for slack */
160 struct slave {
161 int tapea; /* header number at start of this chunk */
162 int count; /* count to next header (used for TS_TAPE */
163 /* after EOT) */
164 int inode; /* inode that we are currently dealing with */
165 int fd; /* FD for this slave */
166 int pid; /* PID for this slave */
167 int sent; /* 1 == we've sent this slave requests */
168 int firstrec; /* record number of this block */
169 char (*tblock)[TP_BSIZE]; /* buffer for data blocks */
170 struct req *req; /* buffer for requests */
171 } slaves[SLAVES+1];
172 struct slave *slp;
173
174 char (*nextblock)[TP_BSIZE];
175
176 static time_t tstart_volume; /* time of volume start */
177 static int tapea_volume; /* value of spcl.c_tapea at volume start */
178
179 int master; /* pid of master, for sending error signals */
180 int tenths; /* length of tape overhead per block written */
181 static int caught; /* have we caught the signal to proceed? */
182 static int ready; /* have we reached the lock point without having */
183 /* received the SIGUSR2 signal from the prev slave? */
184 static sigjmp_buf jmpbuf; /* where to jump to if we are ready when the */
185 /* SIGUSR2 arrives from the previous slave */
186 #ifdef USE_QFA
187 static int gtperr = 0;
188 #endif
189
190 /*
191 * Determine if we can use Linux' clone system call. If so, call it
192 * with the CLONE_IO flag so that all processes will share the same I/O
193 * context, allowing the I/O schedulers to make better scheduling decisions.
194 */
195 #ifdef __linux__
196 /* first, pull in the header files that define sys_clone and CLONE_IO */
197 #include <syscall.h>
198 #define _GNU_SOURCE
199 #include <sched.h>
200 #include <unistd.h>
201 #undef _GNU_SOURCE
202
203 /* If either is not present, fall back on the fork behaviour */
204 #if ! defined(SYS_clone) || ! defined (CLONE_IO)
205 #define fork_clone_io fork
206 #else /* SYS_clone */
207 /* CLONE_IO is available, determine which version of sys_clone to use */
208 #include <linux/version.h>
209 /*
210 * Kernel 2.5.49 introduced two extra parameters to the clone system call.
211 * Neither is useful in our case, so this is easy to handle.
212 */
213 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,49)
214 #if __s390__
215 /* child_stack, clone_flags, parent_tidptr, child_tidptr */
216 #define CLONE_ARGS 0, SIGCHLD|CLONE_IO, NULL, NULL
217 #else
218 /* clone_flags, child_stack, parent_tidptr, child_tidptr */
219 #define CLONE_ARGS SIGCHLD|CLONE_IO, 0, NULL, NULL
220 #endif /* __s390__ */
221 #else
222 #define CLONE_ARGS SIGCHLD|CLONE_IO, 0
223 #endif /* LINUX_VERSION_CODE */
224 pid_t fork_clone_io(void);
225 #endif /* SYS_clone */
226 #else /* __linux__ not defined */
227 #define fork_clone_io fork
228 #endif /* __linux__ */
229
230 int
231 alloctape(void)
232 {
233 int pgoff = getpagesize() - 1;
234 char *buf;
235 int i;
236
237 writesize = ntrec * TP_BSIZE;
238 reqsiz = (ntrec + 1) * sizeof(struct req);
239 /*
240 * CDC 92181's and 92185's make 0.8" gaps in 1600-bpi start/stop mode
241 * (see DEC TU80 User's Guide). The shorter gaps of 6250-bpi require
242 * repositioning after stopping, i.e, streaming mode, where the gap is
243 * variable, 0.30" to 0.45". The gap is maximal when the tape stops.
244 */
245 if (!blocksperfiles && !unlimited)
246 tenths = (cartridge ? 16 : density == 625 ? 5 : 8);
247 else {
248 tenths = 0;
249 density = 1;
250 }
251 /*
252 * Allocate tape buffer contiguous with the array of instruction
253 * packets, so flushtape() can write them together with one write().
254 * Align tape buffer on page boundary to speed up tape write().
255 */
256 for (i = 0; i <= SLAVES; i++) {
257 buf = (char *)
258 malloc((unsigned)(reqsiz + writesize + pgoff + TP_BSIZE));
259 if (buf == NULL)
260 return(0);
261 slaves[i].tblock = (char (*)[TP_BSIZE])
262 #ifdef __linux__
263 (((long)&buf[reqsiz] + pgoff) &~ pgoff);
264 #else
265 (((long)&buf[ntrec + 1] + pgoff) &~ pgoff);
266 #endif
267 slaves[i].req = (struct req *)slaves[i].tblock - ntrec - 1;
268 }
269 slp = &slaves[0];
270 slp->count = 1;
271 slp->tapea = 0;
272 slp->firstrec = 0;
273 nextblock = slp->tblock;
274 return(1);
275 }
276
277 void
278 writerec(const void *dp, int isspcl)
279 {
280
281 slp->req[trecno].dblk = (ext2_loff_t)0;
282 slp->req[trecno].count = 1;
283 /* XXX post increment triggers an egcs-1.1.2-12 bug on alpha/sparc */
284 *(union u_spcl *)(*(nextblock)) = *(union u_spcl *)dp;
285
286 /* Need to write it to the archive file */
287 if (! AfileActive && isspcl && (spcl.c_type == TS_END))
288 AfileActive = 1;
289 if (AfileActive && Afile >= 0 && !(spcl.c_flags & DR_EXTATTRIBUTES)) {
290 /* When we dump an inode which is not a directory,
291 * it means we ended the archive contents */
292 if (isspcl && (spcl.c_type == TS_INODE) &&
293 ((spcl.c_dinode.di_mode & S_IFMT) != IFDIR))
294 AfileActive = 0;
295 else {
296 union u_spcl tmp;
297 tmp = *(union u_spcl *)dp;
298 /* Write the record, _uncompressed_ */
299 if (isspcl) {
300 tmp.s_spcl.c_flags &= ~DR_COMPRESSED;
301 mkchecksum(&tmp);
302 }
303 if (write(Afile, &tmp, TP_BSIZE) != TP_BSIZE)
304 msg("error writing archive file: %s\n",
305 strerror(errno));
306 }
307 }
308
309 nextblock++;
310 if (isspcl)
311 lastspclrec = spcl.c_tapea;
312 trecno++;
313 spcl.c_tapea++;
314 if (trecno >= ntrec)
315 flushtape();
316 }
317
318 void
319 dumpblock(blk_t blkno, int size)
320 {
321 int avail, tpblks;
322 ext2_loff_t dblkno;
323
324 dblkno = fsbtodb(sblock, blkno);
325 tpblks = size >> tp_bshift;
326 while ((avail = MIN(tpblks, ntrec - trecno)) > 0) {
327 slp->req[trecno].dblk = dblkno;
328 slp->req[trecno].count = avail;
329 trecno += avail;
330 spcl.c_tapea += avail;
331 if (trecno >= ntrec)
332 flushtape();
333 dblkno += avail << (tp_bshift - dev_bshift);
334 tpblks -= avail;
335 }
336 }
337
338 int nogripe = 0;
339
340 static void
341 tperror(int errnum)
342 {
343
344 if (pipeout) {
345 msg("write error on %s: %s\n", tape, strerror(errnum));
346 quit("Cannot recover\n");
347 /* NOTREACHED */
348 }
349 msg("write error %d blocks into volume %d: %s\n",
350 blocksthisvol, tapeno, strerror(errnum));
351 broadcast("DUMP WRITE ERROR!\n");
352 if (query("Do you want to rewrite this volume?")) {
353 msg("Closing this volume. Prepare to restart with new media;\n");
354 msg("this dump volume will be rewritten.\n");
355 killall();
356 nogripe = 1;
357 close_rewind();
358 Exit(X_REWRITE);
359 }
360 if (query("Do you want to start the next tape?"))
361 return;
362 dumpabort(0);
363 }
364
365 static void
366 sigpipe(UNUSED(int signo))
367 {
368
369 quit("Broken pipe\n");
370 }
371
372 /*
373 * do_stats --
374 * Update xferrate stats
375 */
376 time_t
377 do_stats(void)
378 {
379 time_t tnow, ttaken;
380 int blocks;
381
382 tnow = time(NULL);
383 ttaken = tnow - tstart_volume;
384 blocks = spcl.c_tapea - tapea_volume;
385 msg("Volume %d completed at: %s", tapeno, ctime(&tnow));
386 if (! compressed)
387 msg("Volume %d %ld blocks (%.2fMB)\n", tapeno,
388 blocks, ((double)blocks * TP_BSIZE / 1048576));
389 if (ttaken > 0) {
390 long volkb = (bytes_written - tapea_bytes) / 1024;
391 long txfrate = volkb / ttaken;
392 msg("Volume %d took %d:%02d:%02d\n", tapeno,
393 ttaken / 3600, (ttaken % 3600) / 60, ttaken % 60);
394 msg("Volume %d transfer rate: %ld kB/s\n", tapeno,
395 txfrate);
396 xferrate += txfrate;
397 if (compressed) {
398 double rate = .0005 + (double) blocks / (double) volkb;
399 msg("Volume %d %ldkB uncompressed, %ldkB compressed,"
400 " %1.3f:1\n",
401 tapeno, blocks, volkb, rate);
402 }
403 }
404 return(tnow);
405 }
406
407 char *
408 mktimeest(time_t tnow)
409 {
410 static char msgbuf[128];
411 time_t deltat;
412
413 msgbuf[0] = '\0';
414
415 if (blockswritten < 500)
416 return NULL;
417 if (blockswritten > tapesize)
418 tapesize = blockswritten;
419 deltat = tstart_writing - tnow + (1.0 * (tnow - tstart_writing))
420 / blockswritten * tapesize;
421 if (tnow > tstart_volume)
422 (void)snprintf(msgbuf, sizeof(msgbuf),
423 "%3.2f%% done at %ld kB/s, finished in %d:%02d\n",
424 (blockswritten * 100.0) / tapesize,
425 (spcl.c_tapea - tapea_volume) / (tnow - tstart_volume),
426 (int)(deltat / 3600), (int)((deltat % 3600) / 60));
427 else
428 (void)snprintf(msgbuf, sizeof(msgbuf),
429 "%3.2f%% done, finished in %d:%02d\n",
430 (blockswritten * 100.0) / tapesize,
431 (int)(deltat / 3600), (int)((deltat % 3600) / 60));
432
433 return msgbuf;
434 }
435
436 #if defined(SIGINFO)
437 /*
438 * statussig --
439 * information message upon receipt of SIGINFO
440 */
441 void
442 statussig(int notused)
443 {
444 int save_errno = errno;
445 char *buf;
446
447 buf = mktimeest(time(NULL));
448 if (buf)
449 write(STDERR_FILENO, buf, strlen(buf));
450 errno = save_errno;
451 }
452 #endif
453
454 static void
455 flushtape(void)
456 {
457 int i, blks, got;
458 long lastfirstrec;
459 struct slave_results returned;
460
461 int siz = (char *)nextblock - (char *)slp->req;
462
463 /* make sure returned has sane values in case we don't read
464 * them from the slave in this pass */
465 returned.unclen = returned.clen = writesize;
466
467 slp->req[trecno].count = 0; /* Sentinel */
468
469 if (dump_atomic_write( slp->fd, (char *)slp->req, siz) != siz)
470 quit("error writing command pipe: %s\n", strerror(errno));
471 slp->sent = 1; /* we sent a request, read the response later */
472
473 lastfirstrec = slp->firstrec;
474
475 if (++slp >= &slaves[SLAVES])
476 slp = &slaves[0];
477
478 /* Read results back from next slave */
479 if (slp->sent) {
480 if (dump_atomic_read( slp->fd, (char *)&returned, sizeof returned)
481 != sizeof returned) {
482 perror(" DUMP: error reading command pipe in master");
483 dumpabort(0);
484 }
485 got = returned.unclen;
486 bytes_written += returned.clen;
487 if (returned.unclen == returned.clen)
488 uncomprblks++;
489 slp->sent = 0;
490
491 /* Check for errors or end of tape */
492 if (got <= 0) {
493 /* Check for errors */
494 if (got < 0)
495 tperror(-got);
496 else
497 msg("End of tape detected\n");
498
499 /*
500 * Drain the results, don't care what the values were.
501 * If we read them here then trewind won't...
502 */
503 for (i = 0; i < SLAVES; i++) {
504 if (slaves[i].sent) {
505 if (dump_atomic_read( slaves[i].fd,
506 (char *)&returned, sizeof returned)
507 != sizeof returned) {
508 perror(" DUMP: error reading command pipe in master");
509 dumpabort(0);
510 }
511 slaves[i].sent = 0;
512 }
513 }
514
515 close_rewind();
516 rollforward();
517 return;
518 }
519 }
520
521 blks = 0;
522 if (spcl.c_type == TS_CLRI || spcl.c_type == TS_BITS)
523 blks = spcl.c_count;
524 else {
525 if (spcl.c_type != TS_END) {
526 for (i = 0; i < spcl.c_count; i++)
527 if (spcl.c_addr[i] != 0)
528 blks++;
529 }
530 }
531 slp->count = lastspclrec + blks + 1 - spcl.c_tapea;
532 slp->tapea = spcl.c_tapea;
533 slp->firstrec = lastfirstrec + ntrec;
534 slp->inode = curino;
535 nextblock = slp->tblock;
536 trecno = 0;
537 asize += tenths + returned.clen / density;
538 blockswritten += ntrec;
539 blocksthisvol += ntrec;
540 if (!pipeout && !unlimited) {
541 if (blocksperfiles && blocksperfiles[blocksperfiles_current]) {
542 if ( compressed ? (bytes_written - tapea_bytes + SLAVES * (writesize + sizeof(struct tapebuf))) >= (((long long)blocksperfiles[blocksperfiles_current]) * 1024)
543 : blocksthisvol >= blocksperfiles[blocksperfiles_current] ) {
544 close_rewind();
545 startnewtape(0);
546 }
547 }
548 else if (asize > tsize) {
549 close_rewind();
550 startnewtape(0);
551 }
552 }
553 timeest();
554 }
555
556 time_t
557 trewind(void)
558 {
559 int f;
560 int got;
561 struct slave_results returned;
562
563 for (f = 0; f < SLAVES; f++) {
564 /*
565 * Drain the results, but unlike EOT we DO (or should) care
566 * what the return values were, since if we detect EOT after
567 * we think we've written the last blocks to the tape anyway,
568 * we have to replay those blocks with rollforward.
569 *
570 * fixme: punt for now.
571 */
572 if (slaves[f].sent) {
573 if (dump_atomic_read( slaves[f].fd, (char *)&returned, sizeof returned)
574 != sizeof returned) {
575 perror(" DUMP: error reading command pipe in master");
576 dumpabort(0);
577 }
578 got = returned.unclen;
579 bytes_written += returned.clen;
580 if (returned.unclen == returned.clen)
581 uncomprblks++;
582 slaves[f].sent = 0;
583
584 if (got < 0)
585 tperror(-got);
586
587 if (got == 0) {
588 msg("EOT detected in last 2 tape records!\n");
589 msg("Use a longer tape, decrease the size estimate\n");
590 quit("or use no size estimate at all.\n");
591 }
592 }
593 (void) close(slaves[f].fd);
594 }
595 while (wait((int *)NULL) >= 0) /* wait for any signals from slaves */
596 /* void */;
597
598 if (!pipeout) {
599
600 msg("Closing %s\n", tape);
601
602 #ifdef RDUMP
603 if (host) {
604 rmtclose();
605 while (rmtopen(tape, O_RDONLY) < 0)
606 sleep(10);
607 rmtclose();
608 }
609 else
610 #endif
611 {
612 (void) close(tapefd);
613 if (!fifoout) {
614 while ((f = OPEN(tape, O_RDONLY)) < 0)
615 sleep (10);
616 (void) close(f);
617 }
618 }
619 }
620 return do_stats();
621 }
622
623
624 void
625 close_rewind(void)
626 {
627 int eot_code = 1;
628 (void)trewind();
629 if (eot_script) {
630 msg("Launching %s\n", eot_script);
631 eot_code = system_command(eot_script, tape, tapeno);
632 }
633 if (eot_code != 0 && eot_code != 1) {
634 msg("Dump aborted by the end of tape script\n");
635 dumpabort(0);
636 }
637 if (eot_code == 0)
638 return;
639 if (nexttape || Mflag)
640 return;
641 if (!nogripe) {
642 msg("Change Volumes: Mount volume #%d\n", tapeno+1);
643 broadcast("CHANGE DUMP VOLUMES!\7\7\n");
644 }
645 while (!query("Is the new volume mounted and ready to go?"))
646 if (query("Do you want to abort?")) {
647 dumpabort(0);
648 /*NOTREACHED*/
649 }
650 }
651
652 void
653 rollforward(void)
654 {
655 struct req *p, *q = NULL, *prev;
656 struct slave *tslp;
657 int i, size, savedtapea, got;
658 union u_spcl *ntb, *otb;
659 struct slave_results returned;
660 #ifdef __linux__
661 int blks;
662 long lastfirstrec;
663 #endif
664 tslp = &slaves[SLAVES];
665 ntb = (union u_spcl *)tslp->tblock[1];
666
667 /* make sure returned has sane values in case we don't read
668 * them from the slave in this pass */
669 returned.unclen = returned.clen = writesize;
670
671 /*
672 * Each of the N slaves should have requests that need to
673 * be replayed on the next tape. Use the extra slave buffers
674 * (slaves[SLAVES]) to construct request lists to be sent to
675 * each slave in turn.
676 */
677 for (i = 0; i < SLAVES; i++) {
678 q = &tslp->req[1];
679 otb = (union u_spcl *)slp->tblock;
680
681 /*
682 * For each request in the current slave, copy it to tslp.
683 */
684
685 prev = NULL;
686 for (p = slp->req; p->count > 0; p += p->count) {
687 *q = *p;
688 if (p->dblk == 0)
689 *ntb++ = *otb++; /* copy the datablock also */
690 prev = q;
691 q += q->count;
692 }
693 if (prev == NULL)
694 quit("rollforward: protocol botch");
695 if (prev->dblk != 0)
696 prev->count -= 1;
697 else
698 ntb--;
699 q -= 1;
700 q->count = 0;
701 q = &tslp->req[0];
702 if (i == 0) {
703 q->dblk = 0;
704 q->count = 1;
705 trecno = 0;
706 nextblock = tslp->tblock;
707 savedtapea = spcl.c_tapea;
708 spcl.c_tapea = slp->tapea;
709 startnewtape(0);
710 spcl.c_tapea = savedtapea;
711 lastspclrec = savedtapea - 1;
712 }
713 size = (char *)ntb - (char *)q;
714 if (dump_atomic_write( slp->fd, (char *)q, size) != size) {
715 perror(" DUMP: error writing command pipe");
716 dumpabort(0);
717 }
718 slp->sent = 1;
719 #ifdef __linux__
720 lastfirstrec = slp->firstrec;
721 #endif
722 if (++slp >= &slaves[SLAVES])
723 slp = &slaves[0];
724
725 q->count = 1;
726
727 if (prev->dblk != 0) {
728 /*
729 * If the last one was a disk block, make the
730 * first of this one be the last bit of that disk
731 * block...
732 */
733 q->dblk = prev->dblk +
734 prev->count * (TP_BSIZE / DEV_BSIZE);
735 ntb = (union u_spcl *)tslp->tblock;
736 } else {
737 /*
738 * It wasn't a disk block. Copy the data to its
739 * new location in the buffer.
740 */
741 q->dblk = 0;
742 *((union u_spcl *)tslp->tblock) = *ntb;
743 ntb = (union u_spcl *)tslp->tblock[1];
744 }
745 }
746 slp->req[0] = *q;
747 nextblock = slp->tblock;
748 if (q->dblk == 0) {
749 #ifdef __linux__
750 /* XXX post increment triggers an egcs-1.1.2-12 bug on alpha/sparc */
751 *(union u_spcl *)(*nextblock) = *(union u_spcl *)tslp->tblock;
752 #endif
753 nextblock++;
754 }
755 trecno = 1;
756
757 /*
758 * Clear the first slaves' response. One hopes that it
759 * worked ok, otherwise the tape is much too short!
760 */
761 if (slp->sent) {
762 if (dump_atomic_read( slp->fd, (char *)&returned, sizeof returned)
763 != sizeof returned) {
764 perror(" DUMP: error reading command pipe in master");
765 dumpabort(0);
766 }
767 got = returned.unclen;
768 bytes_written += returned.clen;
769 if (returned.clen == returned.unclen)
770 uncomprblks++;
771 slp->sent = 0;
772
773 if (got < 0)
774 tperror(-got);
775
776 if (got == 0) {
777 quit("EOT detected at start of the tape!\n");
778 }
779 }
780
781 #ifdef __linux__
782 blks = 0;
783 if (spcl.c_type != TS_END) {
784 for (i = 0; i < spcl.c_count; i++)
785 if (spcl.c_addr[i] != 0)
786 blks++;
787 }
788
789 slp->firstrec = lastfirstrec + ntrec;
790 slp->count = lastspclrec + blks + 1 - spcl.c_tapea;
791 slp->inode = curino;
792 asize += tenths + returned.clen / density;
793 blockswritten += ntrec;
794 blocksthisvol += ntrec;
795 #endif
796 }
797
798 #ifdef __linux__
799 #if defined(SYS_clone) && defined(CLONE_IO)
800 pid_t
801 fork_clone_io(void)
802 {
803 return syscall(SYS_clone, CLONE_ARGS);
804 }
805 #endif
806 #endif
807
808 /*
809 * We implement taking and restoring checkpoints on the tape level.
810 * When each tape is opened, a new process is created by forking; this
811 * saves all of the necessary context in the parent. The child
812 * continues the dump; the parent waits around, saving the context.
813 * If the child returns X_REWRITE, then it had problems writing that tape;
814 * this causes the parent to fork again, duplicating the context, and
815 * everything continues as if nothing had happened.
816 */
817 void
818 startnewtape(int top)
819 {
820 int parentpid;
821 int childpid;
822 int status;
823 int waitpid;
824 char *p;
825
826 #ifdef __linux__
827 sigset_t sigs;
828 sigemptyset(&sigs);
829 sigaddset(&sigs, SIGINT);
830 sigprocmask(SIG_BLOCK, &sigs, NULL);
831 #else /* __linux__ */
832 #ifdef sunos
833 void (*interrupt_save)();
834 #else
835 sig_t interrupt_save;
836 #endif
837 interrupt_save = signal(SIGINT, SIG_IGN);
838 #endif /* __linux__ */
839
840 parentpid = getpid();
841 tapea_volume = spcl.c_tapea;
842 tapea_bytes = bytes_written;
843 tstart_volume = time(NULL);
844
845 restore_check_point:
846 #ifdef __linux__
847 sigprocmask(SIG_UNBLOCK, &sigs, NULL);
848 #else
849 (void)signal(SIGINT, interrupt_save);
850 #endif
851 /*
852 * All signals are inherited...
853 */
854 childpid = fork_clone_io();
855 if (childpid < 0) {
856 msg("Context save fork fails in parent %d\n", parentpid);
857 Exit(X_ABORT);
858 }
859 if (childpid != 0) {
860 /*
861 * PARENT:
862 * save the context by waiting
863 * until the child doing all of the work returns.
864 * don't catch the interrupt
865 */
866 #ifdef __linux__
867 sigprocmask(SIG_BLOCK, &sigs, NULL);
868 #else
869 signal(SIGINT, SIG_IGN);
870 #endif
871 #ifdef TDEBUG
872 msg("Tape: %d; parent process: %d child process %d\n",
873 tapeno+1, parentpid, childpid);
874 #endif /* TDEBUG */
875 while ((waitpid = wait(&status)) != childpid)
876 if (waitpid != rshpid)
877 msg("Parent %d waiting for child %d has another child %d return\n",
878 parentpid, childpid, waitpid);
879 if (status & 0xFF) {
880 msg("Child %d returns LOB status %o\n",
881 childpid, status&0xFF);
882 }
883 status = (status >> 8) & 0xFF;
884 #ifdef TDEBUG
885 switch(status) {
886 case X_FINOK:
887 msg("Child %d finishes X_FINOK\n", childpid);
888 break;
889 case X_ABORT:
890 msg("Child %d finishes X_ABORT\n", childpid);
891 break;
892 case X_REWRITE:
893 msg("Child %d finishes X_REWRITE\n", childpid);
894 break;
895 default:
896 msg("Child %d finishes unknown %d\n",
897 childpid, status);
898 break;
899 }
900 #endif /* TDEBUG */
901 switch(status) {
902 case X_FINOK:
903 Exit(X_FINOK);
904 case X_ABORT:
905 Exit(X_ABORT);
906 case X_REWRITE:
907 goto restore_check_point;
908 default:
909 msg("Bad return code from dump: %d\n", status);
910 Exit(X_ABORT);
911 }
912 /*NOTREACHED*/
913 } else { /* we are the child; just continue */
914 #ifdef TDEBUG
915 sleep(4); /* allow time for parent's message to get out */
916 msg("Child on Tape %d has parent %d, my pid = %d\n",
917 tapeno+1, parentpid, getpid());
918 #endif /* TDEBUG */
919 /*
920 * If we have a name like "/dev/rmt0,/dev/rmt1",
921 * use the name before the comma first, and save
922 * the remaining names for subsequent volumes.
923 */
924 tapeno++; /* current tape sequence */
925 if (Mflag) {
926 snprintf(tape, MAXPATHLEN, "%s%03d", tapeprefix, tapeno);
927 tape[MAXPATHLEN - 1] = '\0';
928 msg("Dumping volume %d on %s\n", tapeno, tape);
929 }
930 else if (nexttape || strchr(tapeprefix, ',')) {
931 if (nexttape && *nexttape)
932 tapeprefix = nexttape;
933 if ((p = strchr(tapeprefix, ',')) != NULL) {
934 *p = '\0';
935 nexttape = p + 1;
936 } else
937 nexttape = NULL;
938 strncpy(tape, tapeprefix, MAXPATHLEN);
939 tape[MAXPATHLEN - 1] = '\0';
940 msg("Dumping volume %d on %s\n", tapeno, tape);
941 }
942 if (blocksperfiles && blocksperfiles_current < *blocksperfiles)
943 blocksperfiles_current++;
944 #ifdef RDUMP
945 while ((tapefd = (host ? rmtopen(tape, O_WRONLY|O_CREAT|O_TRUNC) : pipeout ?
946 fileno(stdout) :
947 OPEN(tape, O_WRONLY|O_CREAT|O_TRUNC, 0666))) < 0)
948 #else
949 while ((tapefd = (pipeout ? fileno(stdout) :
950 OPEN(tape, O_WRONLY|O_CREAT|O_TRUNC, 0666))) < 0)
951 #endif
952 {
953 msg("Cannot open output \"%s\": %s\n", tape,
954 strerror(errno));
955 if (!query("Do you want to retry the open?"))
956 dumpabort(0);
957 }
958 #ifdef RDUMP
959 if (!host)
960 #endif
961 {
962 struct mtget mt_stat;
963 magtapeout = ioctl(tapefd, MTIOCGET, (char *)&mt_stat) == 0;
964 /*
965 msg("Output is to %s\n",
966 magtapeout ? "tape" : "file/pipe");
967 */
968 }
969
970 enslave(); /* Share open tape file descriptor with slaves */
971
972 asize = 0;
973 blocksthisvol = 0;
974 if (top)
975 newtape++; /* new tape signal */
976 spcl.c_count = slp->count;
977 /*
978 * measure firstrec in TP_BSIZE units since restore doesn't
979 * know the correct ntrec value...
980 */
981 spcl.c_firstrec = slp->firstrec;
982 spcl.c_volume++;
983 spcl.c_type = TS_TAPE;
984 spcl.c_flags |= DR_NEWHEADER;
985 spcl.c_ntrec = ntrec;
986 if (compressed)
987 spcl.c_flags |= DR_COMPRESSED;
988 writeheader((dump_ino_t)slp->inode);
989 spcl.c_flags &=~ DR_NEWHEADER;
990 msg("Volume %d started with block %ld at: %s", tapeno,
991 spcl.c_tapea, ctime(&tstart_volume));
992 if (tapeno > 1)
993 msg("Volume %d begins with blocks from inode %d\n",
994 tapeno, slp->inode);
995 if (tapeno < (int)TP_NINOS)
996 volinfo[tapeno] = slp->inode;
997 }
998 }
999
1000 void
1001 dumpabort(UNUSED(int signo))
1002 {
1003
1004 if (master != 0 && master != getpid())
1005 /* Signals master to call dumpabort */
1006 (void) kill(master, SIGTERM);
1007 else {
1008 killall();
1009 msg("The ENTIRE dump is aborted.\n");
1010 }
1011 #ifdef RDUMP
1012 rmtclose();
1013 #endif
1014 Exit(X_ABORT);
1015 }
1016
1017 void
1018 Exit(int status)
1019 {
1020
1021 #ifdef TDEBUG
1022 msg("pid = %d exits with status %d\n", getpid(), status);
1023 #endif /* TDEBUG */
1024 exit(status);
1025 }
1026
1027 /*
1028 * proceed - handler for SIGUSR2, used to synchronize IO between the slaves.
1029 */
1030 static void
1031 proceed(UNUSED(int signo))
1032 {
1033 if (ready)
1034 siglongjmp(jmpbuf, 1);
1035 caught++;
1036 }
1037
1038 void
1039 enslave(void)
1040 {
1041 int cmd[2];
1042 #ifdef LINUX_FORK_BUG
1043 int i, j;
1044 #else
1045 int i, j;
1046 #endif
1047
1048 master = getpid();
1049
1050 { struct sigaction sa;
1051 memset(&sa, 0, sizeof sa);
1052 sigemptyset(&sa.sa_mask);
1053 sa.sa_handler = dumpabort;
1054 sigaction(SIGTERM, &sa, NULL); /* Slave sends SIGTERM on dumpabort() */
1055 sa.sa_handler = sigpipe;
1056 sigaction(SIGPIPE, &sa, NULL);
1057 sa.sa_handler = proceed;
1058 sa.sa_flags = SA_RESTART;
1059 sigaction(SIGUSR2, &sa, NULL); /* Slave sends SIGUSR2 to next slave */
1060 }
1061
1062 for (i = 0; i < SLAVES; i++) {
1063 if (i == slp - &slaves[0]) {
1064 caught = 1;
1065 } else {
1066 caught = 0;
1067 }
1068
1069 if (socketpair(AF_UNIX, SOCK_STREAM, 0, cmd) < 0 ||
1070 (slaves[i].pid = fork_clone_io()) < 0)
1071 quit("too many slaves, %d (recompile smaller): %s\n",
1072 i, strerror(errno));
1073
1074 slaves[i].fd = cmd[1];
1075 slaves[i].sent = 0;
1076 if (slaves[i].pid == 0) { /* Slave starts up here */
1077 sigset_t sigs;
1078 for (j = 0; j <= i; j++)
1079 (void) close(slaves[j].fd);
1080 sigemptyset(&sigs);
1081 sigaddset(&sigs, SIGINT); /* Master handles this */
1082 #if defined(SIGINFO)
1083 sigaddset(&sigs, SIGINFO);
1084 #endif
1085 sigprocmask(SIG_BLOCK, &sigs, NULL);
1086
1087 #ifdef LINUX_FORK_BUG
1088 if (dump_atomic_write( cmd[0], (char *) &i, sizeof i)
1089 != sizeof i)
1090 quit("master/slave protocol botched 3\n");
1091 #endif
1092 doslave(cmd[0],
1093 #ifdef WRITEDEBUG
1094 i,
1095 #endif
1096 (slaves[i].pid == slp->pid));
1097 Exit(X_FINOK);
1098 }
1099 else
1100 close(cmd[0]);
1101 }
1102
1103 #ifdef LINUX_FORK_BUG
1104 /*
1105 * Wait for all slaves to _actually_ start to circumvent a bug in
1106 * Linux kernels >= 2.1.3 where a signal sent to a child that hasn't
1107 * returned from fork() causes a SEGV in the child process
1108 */
1109 for (i = 0; i < SLAVES; i++)
1110 if (dump_atomic_read( slaves[i].fd, (char *) &j, sizeof j) != sizeof j)
1111 quit("master/slave protocol botched 4\n");
1112 #endif
1113
1114 for (i = 0; i < SLAVES; i++)
1115 (void) dump_atomic_write( slaves[i].fd,
1116 (char *) &slaves[(i + 1) % SLAVES].pid,
1117 sizeof slaves[0].pid);
1118
1119 master = 0;
1120 }
1121
1122 void
1123 killall(void)
1124 {
1125 int i;
1126
1127 for (i = 0; i < SLAVES; i++)
1128 if (slaves[i].pid > 0) {
1129 (void) kill(slaves[i].pid, SIGKILL);
1130 slaves[i].sent = 0;
1131 }
1132 }
1133
1134 /*
1135 * Synchronization - each process waits for a SIGUSR2 from the
1136 * previous process before writing to the tape, and sends SIGUSR2
1137 * to the next process when the tape write completes. On tape errors
1138 * a SIGUSR1 is sent to the master which then terminates all of the
1139 * slaves.
1140 */
1141 static void
1142 doslave(int cmd,
1143 #ifdef WRITEDEBUG
1144 int slave_number,
1145 #endif
1146 int first)
1147 {
1148 int nread;
1149 int nextslave;
1150 volatile int wrote = 0, size, eot_count, bufsize;
1151 char * volatile buffer;
1152 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO)
1153 struct tapebuf * volatile comp_buf = NULL;
1154 int compresult;
1155 volatile int do_compress = !first;
1156 unsigned long worklen;
1157 #ifdef HAVE_LZO
1158 lzo_align_t __LZO_MMODEL *LZO_WorkMem;
1159 #endif
1160 #endif /* HAVE_ZLIB || HAVE_BZLIB || HAVE_LZO */
1161 struct slave_results returns;
1162 #ifdef __linux__
1163 errcode_t retval;
1164 #endif
1165 #ifdef USE_QFA
1166 long long curtapepos;
1167 union u_spcl *uspclptr;
1168 struct s_spcl *spclptr;
1169 /* long maxntrecs = 300000000 / (ntrec * 1024); last tested: 50 000 000 */
1170 long maxntrecs = 50000; /* every 50MB */
1171 long cntntrecs = maxntrecs;
1172 #endif /* USE_QFA */
1173 sigset_t set;
1174
1175 sigemptyset(&set);
1176 sigaddset(&set, SIGUSR2);
1177 sigprocmask(SIG_BLOCK, &set, NULL);
1178 sigemptyset(&set);
1179
1180 /*
1181 * Need our own seek pointer.
1182 */
1183 (void) close(diskfd);
1184 if ((diskfd = OPEN(disk, O_RDONLY)) < 0)
1185 quit("slave couldn't reopen disk: %s\n", strerror(errno));
1186 #ifdef __linux__
1187 #ifdef BLKFLSBUF
1188 (void)ioctl(diskfd, BLKFLSBUF, 0);
1189 #endif
1190 ext2fs_close(fs);
1191 retval = dump_fs_open(disk, &fs);
1192 if (retval)
1193 quit("slave couldn't reopen disk: %s\n", error_message(retval));
1194 #endif /* __linux__ */
1195
1196 /*
1197 * Need the pid of the next slave in the loop...
1198 */
1199 if ((nread = dump_atomic_read( cmd, (char *)&nextslave, sizeof nextslave))
1200 != sizeof nextslave) {
1201 quit("master/slave protocol botched - didn't get pid of next slave.\n");
1202 }
1203
1204 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO)
1205 /* if we're doing a compressed dump, allocate the compress buffer */
1206 if (compressed) {
1207 int bsiz = sizeof(struct tapebuf) + writesize;
1208 /* Add extra space to deal with compression enlarging the buffer */
1209 if (TP_BSIZE > writesize/16 + 67)
1210 bsiz += TP_BSIZE;
1211 else
1212 bsiz += writesize/16 + 67;
1213 comp_buf = malloc(bsiz);
1214 if (comp_buf == NULL)
1215 quit("couldn't allocate a compress buffer.\n");
1216 if (zipflag == COMPRESS_ZLIB)
1217 comp_buf->flags = COMPRESS_ZLIB;
1218 else if (zipflag == COMPRESS_BZLIB)
1219 comp_buf->flags = COMPRESS_BZLIB;
1220 else if (zipflag == COMPRESS_LZO) {
1221 comp_buf->flags = COMPRESS_LZO;
1222 if (lzo_init() != LZO_E_OK) quit("lzo_init failed\n");
1223 } else
1224 quit("internal error - unknown compression method: %d\n", zipflag);
1225 }
1226 #ifdef HAVE_LZO
1227 LZO_WorkMem = malloc(LZO1X_1_MEM_COMPRESS);
1228 if (!LZO_WorkMem)
1229 quit("couldn't allocate a compress buffer.\n");
1230 #endif
1231 #endif /* HAVE_ZLIB || HAVE_BZLIB || HAVE_LZO */
1232
1233 /*
1234 * Get list of blocks to dump, read the blocks into tape buffer
1235 */
1236 while ((nread = dump_atomic_read( cmd, (char *)slp->req, reqsiz)) == reqsiz) {
1237 struct req *p = slp->req;
1238
1239 for (trecno = 0; trecno < ntrec;
1240 trecno += p->count, p += p->count) {
1241 if (p->dblk) { /* read a disk block */
1242 bread(p->dblk, slp->tblock[trecno],
1243 p->count * TP_BSIZE);
1244 } else { /* read record from pipe */
1245 if (p->count != 1 || dump_atomic_read( cmd,
1246 (char *)slp->tblock[trecno],
1247 TP_BSIZE) != TP_BSIZE)
1248 quit("master/slave protocol botched.\n");
1249 }
1250 }
1251
1252 /* Try to write the data... */
1253 wrote = 0;
1254 eot_count = 0;
1255 size = 0;
1256 buffer = (char *) slp->tblock[0]; /* set write pointer */
1257 bufsize = writesize; /* length to write */
1258 returns.clen = returns.unclen = bufsize;
1259
1260 #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO)
1261 /*
1262 * When writing a compressed dump, each block except
1263 * the first one on each tape is written
1264 * from struct tapebuf with an 4 byte prefix
1265 * followed by the data. This can be less than
1266 * writesize. Restore, on a short read, can compare the
1267 * length read to the compressed length in the header
1268 * to verify that the read was good. Blocks which don't
1269 * compress well are written uncompressed.
1270 * The first block written by each slave is not compressed
1271 * and does not have a prefix.
1272 */
1273
1274 if (compressed && do_compress) {
1275 comp_buf->length = bufsize;
1276 worklen = TP_BSIZE + writesize;
1277 compresult = 1;
1278 #ifdef HAVE_ZLIB
1279 if (zipflag == COMPRESS_ZLIB) {
1280 compresult = compress2(comp_buf->buf,
1281 &worklen,
1282 (char *)slp->tblock[0],
1283 writesize,
1284 compressed);
1285 if (compresult == Z_OK)
1286 compresult = 1;
1287 else
1288 compresult = 0;
1289 }
1290 #endif /* HAVE_ZLIB */
1291 #ifdef HAVE_BZLIB
1292 if (zipflag == COMPRESS_BZLIB) {
1293 unsigned int worklen2 = worklen;
1294 compresult = BZ2_bzBuffToBuffCompress(
1295 comp_buf->buf,
1296 &worklen2,
1297 (char *)slp->tblock[0],
1298 writesize,
1299 compressed,
1300 0, 30);
1301 worklen = worklen2;
1302 if (compresult == BZ_OK)
1303 compresult = 1;
1304 else
1305 compresult = 0;
1306 }
1307
1308 #endif /* HAVE_BZLIB */
1309 #ifdef HAVE_LZO
1310 if (zipflag == COMPRESS_LZO) {
1311 lzo_uint worklen2 = worklen;
1312 compresult = lzo1x_1_compress((char *)slp->tblock[0],writesize,
1313 comp_buf->buf,
1314 &worklen2,
1315 LZO_WorkMem);
1316 worklen = worklen2;
1317 if (compresult == LZO_E_OK)
1318 compresult = 1;
1319 else
1320 compresult = 0;
1321 }
1322 #endif /* HAVE_LZO */
1323 if (compresult && worklen <= ((unsigned long)writesize - 16)) {
1324 /* write the compressed buffer */
1325 comp_buf->length = worklen;
1326 comp_buf->compressed = 1;
1327 buffer = (char *) comp_buf;
1328 returns.clen = bufsize = worklen + sizeof(struct tapebuf);
1329 }
1330 else {
1331 /* write the data uncompressed */
1332 comp_buf->length = writesize;
1333 comp_buf->compressed = 0;
1334 buffer = (char *) comp_buf;
1335 returns.clen = bufsize = writesize + sizeof(struct tapebuf);
1336 returns.unclen = returns.clen;
1337 memcpy(comp_buf->buf, (char *)slp->tblock[0], writesize);
1338 }
1339 }
1340 /* compress the remaining blocks if we're compressing */
1341 do_compress = compressed;
1342 #endif /* HAVE_ZLIB || HAVE_BZLIB || HAVE_LZO */
1343
1344 if (sigsetjmp(jmpbuf, 1) == 0) {
1345 ready = 1;
1346 if (!caught)
1347 sigsuspend(&set);
1348 }
1349 ready = 0;
1350 caught = 0;
1351
1352 #ifdef USE_QFA
1353 if (gTapeposfd >= 0) {
1354 int i;
1355 int foundone = 0;
1356
1357 for (i = 0; (i < ntrec) && !foundone; ++i) {
1358 uspclptr = (union u_spcl *)&slp->tblock[i];
1359 spclptr = &uspclptr->s_spcl;
1360 if ((spclptr->c_magic == NFS_MAGIC) &&
1361 (spclptr->c_type == TS_INODE) &&
1362 (spclptr->c_date == gThisDumpDate) &&
1363 !(spclptr->c_dinode.di_mode & S_IFDIR) &&
1364 !(spclptr->c_flags & DR_EXTATTRIBUTES)
1365 ) {
1366 foundone = 1;
1367 /* if (cntntrecs >= maxntrecs) { only write every maxntrecs amount of data */
1368 cntntrecs = 0;
1369 if (gtperr == 0)
1370 gtperr = GetTapePos(&curtapepos);
1371 /* if an error occured previously don't
1372 * try again */
1373 if (gtperr == 0) {
1374 #ifdef DEBUG_QFA
1375 msg("inode %ld at tapepos %ld\n", spclptr->c_inumber, curtapepos);
1376 #endif
1377 gtperr = MkTapeString(spclptr, curtapepos);
1378 }
1379 /* } */
1380 }
1381 }
1382 }
1383 #endif /* USE_QFA */
1384
1385 while (eot_count < 10 && size < bufsize) {
1386 #ifdef RDUMP
1387 if (host)
1388 wrote = rmtwrite(buffer + size, bufsize - size);
1389 else
1390 #endif
1391 wrote = write(tapefd, buffer + size, bufsize - size);
1392 #ifdef WRITEDEBUG
1393 printf("slave %d wrote %d\n", slave_number, wrote);
1394 #endif
1395 if (wrote < 0 && errno != ENOSPC)
1396 break;
1397 if (wrote == 0 || (wrote < 0 && errno == ENOSPC))
1398 eot_count++;
1399 else
1400 size += wrote;
1401 }
1402
1403 #ifdef WRITEDEBUG
1404 if (size != bufsize)
1405 printf("slave %d only wrote %d out of %d bytes and gave up.\n",
1406 slave_number, size, bufsize);
1407 #endif
1408
1409 /*
1410 * Handle ENOSPC as an EOT condition.
1411 */
1412 if (wrote < 0 && errno == ENOSPC) {
1413 wrote = 0;
1414 eot_count++;
1415 }
1416
1417 if (eot_count > 0)
1418 returns.clen = returns.unclen = 0;
1419
1420 /*
1421 * pass errno back to master for special handling
1422 */
1423 if (wrote < 0)
1424 returns.unclen = -errno;
1425
1426 /*
1427 * pass size of data and size of write back to master
1428 * (for EOT handling)
1429 */
1430 (void) dump_atomic_write( cmd, (char *)&returns, sizeof returns);
1431
1432 /*
1433 * Signal the next slave to go.
1434 */
1435 (void) kill(nextslave, SIGUSR2);
1436 #ifdef USE_QFA
1437 if (gTapeposfd >= 0) {
1438 cntntrecs += ntrec;
1439 }
1440 #endif /* USE_QFA */
1441 }
1442 if (nread != 0)
1443 quit("error reading command pipe: %s\n", strerror(errno));
1444 }
1445
1446 /*
1447 * Since a read from a pipe may not return all we asked for,
1448 * or a write may not write all we ask if we get a signal,
1449 * loop until the count is satisfied (or error).
1450 */
1451 static ssize_t
1452 dump_atomic_read(int fd, char *buf, size_t count)
1453 {
1454 int got, need = count;
1455
1456 do {
1457 while ((got = read(fd, buf, need)) > 0 && (need -= got) > 0)
1458 buf += got;
1459 } while (got == -1 && errno == EINTR);
1460 return (got < 0 ? got : (ssize_t)count - need);
1461 }
1462
1463 /*
1464 * Since a read from a pipe may not return all we asked for,
1465 * or a write may not write all we ask if we get a signal,
1466 * loop until the count is satisfied (or error).
1467 */
1468 static ssize_t
1469 dump_atomic_write(int fd, const char *buf, size_t count)
1470 {
1471 int got, need = count;
1472
1473 do {
1474 while ((got = write(fd, buf, need)) > 0 && (need -= got) > 0)
1475 buf += got;
1476 } while (got == -1 && errno == EINTR);
1477 return (got < 0 ? got : (ssize_t)count - need);
1478 }
1479
1480
1481 /*
1482 int
1483 SetLogicalPos(void)
1484 {
1485 int err = 0;
1486 struct mt_pos buf;
1487
1488 buf.mt_op = MTSETDRVBUFFER;
1489 buf.mt_count = MT_ST_BOOLEANS | MT_ST_SCSI2LOGICAL;
1490 if (ioctl(tapefd, MTIOCTOP, &buf) == -1) {
1491 err = errno;
1492 msg("[%ld] error: %d (setting logical)\n",
1493 (unsigned long)getpid(), err);
1494 }
1495 return err;
1496 }
1497 */
1498
1499 #ifdef USE_QFA
1500 #define LSEEK_GET_TAPEPOS 10
1501 #define LSEEK_GO2_TAPEPOS 11
1502 /*
1503 * read the current tape position
1504 */
1505 static int
1506 GetTapePos(long long *pos)
1507 {
1508 int err = 0;
1509
1510 #ifdef RDUMP
1511 if (host) {
1512 *pos = (long long) rmtseek((OFF_T)0, (int)LSEEK_GET_TAPEPOS);
1513 err = *pos < 0;
1514 }
1515 else
1516 #endif
1517 {
1518 if (magtapeout) {
1519 long mtpos;
1520 *pos = 0;
1521 err = (ioctl(tapefd, MTIOCPOS, &mtpos) < 0);
1522 *pos = (long long)mtpos;
1523 }
1524 else {
1525 *pos = LSEEK(tapefd, 0, SEEK_CUR);
1526 err = (*pos < 0);
1527 }
1528 }
1529 if (err) {
1530 err = errno;
1531 msg("[%ld] error: %d (getting tapepos: %lld)\n", getpid(),
1532 err, *pos);
1533 return err;
1534 }
1535 return err;
1536 }
1537
1538 static int
1539 MkTapeString(struct s_spcl *spclptr, long long curtapepos)
1540 {
1541 int err = 0;
1542
1543 #ifdef DEBUG_QFA
1544 msg("inode %ld at tapepos %lld\n", spclptr->c_inumber, curtapepos);
1545 #endif
1546
1547 snprintf(gTps, sizeof(gTps), "%ld\t%d\t%lld\n",
1548 (unsigned long)spclptr->c_inumber,
1549 tapeno,
1550 curtapepos);
1551 gTps[sizeof(gTps) - 1] = '\0';
1552 if (write(gTapeposfd, gTps, strlen(gTps)) != (ssize_t)strlen(gTps)) {
1553 err = errno;
1554 warn("error writing tapepos file. (error %d)\n", errno);
1555 }
1556 return err;
1557 }
1558 #endif /* USE_QFA */