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