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