]> git.wh0rd.org - dump.git/blob - dump/tape.c
Another set of cleanups from Andreas.
[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 <pop@noos.fr>, 1999-2000
6 * Stelian Pop <pop@noos.fr> - AlcĂ´ve <www.alcove.fr>, 2000
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. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
40 */
41
42 #ifndef lint
43 static const char rcsid[] =
44 "$Id: tape.c,v 1.39 2001/03/23 14:40:12 stelian Exp $";
45 #endif /* not lint */
46
47 #include <config.h>
48 #include <errno.h>
49 #include <fcntl.h>
50 #include <setjmp.h>
51 #include <signal.h>
52 #include <stdio.h>
53 #include <compaterr.h>
54 #ifdef __STDC__
55 #include <stdlib.h>
56 #include <string.h>
57 #include <unistd.h>
58 #else
59 int write(), read();
60 #endif
61
62 #ifdef __linux__
63 #include <sys/types.h>
64 #include <time.h>
65 #include <linux/types.h>
66 #endif
67 #include <sys/param.h>
68 #include <sys/socket.h>
69 #include <sys/time.h>
70 #include <sys/wait.h>
71 #ifdef __linux__
72 #include <linux/ext2_fs.h>
73 #include <ext2fs/ext2fs.h>
74 #include <bsdcompat.h>
75 #elif defined sunos
76 #include <sys/vnode.h>
77
78 #include <ufs/fs.h>
79 #include <ufs/inode.h>
80 #else
81 #include <ufs/ufs/dinode.h>
82 #include <ufs/ffs/fs.h>
83 #endif /* __linux__ */
84
85 #include <protocols/dumprestore.h>
86
87 #ifdef HAVE_ZLIB
88 #include <zlib.h>
89 #endif /* HAVE_ZLIB */
90
91 #include "dump.h"
92
93 int writesize; /* size of malloc()ed buffer for tape */
94 long lastspclrec = -1; /* tape block number of last written header */
95 int trecno = 0; /* next record to write in current block */
96 extern long blocksperfile; /* number of blocks per output file */
97 long blocksthisvol; /* number of blocks on current output file */
98 extern int ntrec; /* blocking factor on tape */
99 extern int cartridge;
100 extern char *host;
101 char *nexttape;
102 extern pid_t rshpid;
103 int eot_code = 1;
104 long long tapea_bytes = 0; /* bytes_written at start of current volume */
105
106 static ssize_t atomic_read __P((int, void *, size_t));
107 static ssize_t atomic_write __P((int, const void *, size_t));
108 static void doslave __P((int, int));
109 static void enslave __P((void));
110 static void flushtape __P((void));
111 static void killall __P((void));
112 static void rollforward __P((void));
113 static int system_command __P((const char *, const char *, int));
114
115 /*
116 * Concurrent dump mods (Caltech) - disk block reading and tape writing
117 * are exported to several slave processes. While one slave writes the
118 * tape, the others read disk blocks; they pass control of the tape in
119 * a ring via signals. The parent process traverses the filesystem and
120 * sends writeheader()'s and lists of daddr's to the slaves via pipes.
121 * The following structure defines the instruction packets sent to slaves.
122 */
123 struct req {
124 daddr_t dblk;
125 int count;
126 };
127 int reqsiz;
128
129 struct slave_results {
130 ssize_t unclen; /* uncompressed length */
131 ssize_t clen; /* compressed length */
132 };
133
134 #define SLAVES 3 /* 1 slave writing, 1 reading, 1 for slack */
135 struct slave {
136 int tapea; /* header number at start of this chunk */
137 int count; /* count to next header (used for TS_TAPE */
138 /* after EOT) */
139 int inode; /* inode that we are currently dealing with */
140 int fd; /* FD for this slave */
141 int pid; /* PID for this slave */
142 int sent; /* 1 == we've sent this slave requests */
143 int firstrec; /* record number of this block */
144 char (*tblock)[TP_BSIZE]; /* buffer for data blocks */
145 struct req *req; /* buffer for requests */
146 } slaves[SLAVES+1];
147 struct slave *slp;
148
149 char (*nextblock)[TP_BSIZE];
150
151 static time_t tstart_volume; /* time of volume start */
152 static int tapea_volume; /* value of spcl.c_tapea at volume start */
153
154 int master; /* pid of master, for sending error signals */
155 int tenths; /* length of tape overhead per block written */
156 static int caught; /* have we caught the signal to proceed? */
157 static int ready; /* have we reached the lock point without having */
158 /* received the SIGUSR2 signal from the prev slave? */
159 static sigjmp_buf jmpbuf; /* where to jump to if we are ready when the */
160 /* SIGUSR2 arrives from the previous slave */
161
162 int
163 alloctape(void)
164 {
165 int pgoff = getpagesize() - 1;
166 char *buf;
167 int i;
168
169 writesize = ntrec * TP_BSIZE;
170 reqsiz = (ntrec + 1) * sizeof(struct req);
171 /*
172 * CDC 92181's and 92185's make 0.8" gaps in 1600-bpi start/stop mode
173 * (see DEC TU80 User's Guide). The shorter gaps of 6250-bpi require
174 * repositioning after stopping, i.e, streaming mode, where the gap is
175 * variable, 0.30" to 0.45". The gap is maximal when the tape stops.
176 */
177 if (blocksperfile == 0 && !unlimited)
178 tenths = (cartridge ? 16 : density == 625 ? 5 : 8);
179 else {
180 tenths = 0;
181 density = 1;
182 }
183 /*
184 * Allocate tape buffer contiguous with the array of instruction
185 * packets, so flushtape() can write them together with one write().
186 * Align tape buffer on page boundary to speed up tape write().
187 */
188 for (i = 0; i <= SLAVES; i++) {
189 buf = (char *)
190 malloc((unsigned)(reqsiz + writesize + pgoff + TP_BSIZE));
191 if (buf == NULL)
192 return(0);
193 slaves[i].tblock = (char (*)[TP_BSIZE])
194 #ifdef __linux__
195 (((long)&buf[reqsiz] + pgoff) &~ pgoff);
196 #else
197 (((long)&buf[ntrec + 1] + pgoff) &~ pgoff);
198 #endif
199 slaves[i].req = (struct req *)slaves[i].tblock - ntrec - 1;
200 }
201 slp = &slaves[0];
202 slp->count = 1;
203 slp->tapea = 0;
204 slp->firstrec = 0;
205 nextblock = slp->tblock;
206 return(1);
207 }
208
209 void
210 writerec(const void *dp, int isspcl)
211 {
212
213 slp->req[trecno].dblk = (daddr_t)0;
214 slp->req[trecno].count = 1;
215 /* XXX post increment triggers an egcs-1.1.2-12 bug on alpha/sparc */
216 *(union u_spcl *)(*(nextblock)) = *(union u_spcl *)dp;
217 nextblock++;
218 if (isspcl)
219 lastspclrec = spcl.c_tapea;
220 trecno++;
221 spcl.c_tapea++;
222 if (trecno >= ntrec)
223 flushtape();
224 }
225
226 void
227 dumpblock(daddr_t blkno, int size)
228 {
229 int avail, tpblks, dblkno;
230
231 dblkno = fsbtodb(sblock, blkno);
232 tpblks = size >> tp_bshift;
233 while ((avail = MIN(tpblks, ntrec - trecno)) > 0) {
234 slp->req[trecno].dblk = dblkno;
235 slp->req[trecno].count = avail;
236 trecno += avail;
237 spcl.c_tapea += avail;
238 if (trecno >= ntrec)
239 flushtape();
240 dblkno += avail << (tp_bshift - dev_bshift);
241 tpblks -= avail;
242 }
243 }
244
245 int nogripe = 0;
246
247 static void
248 tperror(int errnum)
249 {
250
251 if (pipeout) {
252 msg("write error on %s: %s\n", tape, strerror(errnum));
253 quit("Cannot recover\n");
254 /* NOTREACHED */
255 }
256 msg("write error %d blocks into volume %d: %s\n",
257 blocksthisvol, tapeno, strerror(errnum));
258 broadcast("DUMP WRITE ERROR!\n");
259 if (query("Do you want to rewrite this volume?")) {
260 msg("Closing this volume. Prepare to restart with new media;\n");
261 msg("this dump volume will be rewritten.\n");
262 killall();
263 nogripe = 1;
264 close_rewind();
265 Exit(X_REWRITE);
266 }
267 if (query("Do you want to start the next tape?"))
268 return;
269 dumpabort(0);
270 }
271
272 static void
273 sigpipe(int signo)
274 {
275
276 quit("Broken pipe\n");
277 }
278
279 /*
280 * do_stats --
281 * Update xferrate stats
282 */
283 time_t
284 do_stats(void)
285 {
286 time_t tnow, ttaken;
287 int blocks;
288
289 tnow = time(NULL);
290 ttaken = tnow - tstart_volume;
291 blocks = spcl.c_tapea - tapea_volume;
292 msg("Volume %d completed at: %s", tapeno, ctime(&tnow));
293 if (! compressed)
294 msg("Volume %d %ld tape blocks (%.2fMB)\n", tapeno,
295 blocks, ((double)blocks * TP_BSIZE / 1048576));
296 if (ttaken > 0) {
297 long volkb = (bytes_written - tapea_bytes) / 1024;
298 long txfrate = volkb / ttaken;
299 msg("Volume %d took %d:%02d:%02d\n", tapeno,
300 ttaken / 3600, (ttaken % 3600) / 60, ttaken % 60);
301 msg("Volume %d transfer rate: %ld kB/s\n", tapeno,
302 txfrate);
303 xferrate += txfrate;
304 if (compressed) {
305 double rate = .0005 + (double) blocks / (double) volkb;
306 msg("Volume %d %ldKB uncompressed, %ldkB compressed,"
307 " %1.3f:1\n",
308 tapeno, blocks, volkb, rate);
309 }
310 }
311 return(tnow);
312 }
313
314 char *
315 mktimeest(time_t tnow)
316 {
317 static char msgbuf[128];
318 time_t deltat;
319
320 msgbuf[0] = '\0';
321
322 if (blockswritten < 500)
323 return NULL;
324 if (blockswritten > tapesize)
325 tapesize = blockswritten;
326 deltat = tstart_writing - tnow + (1.0 * (tnow - tstart_writing))
327 / blockswritten * tapesize;
328 if (tnow > tstart_volume)
329 (void)snprintf(msgbuf, sizeof(msgbuf),
330 "%3.2f%% done at %ld KB/s, finished in %d:%02d\n",
331 (blockswritten * 100.0) / tapesize,
332 (spcl.c_tapea - tapea_volume) / (tnow - tstart_volume),
333 (int)(deltat / 3600), (int)((deltat % 3600) / 60));
334 else
335 (void)snprintf(msgbuf, sizeof(msgbuf),
336 "%3.2f%% done, finished in %d:%02d\n",
337 (blockswritten * 100.0) / tapesize,
338 (int)(deltat / 3600), (int)((deltat % 3600) / 60));
339
340 return msgbuf;
341 }
342
343 #if defined(SIGINFO)
344 /*
345 * statussig --
346 * information message upon receipt of SIGINFO
347 */
348 void
349 statussig(int notused)
350 {
351 int save_errno = errno;
352 char *buf;
353
354 buf = mktimeest(time(NULL));
355 if (buf)
356 write(STDERR_FILENO, buf, strlen(buf));
357 errno = save_errno;
358 }
359 #endif
360
361 static void
362 flushtape(void)
363 {
364 int i, blks, got;
365 long lastfirstrec;
366 struct slave_results returned;
367
368 int siz = (char *)nextblock - (char *)slp->req;
369
370 slp->req[trecno].count = 0; /* Sentinel */
371
372 if (atomic_write( slp->fd, (char *)slp->req, siz) != siz)
373 quit("error writing command pipe: %s\n", strerror(errno));
374 slp->sent = 1; /* we sent a request, read the response later */
375
376 lastfirstrec = slp->firstrec;
377
378 if (++slp >= &slaves[SLAVES])
379 slp = &slaves[0];
380
381 /* Read results back from next slave */
382 if (slp->sent) {
383 if (atomic_read( slp->fd, (char *)&returned, sizeof returned)
384 != sizeof returned) {
385 perror(" DUMP: error reading command pipe in master");
386 dumpabort(0);
387 }
388 got = returned.unclen;
389 bytes_written += returned.clen;
390 if (returned.unclen == returned.clen)
391 uncomprblks++;
392 slp->sent = 0;
393
394 /* Check for errors or end of tape */
395 if (got <= 0) {
396 /* Check for errors */
397 if (got < 0)
398 tperror(-got);
399 else
400 msg("End of tape detected\n");
401
402 /*
403 * Drain the results, don't care what the values were.
404 * If we read them here then trewind won't...
405 */
406 for (i = 0; i < SLAVES; i++) {
407 if (slaves[i].sent) {
408 if (atomic_read( slaves[i].fd,
409 (char *)&returned, sizeof returned)
410 != sizeof returned) {
411 perror(" DUMP: error reading command pipe in master");
412 dumpabort(0);
413 }
414 slaves[i].sent = 0;
415 }
416 }
417
418 close_rewind();
419 rollforward();
420 return;
421 }
422 }
423
424 blks = 0;
425 if (spcl.c_type != TS_END) {
426 for (i = 0; i < spcl.c_count; i++)
427 if (spcl.c_addr[i] != 0)
428 blks++;
429 }
430 slp->count = lastspclrec + blks + 1 - spcl.c_tapea;
431 slp->tapea = spcl.c_tapea;
432 slp->firstrec = lastfirstrec + ntrec;
433 slp->inode = curino;
434 nextblock = slp->tblock;
435 trecno = 0;
436 asize += tenths + returned.clen / density;
437 blockswritten += ntrec;
438 blocksthisvol += ntrec;
439 if (!pipeout && !unlimited && (blocksperfile ?
440 (blocksthisvol >= blocksperfile) : (asize > tsize))) {
441 close_rewind();
442 startnewtape(0);
443 }
444 timeest();
445 }
446
447 /*
448 * Executes the command in a shell.
449 * Returns -1 if an error occured, the exit status of
450 * the command on success.
451 */
452 int system_command(const char *command, const char *device, int volnum) {
453 int pid, status;
454 char commandstr[4096];
455
456 pid = fork();
457 if (pid == -1) {
458 perror(" DUMP: unable to fork");
459 return -1;
460 }
461 if (pid == 0) {
462 setuid(getuid());
463 setgid(getgid());
464 #if OLD_STYLE_FSCRIPT
465 snprintf(commandstr, sizeof(commandstr), "%s", command);
466 #else
467 snprintf(commandstr, sizeof(commandstr), "%s %s %d", command, device, volnum);
468 #endif
469 commandstr[sizeof(commandstr) - 1] = '\0';
470 execl("/bin/sh", "sh", "-c", commandstr, NULL);
471 perror(" DUMP: unable to execute shell");
472 exit(-1);
473 }
474 do {
475 if (waitpid(pid, &status, 0) == -1) {
476 if (errno != EINTR) {
477 perror(" DUMP: waitpid error");
478 return -1;
479 }
480 } else {
481 if (WIFEXITED(status))
482 return WEXITSTATUS(status);
483 else
484 return -1;
485 }
486 } while(1);
487 }
488
489 time_t
490 trewind(void)
491 {
492 int f;
493 int got;
494 struct slave_results returned;
495
496 for (f = 0; f < SLAVES; f++) {
497 /*
498 * Drain the results, but unlike EOT we DO (or should) care
499 * what the return values were, since if we detect EOT after
500 * we think we've written the last blocks to the tape anyway,
501 * we have to replay those blocks with rollforward.
502 *
503 * fixme: punt for now.
504 */
505 if (slaves[f].sent) {
506 if (atomic_read( slaves[f].fd, (char *)&returned, sizeof returned)
507 != sizeof returned) {
508 perror(" DUMP: error reading command pipe in master");
509 dumpabort(0);
510 }
511 got = returned.unclen;
512 bytes_written += returned.clen;
513 if (returned.unclen == returned.clen)
514 uncomprblks++;
515 slaves[f].sent = 0;
516
517 if (got < 0)
518 tperror(-got);
519
520 if (got == 0) {
521 msg("EOT detected in last 2 tape records!\n");
522 msg("Use a longer tape, decrease the size estimate\n");
523 quit("or use no size estimate at all.\n");
524 }
525 }
526 (void) close(slaves[f].fd);
527 }
528 while (wait((int *)NULL) >= 0) /* wait for any signals from slaves */
529 /* void */;
530
531 if (!pipeout) {
532
533 msg("Closing %s\n", tape);
534
535 #ifdef RDUMP
536 if (host) {
537 rmtclose();
538 while (rmtopen(tape, 0) < 0)
539 sleep(10);
540 rmtclose();
541 }
542 else
543 #endif
544 {
545 (void) close(tapefd);
546 while ((f = open(tape, 0)) < 0)
547 sleep (10);
548 (void) close(f);
549 }
550 eot_code = 1;
551 if (eot_script && spcl.c_type != TS_END) {
552 msg("Launching %s\n", eot_script);
553 eot_code = system_command(eot_script, tape, tapeno);
554 }
555 if (eot_code != 0 && eot_code != 1) {
556 msg("Dump aborted by the end of tape script\n");
557 dumpabort(0);
558 }
559 }
560 return do_stats();
561 }
562
563
564 void
565 close_rewind(void)
566 {
567 (void)trewind();
568 if (nexttape || Mflag || (eot_code == 0) )
569 return;
570 if (!nogripe) {
571 msg("Change Volumes: Mount volume #%d\n", tapeno+1);
572 broadcast("CHANGE DUMP VOLUMES!\7\7\n");
573 }
574 while (!query("Is the new volume mounted and ready to go?"))
575 if (query("Do you want to abort?")) {
576 dumpabort(0);
577 /*NOTREACHED*/
578 }
579 }
580
581 void
582 rollforward(void)
583 {
584 register struct req *p, *q, *prev;
585 register struct slave *tslp;
586 int i, size, savedtapea, got;
587 union u_spcl *ntb, *otb;
588 struct slave_results returned;
589 #ifdef __linux__
590 int blks;
591 long lastfirstrec;
592 #endif
593 tslp = &slaves[SLAVES];
594 ntb = (union u_spcl *)tslp->tblock[1];
595
596 /*
597 * Each of the N slaves should have requests that need to
598 * be replayed on the next tape. Use the extra slave buffers
599 * (slaves[SLAVES]) to construct request lists to be sent to
600 * each slave in turn.
601 */
602 for (i = 0; i < SLAVES; i++) {
603 q = &tslp->req[1];
604 otb = (union u_spcl *)slp->tblock;
605
606 /*
607 * For each request in the current slave, copy it to tslp.
608 */
609
610 prev = NULL;
611 for (p = slp->req; p->count > 0; p += p->count) {
612 *q = *p;
613 if (p->dblk == 0)
614 *ntb++ = *otb++; /* copy the datablock also */
615 prev = q;
616 q += q->count;
617 }
618 if (prev == NULL)
619 quit("rollforward: protocol botch");
620 if (prev->dblk != 0)
621 prev->count -= 1;
622 else
623 ntb--;
624 q -= 1;
625 q->count = 0;
626 q = &tslp->req[0];
627 if (i == 0) {
628 q->dblk = 0;
629 q->count = 1;
630 trecno = 0;
631 nextblock = tslp->tblock;
632 savedtapea = spcl.c_tapea;
633 spcl.c_tapea = slp->tapea;
634 startnewtape(0);
635 spcl.c_tapea = savedtapea;
636 lastspclrec = savedtapea - 1;
637 }
638 size = (char *)ntb - (char *)q;
639 if (atomic_write( slp->fd, (char *)q, size) != size) {
640 perror(" DUMP: error writing command pipe");
641 dumpabort(0);
642 }
643 slp->sent = 1;
644 #ifdef __linux__
645 lastfirstrec = slp->firstrec;
646 #endif
647 if (++slp >= &slaves[SLAVES])
648 slp = &slaves[0];
649
650 q->count = 1;
651
652 if (prev->dblk != 0) {
653 /*
654 * If the last one was a disk block, make the
655 * first of this one be the last bit of that disk
656 * block...
657 */
658 q->dblk = prev->dblk +
659 prev->count * (TP_BSIZE / DEV_BSIZE);
660 ntb = (union u_spcl *)tslp->tblock;
661 } else {
662 /*
663 * It wasn't a disk block. Copy the data to its
664 * new location in the buffer.
665 */
666 q->dblk = 0;
667 *((union u_spcl *)tslp->tblock) = *ntb;
668 ntb = (union u_spcl *)tslp->tblock[1];
669 }
670 }
671 slp->req[0] = *q;
672 nextblock = slp->tblock;
673 if (q->dblk == 0) {
674 #ifdef __linux__
675 /* XXX post increment triggers an egcs-1.1.2-12 bug on alpha/sparc */
676 *(union u_spcl *)(*nextblock) = *(union u_spcl *)tslp->tblock;
677 #endif
678 nextblock++;
679 }
680 trecno = 1;
681
682 /*
683 * Clear the first slaves' response. One hopes that it
684 * worked ok, otherwise the tape is much too short!
685 */
686 if (slp->sent) {
687 if (atomic_read( slp->fd, (char *)&returned, sizeof returned)
688 != sizeof returned) {
689 perror(" DUMP: error reading command pipe in master");
690 dumpabort(0);
691 }
692 got = returned.unclen;
693 bytes_written += returned.clen;
694 if (returned.clen == returned.unclen)
695 uncomprblks++;
696 slp->sent = 0;
697
698 if (got < 0)
699 tperror(-got);
700
701 if (got == 0) {
702 quit("EOT detected at start of the tape!\n");
703 }
704 }
705
706 #ifdef __linux__
707 blks = 0;
708 if (spcl.c_type != TS_END) {
709 for (i = 0; i < spcl.c_count; i++)
710 if (spcl.c_addr[i] != 0)
711 blks++;
712 }
713
714 slp->firstrec = lastfirstrec + ntrec;
715 slp->count = lastspclrec + blks + 1 - spcl.c_tapea;
716 slp->inode = curino;
717 asize += tenths + returned.clen / density;
718 blockswritten += ntrec;
719 blocksthisvol += ntrec;
720 #endif
721 }
722
723 /*
724 * We implement taking and restoring checkpoints on the tape level.
725 * When each tape is opened, a new process is created by forking; this
726 * saves all of the necessary context in the parent. The child
727 * continues the dump; the parent waits around, saving the context.
728 * If the child returns X_REWRITE, then it had problems writing that tape;
729 * this causes the parent to fork again, duplicating the context, and
730 * everything continues as if nothing had happened.
731 */
732 void
733 startnewtape(int top)
734 {
735 int parentpid;
736 int childpid;
737 int status;
738 int waitpid;
739 char *p;
740
741 #ifdef __linux__
742 sigset_t sigs;
743 sigemptyset(&sigs);
744 sigaddset(&sigs, SIGINT);
745 sigprocmask(SIG_BLOCK, &sigs, NULL);
746 #else /* __linux__ */
747 #ifdef sunos
748 void (*interrupt_save)();
749 #else
750 sig_t interrupt_save;
751 #endif
752 interrupt_save = signal(SIGINT, SIG_IGN);
753 #endif /* __linux__ */
754
755 parentpid = getpid();
756 tapea_volume = spcl.c_tapea;
757 tapea_bytes = bytes_written;
758 tstart_volume = time(NULL);
759
760 restore_check_point:
761 #ifdef __linux__
762 sigprocmask(SIG_UNBLOCK, &sigs, NULL);
763 #else
764 (void)signal(SIGINT, interrupt_save);
765 #endif
766 /*
767 * All signals are inherited...
768 */
769 childpid = fork();
770 if (childpid < 0) {
771 msg("Context save fork fails in parent %d\n", parentpid);
772 Exit(X_ABORT);
773 }
774 if (childpid != 0) {
775 /*
776 * PARENT:
777 * save the context by waiting
778 * until the child doing all of the work returns.
779 * don't catch the interrupt
780 */
781 #ifdef __linux__
782 sigprocmask(SIG_BLOCK, &sigs, NULL);
783 #else
784 signal(SIGINT, SIG_IGN);
785 #endif
786 #ifdef TDEBUG
787 msg("Tape: %d; parent process: %d child process %d\n",
788 tapeno+1, parentpid, childpid);
789 #endif /* TDEBUG */
790 while ((waitpid = wait(&status)) != childpid)
791 if (waitpid != rshpid)
792 msg("Parent %d waiting for child %d has another child %d return\n",
793 parentpid, childpid, waitpid);
794 if (status & 0xFF) {
795 msg("Child %d returns LOB status %o\n",
796 childpid, status&0xFF);
797 }
798 status = (status >> 8) & 0xFF;
799 #ifdef TDEBUG
800 switch(status) {
801 case X_FINOK:
802 msg("Child %d finishes X_FINOK\n", childpid);
803 break;
804 case X_ABORT:
805 msg("Child %d finishes X_ABORT\n", childpid);
806 break;
807 case X_REWRITE:
808 msg("Child %d finishes X_REWRITE\n", childpid);
809 break;
810 default:
811 msg("Child %d finishes unknown %d\n",
812 childpid, status);
813 break;
814 }
815 #endif /* TDEBUG */
816 switch(status) {
817 case X_FINOK:
818 Exit(X_FINOK);
819 case X_ABORT:
820 Exit(X_ABORT);
821 case X_REWRITE:
822 goto restore_check_point;
823 default:
824 msg("Bad return code from dump: %d\n", status);
825 Exit(X_ABORT);
826 }
827 /*NOTREACHED*/
828 } else { /* we are the child; just continue */
829 #ifdef TDEBUG
830 sleep(4); /* allow time for parent's message to get out */
831 msg("Child on Tape %d has parent %d, my pid = %d\n",
832 tapeno+1, parentpid, getpid());
833 #endif /* TDEBUG */
834 /*
835 * If we have a name like "/dev/rmt0,/dev/rmt1",
836 * use the name before the comma first, and save
837 * the remaining names for subsequent volumes.
838 */
839 tapeno++; /* current tape sequence */
840 if (Mflag) {
841 snprintf(tape, MAXPATHLEN, "%s%03d", tapeprefix, tapeno);
842 tape[MAXPATHLEN - 1] = '\0';
843 msg("Dumping volume %d on %s\n", tapeno, tape);
844 }
845 else if (nexttape || strchr(tapeprefix, ',')) {
846 if (nexttape && *nexttape)
847 tapeprefix = nexttape;
848 if ((p = strchr(tapeprefix, ',')) != NULL) {
849 *p = '\0';
850 nexttape = p + 1;
851 } else
852 nexttape = NULL;
853 strncpy(tape, tapeprefix, MAXPATHLEN);
854 tape[MAXPATHLEN - 1] = '\0';
855 msg("Dumping volume %d on %s\n", tapeno, tape);
856 }
857 #ifdef RDUMP
858 while ((tapefd = (host ? rmtopen(tape, 2) : pipeout ?
859 fileno(stdout) :
860 open(tape, O_WRONLY|O_CREAT, 0666))) < 0)
861 #else
862 while ((tapefd = (pipeout ? fileno(stdout) :
863 open(tape, O_WRONLY|O_CREAT, 0666))) < 0)
864 #endif
865 {
866 msg("Cannot open output \"%s\".\n", tape);
867 if (!query("Do you want to retry the open?"))
868 dumpabort(0);
869 }
870
871 enslave(); /* Share open tape file descriptor with slaves */
872
873 asize = 0;
874 blocksthisvol = 0;
875 if (top)
876 newtape++; /* new tape signal */
877 spcl.c_count = slp->count;
878 /*
879 * measure firstrec in TP_BSIZE units since restore doesn't
880 * know the correct ntrec value...
881 */
882 spcl.c_firstrec = slp->firstrec;
883 spcl.c_volume++;
884 spcl.c_type = TS_TAPE;
885 spcl.c_flags |= DR_NEWHEADER;
886 if (compressed)
887 spcl.c_flags |= DR_COMPRESSED;
888 writeheader((dump_ino_t)slp->inode);
889 spcl.c_flags &=~ DR_NEWHEADER;
890 msg("Volume %d started with block %ld at: %s", tapeno,
891 spcl.c_tapea, ctime(&tstart_volume));
892 if (tapeno > 1)
893 msg("Volume %d begins with blocks from inode %d\n",
894 tapeno, slp->inode);
895 }
896 }
897
898 void
899 dumpabort(int signo)
900 {
901
902 if (master != 0 && master != getpid())
903 /* Signals master to call dumpabort */
904 (void) kill(master, SIGTERM);
905 else {
906 killall();
907 msg("The ENTIRE dump is aborted.\n");
908 }
909 #ifdef RDUMP
910 rmtclose();
911 #endif
912 Exit(X_ABORT);
913 }
914
915 void
916 Exit(int status)
917 {
918
919 #ifdef TDEBUG
920 msg("pid = %d exits with status %d\n", getpid(), status);
921 #endif /* TDEBUG */
922 exit(status);
923 }
924
925 /*
926 * proceed - handler for SIGUSR2, used to synchronize IO between the slaves.
927 */
928 static void
929 proceed(int signo)
930 {
931 if (ready)
932 siglongjmp(jmpbuf, 1);
933 caught++;
934 }
935
936 void
937 enslave(void)
938 {
939 int cmd[2];
940 #ifdef LINUX_FORK_BUG
941 int i, j;
942 #else
943 register int i, j;
944 #endif
945
946 master = getpid();
947
948 { struct sigaction sa;
949 memset(&sa, 0, sizeof sa);
950 sigemptyset(&sa.sa_mask);
951 sa.sa_handler = dumpabort;
952 sigaction(SIGTERM, &sa, NULL); /* Slave sends SIGTERM on dumpabort() */
953 sa.sa_handler = sigpipe;
954 sigaction(SIGPIPE, &sa, NULL);
955 sa.sa_handler = proceed;
956 sa.sa_flags = SA_RESTART;
957 sigaction(SIGUSR2, &sa, NULL); /* Slave sends SIGUSR2 to next slave */
958 }
959
960 for (i = 0; i < SLAVES; i++) {
961 if (i == slp - &slaves[0]) {
962 caught = 1;
963 } else {
964 caught = 0;
965 }
966
967 if (socketpair(AF_UNIX, SOCK_STREAM, 0, cmd) < 0 ||
968 (slaves[i].pid = fork()) < 0)
969 quit("too many slaves, %d (recompile smaller): %s\n",
970 i, strerror(errno));
971
972 slaves[i].fd = cmd[1];
973 slaves[i].sent = 0;
974 if (slaves[i].pid == 0) { /* Slave starts up here */
975 sigset_t sigs;
976 for (j = 0; j <= i; j++)
977 (void) close(slaves[j].fd);
978 sigemptyset(&sigs);
979 sigaddset(&sigs, SIGINT); /* Master handles this */
980 #if defined(SIGINFO)
981 sigaddset(&sigs, SIGINFO);
982 #endif
983 sigprocmask(SIG_BLOCK, &sigs, NULL);
984
985 #ifdef LINUX_FORK_BUG
986 if (atomic_write( cmd[0], (char *) &i, sizeof i)
987 != sizeof i)
988 quit("master/slave protocol botched 3\n");
989 #endif
990 doslave(cmd[0], i);
991 Exit(X_FINOK);
992 }
993 }
994
995 #ifdef LINUX_FORK_BUG
996 /*
997 * Wait for all slaves to _actually_ start to circumvent a bug in
998 * Linux kernels >= 2.1.3 where a signal sent to a child that hasn't
999 * returned from fork() causes a SEGV in the child process
1000 */
1001 for (i = 0; i < SLAVES; i++)
1002 if (atomic_read( slaves[i].fd, (char *) &j, sizeof j) != sizeof j)
1003 quit("master/slave protocol botched 4\n");
1004 #endif
1005
1006 for (i = 0; i < SLAVES; i++)
1007 (void) atomic_write( slaves[i].fd,
1008 (char *) &slaves[(i + 1) % SLAVES].pid,
1009 sizeof slaves[0].pid);
1010
1011 master = 0;
1012 }
1013
1014 void
1015 killall(void)
1016 {
1017 register int i;
1018
1019 for (i = 0; i < SLAVES; i++)
1020 if (slaves[i].pid > 0) {
1021 (void) kill(slaves[i].pid, SIGKILL);
1022 slaves[i].sent = 0;
1023 }
1024 }
1025
1026 /*
1027 * Synchronization - each process waits for a SIGUSR2 from the
1028 * previous process before writing to the tape, and sends SIGUSR2
1029 * to the next process when the tape write completes. On tape errors
1030 * a SIGUSR1 is sent to the master which then terminates all of the
1031 * slaves.
1032 */
1033 static void
1034 doslave(int cmd, int slave_number)
1035 {
1036 register int nread;
1037 int nextslave, size, eot_count, bufsize;
1038 volatile int wrote = 0;
1039 char *buffer;
1040 #ifdef HAVE_ZLIB
1041 struct tapebuf *comp_buf = NULL;
1042 int compresult, do_compress = 0;
1043 unsigned long worklen;
1044 #endif /* HAVE_ZLIB */
1045 struct slave_results returns;
1046 #ifdef __linux__
1047 errcode_t retval;
1048 #endif
1049
1050 /*
1051 * Need our own seek pointer.
1052 */
1053 (void) close(diskfd);
1054 if ((diskfd = open(disk, O_RDONLY)) < 0)
1055 quit("slave couldn't reopen disk: %s\n", strerror(errno));
1056 #ifdef __linux__
1057 ext2fs_close(fs);
1058 retval = dump_fs_open(disk, &fs);
1059 if (retval)
1060 quit("slave couldn't reopen disk: %s\n", error_message(retval));
1061 #endif /* __linux__ */
1062
1063 /*
1064 * Need the pid of the next slave in the loop...
1065 */
1066 if ((nread = atomic_read( cmd, (char *)&nextslave, sizeof nextslave))
1067 != sizeof nextslave) {
1068 quit("master/slave protocol botched - didn't get pid of next slave.\n");
1069 }
1070
1071 #ifdef HAVE_ZLIB
1072 /* if we're doing a compressed dump, allocate the compress buffer */
1073 if (compressed) {
1074 comp_buf = malloc(sizeof(struct tapebuf) + TP_BSIZE + writesize);
1075 if (comp_buf == NULL)
1076 quit("couldn't allocate a compress buffer.\n");
1077 comp_buf->flags = 0;
1078 }
1079 #endif /* HAVE_ZLIB */
1080
1081 /*
1082 * Get list of blocks to dump, read the blocks into tape buffer
1083 */
1084 while ((nread = atomic_read( cmd, (char *)slp->req, reqsiz)) == reqsiz) {
1085 register struct req *p = slp->req;
1086
1087 for (trecno = 0; trecno < ntrec;
1088 trecno += p->count, p += p->count) {
1089 if (p->dblk) { /* read a disk block */
1090 bread(p->dblk, slp->tblock[trecno],
1091 p->count * TP_BSIZE);
1092 } else { /* read record from pipe */
1093 if (p->count != 1 || atomic_read( cmd,
1094 (char *)slp->tblock[trecno],
1095 TP_BSIZE) != TP_BSIZE)
1096 quit("master/slave protocol botched.\n");
1097 }
1098 }
1099
1100 /* Try to write the data... */
1101 wrote = 0;
1102 eot_count = 0;
1103 size = 0;
1104 buffer = (char *) slp->tblock[0]; /* set write pointer */
1105 bufsize = writesize; /* length to write */
1106 returns.clen = returns.unclen = bufsize;
1107
1108 #ifdef HAVE_ZLIB
1109 /*
1110 * When writing a compressed dump, each block is
1111 * written from struct tapebuf with an 4 byte prefix
1112 * followed by the data. This can be less than
1113 * writesize. Restore, on a short read, can compare the
1114 * length read to the compressed length in the header
1115 * to verify that the read was good. Blocks which don't
1116 * compress well are written uncompressed.
1117 * The first block written by each slave is not compressed.
1118 */
1119
1120 if (compressed) {
1121 comp_buf->length = bufsize;
1122 worklen = TP_BSIZE + writesize;
1123 if (do_compress)
1124 compresult = compress2(comp_buf->buf, &worklen,
1125 (char *)slp->tblock[0], writesize, compressed);
1126 if (compresult == Z_OK && worklen <= writesize-32) {
1127 /* write the compressed buffer */
1128 comp_buf->length = worklen;
1129 comp_buf->compressed = 1;
1130 buffer = (char *) comp_buf;
1131 returns.clen = bufsize = worklen + sizeof(struct tapebuf);
1132 }
1133 else {
1134 /* write the data uncompressed */
1135 comp_buf->length = writesize;
1136 comp_buf->compressed = 0;
1137 buffer = (char *) comp_buf;
1138 returns.clen = bufsize = writesize + sizeof(struct tapebuf);
1139 returns.unclen = returns.clen;
1140 memcpy(comp_buf->buf, (char *)slp->tblock[0], writesize);
1141 }
1142 }
1143 /* compress the remaining blocks */
1144 do_compress = compressed;
1145 #endif /* HAVE_ZLIB */
1146
1147 if (sigsetjmp(jmpbuf, 1) == 0) {
1148 ready = 1;
1149 if (!caught)
1150 (void) pause();
1151 }
1152 ready = 0;
1153 caught = 0;
1154
1155 while (eot_count < 10 && size < bufsize) {
1156 #ifdef RDUMP
1157 if (host)
1158 wrote = rmtwrite(buffer + size, bufsize - size);
1159 else
1160 #endif
1161 wrote = write(tapefd, buffer + size, bufsize - size);
1162 #ifdef WRITEDEBUG
1163 printf("slave %d wrote %d\n", slave_number, wrote);
1164 #endif
1165 if (wrote < 0)
1166 break;
1167 if (wrote == 0)
1168 eot_count++;
1169 size += wrote;
1170 }
1171
1172 #ifdef WRITEDEBUG
1173 if (size != bufsize)
1174 printf("slave %d only wrote %d out of %d bytes and gave up.\n",
1175 slave_number, size, bufsize);
1176 #endif
1177
1178 /*
1179 * Handle ENOSPC as an EOT condition.
1180 */
1181 if (wrote < 0 && errno == ENOSPC) {
1182 wrote = 0;
1183 eot_count++;
1184 }
1185
1186 if (eot_count > 0)
1187 returns.clen = returns.unclen = 0;
1188
1189 /*
1190 * pass errno back to master for special handling
1191 */
1192 if (wrote < 0)
1193 returns.unclen = -errno;
1194
1195 /*
1196 * pass size of data and size of write back to master
1197 * (for EOT handling)
1198 */
1199 (void) atomic_write( cmd, (char *)&returns, sizeof returns);
1200
1201 /*
1202 * Signal the next slave to go.
1203 */
1204 (void) kill(nextslave, SIGUSR2);
1205 }
1206 if (nread != 0)
1207 quit("error reading command pipe: %s\n", strerror(errno));
1208 }
1209
1210 /*
1211 * Since a read from a pipe may not return all we asked for,
1212 * or a write may not write all we ask if we get a signal,
1213 * loop until the count is satisfied (or error).
1214 */
1215 static ssize_t
1216 atomic_read(int fd, void *buf, size_t count)
1217 {
1218 int got, need = count;
1219
1220 do {
1221 while ((got = read(fd, buf, need)) > 0 && (need -= got) > 0)
1222 (char *)buf += got;
1223 } while (got == -1 && errno == EINTR);
1224 return (got < 0 ? got : count - need);
1225 }
1226
1227 /*
1228 * Since a read from a pipe may not return all we asked for,
1229 * or a write may not write all we ask if we get a signal,
1230 * loop until the count is satisfied (or error).
1231 */
1232 static ssize_t
1233 atomic_write(int fd, const void *buf, size_t count)
1234 {
1235 int got, need = count;
1236
1237 do {
1238 while ((got = write(fd, buf, need)) > 0 && (need -= got) > 0)
1239 (char *)buf += got;
1240 } while (got == -1 && errno == EINTR);
1241 return (got < 0 ? got : count - need);
1242 }