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