]> git.wh0rd.org - dump.git/blobdiff - dump/tape.c
The -F script is called now *only* at the end of a tape.
[dump.git] / dump / tape.c
index ce150568df6af077126891da2cfb5ca118be253b..69715003e67bf772103bfad8d0b5d996a64c03ec 100644 (file)
@@ -1,8 +1,8 @@
 /*
  *     Ported to Linux's Second Extended File System as part of the
  *     dump and restore backup suit
- *     Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
- *
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <pop@cybercable.fr>, 1999-2000
  */
 
 /*-
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)tape.c     8.4 (Berkeley) 5/1/95";
+static const char rcsid[] =
+       "$Id: tape.c,v 1.19 2000/05/28 16:24:14 stelian Exp $";
 #endif /* not lint */
 
+#ifdef __linux__
+#include <sys/types.h>
+#include <linux/types.h>
+#endif
 #include <sys/param.h>
 #include <sys/socket.h>
 #include <sys/time.h>
@@ -68,6 +73,7 @@ static char sccsid[] = "@(#)tape.c    8.4 (Berkeley) 5/1/95";
 #include <setjmp.h>
 #include <signal.h>
 #include <stdio.h>
+#include <compaterr.h>
 #ifdef __STDC__
 #include <stdlib.h>
 #include <string.h>
@@ -76,11 +82,11 @@ static char sccsid[] = "@(#)tape.c  8.4 (Berkeley) 5/1/95";
 int    write(), read();
 #endif
 
-#ifdef __linux__
+#ifdef __linux__
 #include <ext2fs/ext2fs.h>
 #endif
+
 #include "dump.h"
-#include "pathnames.h"
 
 int    writesize;              /* size of malloc()ed buffer for tape */
 long   lastspclrec = -1;       /* tape block number of last written header */
@@ -91,13 +97,17 @@ extern      int ntrec;              /* blocking factor on tape */
 extern int cartridge;
 extern char *host;
 char   *nexttape;
+extern  pid_t rshpid;
+int    eot_code = 1;
 
-static int atomic __P((int (*)(), int, char *, int));
+static ssize_t atomic_read __P((int, void *, size_t));
+static ssize_t atomic_write __P((int, const void *, size_t));
 static void doslave __P((int, int));
 static void enslave __P((void));
 static void flushtape __P((void));
 static void killall __P((void));
 static void rollforward __P((void));
+static int system_command __P((const char *, const char *, int));
 
 /*
  * Concurrent dump mods (Caltech) - disk block reading and tape writing
@@ -130,16 +140,19 @@ struct slave *slp;
 
 char   (*nextblock)[TP_BSIZE];
 
+static time_t tstart_volume;   /* time of volume start */ 
+static int tapea_volume;       /* value of spcl.c_tapea at volume start */
+
 int master;            /* pid of master, for sending error signals */
 int tenths;            /* length of tape used per block written */
 static int caught;     /* have we caught the signal to proceed? */
 static int ready;      /* have we reached the lock point without having */
                        /* received the SIGUSR2 signal from the prev slave? */
-static jmp_buf jmpbuf; /* where to jump to if we are ready when the */
+static sigjmp_buf jmpbuf;      /* where to jump to if we are ready when the */
                        /* SIGUSR2 arrives from the previous slave */
 
 int
-alloctape()
+alloctape(void)
 {
        int pgoff = getpagesize() - 1;
        char *buf;
@@ -153,7 +166,7 @@ alloctape()
         * repositioning after stopping, i.e, streaming mode, where the gap is
         * variable, 0.30" to 0.45".  The gap is maximal when the tape stops.
         */
-       if (blocksperfile == 0)
+       if (blocksperfile == 0 && !unlimited)
                tenths = writesize / density +
                    (cartridge ? 16 : density == 625 ? 5 : 8);
        /*
@@ -183,14 +196,14 @@ alloctape()
 }
 
 void
-writerec(dp, isspcl)
-       char *dp;
-       int isspcl;
+writerec(const void *dp, int isspcl)
 {
 
        slp->req[trecno].dblk = (daddr_t)0;
        slp->req[trecno].count = 1;
-       *(union u_spcl *)(*(nextblock)++) = *(union u_spcl *)dp;
+       /* XXX post increment triggers an egcs-1.1.2-12 bug on alpha/sparc */
+       *(union u_spcl *)(*(nextblock)) = *(union u_spcl *)dp;
+       nextblock++;
        if (isspcl)
                lastspclrec = spcl.c_tapea;
        trecno++;
@@ -200,9 +213,7 @@ writerec(dp, isspcl)
 }
 
 void
-dumpblock(blkno, size)
-       daddr_t blkno;
-       int size;
+dumpblock(daddr_t blkno, int size)
 {
        int avail, tpblks, dblkno;
 
@@ -222,9 +233,8 @@ dumpblock(blkno, size)
 
 int    nogripe = 0;
 
-void
-tperror(signo)
-       int signo;
+static void
+tperror(int signo)
 {
 
        if (pipeout) {
@@ -244,16 +254,82 @@ tperror(signo)
        Exit(X_REWRITE);
 }
 
-void
-sigpipe(signo)
-       int signo;
+static void
+sigpipe(int signo)
 {
 
        quit("Broken pipe\n");
 }
 
+/*
+ * do_stats --
+ *     Update xferrate stats
+ */
+time_t
+do_stats(void)
+{
+       time_t tnow, ttaken;
+       int blocks;
+
+#ifdef __linux__
+       (void)time4(&tnow);
+#else
+       (void)time(&tnow);
+#endif
+       ttaken = tnow - tstart_volume;
+       blocks = spcl.c_tapea - tapea_volume;
+       msg("Volume %d completed at: %s", tapeno, 
+#ifdef __linux__
+                                         ctime4(&tnow));
+#else
+                                         ctime(&tnow));
+#endif
+       if (ttaken > 0) {
+               msg("Volume %d took %d:%02d:%02d\n", tapeno,
+                       ttaken / 3600, (ttaken % 3600) / 60, ttaken % 60);
+               msg("Volume %d transfer rate: %ld KB/s\n", tapeno,
+                       blocks / ttaken);
+               xferrate += blocks / ttaken;
+       }
+       return(tnow);
+}
+
+#if defined(SIGINFO)
+/*
+ * statussig --
+ *     information message upon receipt of SIGINFO
+ *     (derived from optr.c::timeest())
+ */
+void
+statussig(int notused)
+{
+       time_t  tnow, deltat;
+       char    msgbuf[128];
+       int save_errno = errno;
+
+       if (blockswritten < 500)
+               return;
+#ifdef __linux__
+       (void) time4(&tnow);
+#else
+       (void) time((time_t *) &tnow);
+#endif
+       if (blockswritten > tapesize)
+               tapesize = blockswritten;
+       deltat = tstart_writing - tnow + (1.0 * (tnow - tstart_writing))
+               / blockswritten * tapesize;
+       (void)snprintf(msgbuf, sizeof(msgbuf),
+               "%3.2f%% done at %ld KB/s, finished in %d:%02d\n",
+               (blockswritten * 100.0) / tapesize,
+               (spcl.c_tapea - tapea_volume) / (tnow - tstart_volume),
+               (int)(deltat / 3600), (int)((deltat % 3600) / 60));
+       write(STDERR_FILENO, msgbuf, strlen(msgbuf));
+       errno = save_errno;
+}
+#endif
+
 static void
-flushtape()
+flushtape(void)
 {
        int i, blks, got;
        long lastfirstrec;
@@ -262,7 +338,7 @@ flushtape()
 
        slp->req[trecno].count = 0;                     /* Sentinel */
 
-       if (atomic(write, slp->fd, (char *)slp->req, siz) != siz)
+       if (atomic_write( slp->fd, (char *)slp->req, siz) != siz)
                quit("error writing command pipe: %s\n", strerror(errno));
        slp->sent = 1; /* we sent a request, read the response later */
 
@@ -273,7 +349,7 @@ flushtape()
 
        /* Read results back from next slave */
        if (slp->sent) {
-               if (atomic(read, slp->fd, (char *)&got, sizeof got)
+               if (atomic_read( slp->fd, (char *)&got, sizeof got)
                    != sizeof got) {
                        perror("  DUMP: error reading command pipe in master");
                        dumpabort(0);
@@ -290,7 +366,7 @@ flushtape()
                         */
                        for (i = 0; i < SLAVES; i++) {
                                if (slaves[i].sent) {
-                                       if (atomic(read, slaves[i].fd,
+                                       if (atomic_read( slaves[i].fd,
                                            (char *)&got, sizeof got)
                                            != sizeof got) {
                                                perror("  DUMP: error reading command pipe in master");
@@ -321,7 +397,7 @@ flushtape()
        asize += tenths;
        blockswritten += ntrec;
        blocksthisvol += ntrec;
-       if (!pipeout && (blocksperfile ?
+       if (!pipeout && !unlimited && (blocksperfile ?
            (blocksthisvol >= blocksperfile) : (asize > tsize))) {
                close_rewind();
                startnewtape(0);
@@ -329,23 +405,61 @@ flushtape()
        timeest();
 }
 
-void
-trewind()
+/*
+ * Executes the command in a shell.
+ * Returns -1 if an error occured, the exit status of
+ * the command on success.
+ */
+int system_command(const char *command, const char *device, int volnum) {
+       int pid, status;
+       char commandstr[4096];
+
+       pid = fork();
+       if (pid == -1) {
+               perror("  DUMP: unable to fork");
+               return -1;
+       }
+       if (pid == 0) {
+               setuid(getuid());
+               setgid(getgid());
+               snprintf(commandstr, sizeof(commandstr), "%s %s %d", command, device, volnum);
+               commandstr[sizeof(commandstr) - 1] = '\0';
+               execl("/bin/sh", "sh", "-c", commandstr, NULL);
+               perror("  DUMP: unable to execute shell");
+               exit(-1);
+       }
+       do {
+               if (waitpid(pid, &status, 0) == -1) {
+                       if (errno != EINTR) {
+                               perror("  DUMP: waitpid error");
+                               return -1;
+                       }
+               } else {
+                       if (WIFEXITED(status))
+                               return WEXITSTATUS(status);
+                       else
+                               return -1;
+               }
+       } while(1);
+}
+
+time_t
+trewind(void)
 {
        int f;
        int got;
 
        for (f = 0; f < SLAVES; f++) {
                /*
-                * Drain the results, but unlike EOT we DO (or should) care 
-                * what the return values were, since if we detect EOT after 
-                * we think we've written the last blocks to the tape anyway, 
+                * Drain the results, but unlike EOT we DO (or should) care
+                * what the return values were, since if we detect EOT after
+                * we think we've written the last blocks to the tape anyway,
                 * we have to replay those blocks with rollforward.
                 *
-                * fixme: punt for now.  
+                * fixme: punt for now.
                 */
                if (slaves[f].sent) {
-                       if (atomic(read, slaves[f].fd, (char *)&got, sizeof got)
+                       if (atomic_read( slaves[f].fd, (char *)&got, sizeof got)
                            != sizeof got) {
                                perror("  DUMP: error reading command pipe in master");
                                dumpabort(0);
@@ -362,31 +476,44 @@ trewind()
        while (wait((int *)NULL) >= 0)  /* wait for any signals from slaves */
                /* void */;
 
-       if (pipeout)
-               return;
+       if (!pipeout) {
 
-       msg("Closing %s\n", tape);
+               msg("Closing %s\n", tape);
 
 #ifdef RDUMP
-       if (host) {
-               rmtclose();
-               while (rmtopen(tape, 0) < 0)
-                       sleep(10);
-               rmtclose();
-               return;
-       }
+               if (host) {
+                       rmtclose();
+                       while (rmtopen(tape, 0) < 0)
+                               sleep(10);
+                       rmtclose();
+               }
+               else 
 #endif
-       (void) close(tapefd);
-       while ((f = open(tape, 0)) < 0)
-               sleep (10);
-       (void) close(f);
+               {
+                       (void) close(tapefd);
+                       while ((f = open(tape, 0)) < 0)
+                               sleep (10);
+                       (void) close(f);
+               }
+               eot_code = 1;
+               if (eot_script && spcl.c_type != TS_END) {
+                       msg("Launching %s\n", eot_script);
+                       eot_code = system_command(eot_script, tape, tapeno);
+               }
+               if (eot_code != 0 && eot_code != 1) {
+                       msg("Dump aborted by the end of tape script\n");
+                       dumpabort(0);
+               }
+       }
+       return do_stats();
 }
 
+               
 void
-close_rewind()
+close_rewind(void)
 {
-       trewind();
-       if (nexttape)
+       (void)trewind();
+       if (nexttape || Mflag || (eot_code == 0) )
                return;
        if (!nogripe) {
                msg("Change Volumes: Mount volume #%d\n", tapeno+1);
@@ -400,19 +527,23 @@ close_rewind()
 }
 
 void
-rollforward()
+rollforward(void)
 {
        register struct req *p, *q, *prev;
        register struct slave *tslp;
        int i, size, savedtapea, got;
        union u_spcl *ntb, *otb;
+#ifdef __linux__
+       int blks;
+       long lastfirstrec;
+#endif
        tslp = &slaves[SLAVES];
        ntb = (union u_spcl *)tslp->tblock[1];
 
        /*
-        * Each of the N slaves should have requests that need to 
-        * be replayed on the next tape.  Use the extra slave buffers 
-        * (slaves[SLAVES]) to construct request lists to be sent to 
+        * Each of the N slaves should have requests that need to
+        * be replayed on the next tape.  Use the extra slave buffers
+        * (slaves[SLAVES]) to construct request lists to be sent to
         * each slave in turn.
         */
        for (i = 0; i < SLAVES; i++) {
@@ -420,7 +551,7 @@ rollforward()
                otb = (union u_spcl *)slp->tblock;
 
                /*
-                * For each request in the current slave, copy it to tslp. 
+                * For each request in the current slave, copy it to tslp.
                 */
 
                prev = NULL;
@@ -452,11 +583,14 @@ rollforward()
                        lastspclrec = savedtapea - 1;
                }
                size = (char *)ntb - (char *)q;
-               if (atomic(write, slp->fd, (char *)q, size) != size) {
+               if (atomic_write( slp->fd, (char *)q, size) != size) {
                        perror("  DUMP: error writing command pipe");
                        dumpabort(0);
                }
                slp->sent = 1;
+#ifdef __linux__
+               lastfirstrec = slp->firstrec;
+#endif
                if (++slp >= &slaves[SLAVES])
                        slp = &slaves[0];
 
@@ -464,8 +598,8 @@ rollforward()
 
                if (prev->dblk != 0) {
                        /*
-                        * If the last one was a disk block, make the 
-                        * first of this one be the last bit of that disk 
+                        * If the last one was a disk block, make the
+                        * first of this one be the last bit of that disk
                         * block...
                         */
                        q->dblk = prev->dblk +
@@ -473,7 +607,7 @@ rollforward()
                        ntb = (union u_spcl *)tslp->tblock;
                } else {
                        /*
-                        * It wasn't a disk block.  Copy the data to its 
+                        * It wasn't a disk block.  Copy the data to its
                         * new location in the buffer.
                         */
                        q->dblk = 0;
@@ -483,8 +617,13 @@ rollforward()
        }
        slp->req[0] = *q;
        nextblock = slp->tblock;
-       if (q->dblk == 0)
+       if (q->dblk == 0) {
+#ifdef __linux__
+       /* XXX post increment triggers an egcs-1.1.2-12 bug on alpha/sparc */
+               *(union u_spcl *)(*nextblock) = *(union u_spcl *)tslp->tblock;
+#endif
                nextblock++;
+       }
        trecno = 1;
 
        /*
@@ -492,7 +631,7 @@ rollforward()
         * worked ok, otherwise the tape is much too short!
         */
        if (slp->sent) {
-               if (atomic(read, slp->fd, (char *)&got, sizeof got)
+               if (atomic_read( slp->fd, (char *)&got, sizeof got)
                    != sizeof got) {
                        perror("  DUMP: error reading command pipe in master");
                        dumpabort(0);
@@ -503,6 +642,22 @@ rollforward()
                        quit("EOT detected at start of the tape!\n");
                }
        }
+
+#ifdef __linux__
+       blks = 0;
+       if (spcl.c_type != TS_END) {
+               for (i = 0; i < spcl.c_count; i++)
+                       if (spcl.c_addr[i] != 0)
+                               blks++;
+       }
+
+       slp->firstrec = lastfirstrec + ntrec;
+       slp->count = lastspclrec + blks + 1 - spcl.c_tapea;
+       slp->inode = curino;
+       asize += tenths;
+       blockswritten += ntrec;
+       blocksthisvol += ntrec;
+#endif
 }
 
 /*
@@ -515,29 +670,42 @@ rollforward()
  * everything continues as if nothing had happened.
  */
 void
-startnewtape(top)
-       int top;
+startnewtape(int top)
 {
        int     parentpid;
        int     childpid;
        int     status;
        int     waitpid;
        char    *p;
+
 #ifdef __linux__
-       void    (*interrupt_save)();
+       sigset_t sigs;
+       sigemptyset(&sigs);
+       sigaddset(&sigs, SIGINT);
+       sigprocmask(SIG_BLOCK, &sigs, NULL);
 #else  /* __linux__ */
 #ifdef sunos
        void    (*interrupt_save)();
 #else
        sig_t   interrupt_save;
 #endif
+       interrupt_save = signal(SIGINT, SIG_IGN);
 #endif /* __linux__ */
 
-       interrupt_save = signal(SIGINT, SIG_IGN);
        parentpid = getpid();
+       tapea_volume = spcl.c_tapea;
+#ifdef __linux__
+       (void)time4(&tstart_volume);
+#else
+       (void)time((&tstart_volume);
+#endif
 
 restore_check_point:
+#ifdef __linux__
+       sigprocmask(SIG_UNBLOCK, &sigs, NULL);
+#else
        (void)signal(SIGINT, interrupt_save);
+#endif
        /*
         *      All signals are inherited...
         */
@@ -553,13 +721,18 @@ restore_check_point:
                 *      until the child doing all of the work returns.
                 *      don't catch the interrupt
                 */
+#ifdef __linux__
+               sigprocmask(SIG_BLOCK, &sigs, NULL);
+#else
                signal(SIGINT, SIG_IGN);
+#endif
 #ifdef TDEBUG
                msg("Tape: %d; parent process: %d child process %d\n",
                        tapeno+1, parentpid, childpid);
 #endif /* TDEBUG */
                while ((waitpid = wait(&status)) != childpid)
-                       msg("Parent %d waiting for child %d has another child %d return\n",
+                       if (waitpid != rshpid)
+                               msg("Parent %d waiting for child %d has another child %d return\n",
                                parentpid, childpid, waitpid);
                if (status & 0xFF) {
                        msg("Child %d returns LOB status %o\n",
@@ -571,7 +744,7 @@ restore_check_point:
                        case X_FINOK:
                                msg("Child %d finishes X_FINOK\n", childpid);
                                break;
-                       case X_ABORT:   
+                       case X_ABORT:
                                msg("Child %d finishes X_ABORT\n", childpid);
                                break;
                        case X_REWRITE:
@@ -607,21 +780,29 @@ restore_check_point:
                 * the remaining names for subsequent volumes.
                 */
                tapeno++;               /* current tape sequence */
-               if (nexttape || strchr(tape, ',')) {
+               if (Mflag) {
+                       snprintf(tape, MAXPATHLEN, "%s%03d", tapeprefix, tapeno);
+                       tape[MAXPATHLEN - 1] = '\0';
+                       msg("Dumping volume %d on %s\n", tapeno, tape);
+               }
+               else if (nexttape || strchr(tapeprefix, ',')) {
                        if (nexttape && *nexttape)
-                               tape = nexttape;
-                       if ((p = strchr(tape, ',')) != NULL) {
+                               tapeprefix = nexttape;
+                       if ((p = strchr(tapeprefix, ',')) != NULL) {
                                *p = '\0';
                                nexttape = p + 1;
                        } else
                                nexttape = NULL;
+                       strncpy(tape, tapeprefix, MAXPATHLEN);
+                       tape[MAXPATHLEN - 1] = '\0';
                        msg("Dumping volume %d on %s\n", tapeno, tape);
                }
 #ifdef RDUMP
-               while ((tapefd = (host ? rmtopen(tape, 2) :
-                       pipeout ? 1 : open(tape, O_WRONLY|O_CREAT, 0666))) < 0)
+               while ((tapefd = (host ? rmtopen(tape, 2) : pipeout ? 
+                       fileno(stdout) : 
+                       open(tape, O_WRONLY|O_CREAT, 0666))) < 0)
 #else
-               while ((tapefd = (pipeout ? 1 : 
+               while ((tapefd = (pipeout ? fileno(stdout) :
                                  open(tape, O_WRONLY|O_CREAT, 0666))) < 0)
 #endif
                    {
@@ -636,7 +817,7 @@ restore_check_point:
                blocksthisvol = 0;
                if (top)
                        newtape++;              /* new tape signal */
-               spcl.c_count = slp->count; 
+               spcl.c_count = slp->count;
                /*
                 * measure firstrec in TP_BSIZE units since restore doesn't
                 * know the correct ntrec value...
@@ -647,6 +828,12 @@ restore_check_point:
                spcl.c_flags |= DR_NEWHEADER;
                writeheader((ino_t)slp->inode);
                spcl.c_flags &=~ DR_NEWHEADER;
+               msg("Volume %d started at: %s", tapeno, 
+#ifdef __linux__
+                                               ctime4(&tstart_volume));
+#else
+                                               ctime(&tstart_volume));
+#endif
                if (tapeno > 1)
                        msg("Volume %d begins with blocks from inode %d\n",
                                tapeno, slp->inode);
@@ -654,8 +841,7 @@ restore_check_point:
 }
 
 void
-dumpabort(signo)
-       int signo;
+dumpabort(int signo)
 {
 
        if (master != 0 && master != getpid())
@@ -671,9 +857,8 @@ dumpabort(signo)
        Exit(X_ABORT);
 }
 
-__dead void
-Exit(status)
-       int status;
+void
+Exit(int status)
 {
 
 #ifdef TDEBUG
@@ -685,18 +870,16 @@ Exit(status)
 /*
  * proceed - handler for SIGUSR2, used to synchronize IO between the slaves.
  */
-void
-proceed(signo)
-       int signo;
+static void
+proceed(int signo)
 {
-
-       if (ready)
-               longjmp(jmpbuf, 1);
        caught++;
+       if (ready)
+               siglongjmp(jmpbuf, 1);
 }
 
 void
-enslave()
+enslave(void)
 {
        int cmd[2];
 #ifdef LINUX_FORK_BUG
@@ -707,10 +890,17 @@ enslave()
 
        master = getpid();
 
-       signal(SIGTERM, dumpabort);  /* Slave sends SIGTERM on dumpabort() */
-       signal(SIGPIPE, sigpipe);
-       signal(SIGUSR1, tperror);    /* Slave sends SIGUSR1 on tape errors */
-       signal(SIGUSR2, proceed);    /* Slave sends SIGUSR2 to next slave */
+    {  struct sigaction sa;
+       sa.sa_handler = dumpabort;
+       sigaction(SIGTERM, &sa, NULL); /* Slave sends SIGTERM on dumpabort() */
+       sa.sa_handler = sigpipe;
+       sigaction(SIGPIPE, &sa, NULL);
+       sa.sa_handler = tperror;
+       sigaction(SIGUSR1, &sa, NULL); /* Slave sends SIGUSR1 on tape errors */
+       sa.sa_handler = proceed;
+       sa.sa_flags = SA_RESTART;
+       sigaction(SIGUSR2, &sa, NULL); /* Slave sends SIGUSR2 to next slave */
+   }
 
        for (i = 0; i < SLAVES; i++) {
                if (i == slp - &slaves[0]) {
@@ -727,11 +917,18 @@ enslave()
                slaves[i].fd = cmd[1];
                slaves[i].sent = 0;
                if (slaves[i].pid == 0) {           /* Slave starts up here */
+                       sigset_t sigs;
                        for (j = 0; j <= i; j++)
                                (void) close(slaves[j].fd);
-                       signal(SIGINT, SIG_IGN);    /* Master handles this */
+                       sigemptyset(&sigs);
+                       sigaddset(&sigs, SIGINT);  /* Master handles this */
+#if defined(SIGINFO)
+                       sigaddset(&sigs, SIGINFO);
+#endif
+                       sigprocmask(SIG_BLOCK, &sigs, NULL);
+
 #ifdef LINUX_FORK_BUG
-                       if (atomic(write, cmd[0], (char *) &i, sizeof i)
+                       if (atomic_write( cmd[0], (char *) &i, sizeof i)
                            != sizeof i)
                                quit("master/slave protocol botched 3\n");
 #endif
@@ -747,13 +944,12 @@ enslave()
         * returned from fork() causes a SEGV in the child process
         */
        for (i = 0; i < SLAVES; i++)
-               if (atomic(read, slaves[i].fd, (char *) &j, sizeof j) != sizeof j)
+               if (atomic_read( slaves[i].fd, (char *) &j, sizeof j) != sizeof j)
                        quit("master/slave protocol botched 4\n");
 #endif
 
-       /* write pid of next slave to each slave */
        for (i = 0; i < SLAVES; i++)
-               (void) atomic(write, slaves[i].fd, 
+               (void) atomic_write( slaves[i].fd, 
                              (char *) &slaves[(i + 1) % SLAVES].pid, 
                              sizeof slaves[0].pid);
                
@@ -761,13 +957,15 @@ enslave()
 }
 
 void
-killall()
+killall(void)
 {
        register int i;
 
        for (i = 0; i < SLAVES; i++)
-               if (slaves[i].pid > 0)
+               if (slaves[i].pid > 0) {
                        (void) kill(slaves[i].pid, SIGKILL);
+                       slaves[i].sent = 0;
+               }
 }
 
 /*
@@ -778,19 +976,16 @@ killall()
  * get the lock back for the next cycle by swapping descriptors.
  */
 static void
-doslave(cmd, slave_number)
-       register int cmd;
-        int slave_number;
+doslave(int cmd, int slave_number)
 {
        register int nread;
-       int nextslave, size, wrote, eot_count;
+       int nextslave, size, eot_count;
+       volatile int wrote = 0;
+       sigset_t sigset;
 #ifdef __linux__
        errcode_t retval;
 #endif
 
-#ifdef TDEBUG
-       msg("slave %d, pid %d\n", slave_number, getpid());
-#endif
        /*
         * Need our own seek pointer.
         */
@@ -799,15 +994,15 @@ doslave(cmd, slave_number)
                quit("slave couldn't reopen disk: %s\n", strerror(errno));
 #ifdef __linux__
        ext2fs_close(fs);
-       retval = ext2fs_open(disk, 0, 0, 0, unix_io_manager, &fs);
+       retval = dump_fs_open(disk, &fs);
        if (retval)
-               quit("slave couldn't reopen disk: %s\n", strerror(errno));
+               quit("slave couldn't reopen disk: %s\n", error_message(retval));
 #endif /* __linux__ */
 
        /*
         * Need the pid of the next slave in the loop...
         */
-       if ((nread = atomic(read, cmd, (char *)&nextslave, sizeof nextslave))
+       if ((nread = atomic_read( cmd, (char *)&nextslave, sizeof nextslave))
            != sizeof nextslave) {
                quit("master/slave protocol botched - didn't get pid of next slave.\n");
        }
@@ -815,7 +1010,7 @@ doslave(cmd, slave_number)
        /*
         * Get list of blocks to dump, read the blocks into tape buffer
         */
-       while ((nread = atomic(read, cmd, (char *)slp->req, reqsiz)) == reqsiz) {
+       while ((nread = atomic_read( cmd, (char *)slp->req, reqsiz)) == reqsiz) {
                register struct req *p = slp->req;
 
                for (trecno = 0; trecno < ntrec;
@@ -824,13 +1019,13 @@ doslave(cmd, slave_number)
                                bread(p->dblk, slp->tblock[trecno],
                                        p->count * TP_BSIZE);
                        } else {
-                               if (p->count != 1 || atomic(read, cmd,
-                                   (char *)slp->tblock[trecno], 
+                               if (p->count != 1 || atomic_read( cmd,
+                                   (char *)slp->tblock[trecno],
                                    TP_BSIZE) != TP_BSIZE)
                                       quit("master/slave protocol botched.\n");
                        }
                }
-               if (setjmp(jmpbuf) == 0) {
+               if (sigsetjmp(jmpbuf, 1) == 0) {
                        ready = 1;
                        if (!caught)
                                (void) pause();
@@ -839,6 +1034,7 @@ doslave(cmd, slave_number)
                caught = 0;
 
                /* Try to write the data... */
+               wrote = 0;
                eot_count = 0;
                size = 0;
 
@@ -852,9 +1048,9 @@ doslave(cmd, slave_number)
                                wrote = write(tapefd, slp->tblock[0]+size,
                                    writesize-size);
 #ifdef WRITEDEBUG
-                       msg("slave %d wrote %d\n", slave_number, wrote);
+                       printf("slave %d wrote %d\n", slave_number, wrote);
 #endif
-                       if (wrote < 0) 
+                       if (wrote < 0)
                                break;
                        if (wrote == 0)
                                eot_count++;
@@ -862,29 +1058,34 @@ doslave(cmd, slave_number)
                }
 
 #ifdef WRITEDEBUG
-               if (size != writesize) 
-                msg("slave %d only wrote %d out of %d bytes and gave up.\n",
+               if (size != writesize)
+                printf("slave %d only wrote %d out of %d bytes and gave up.\n",
                     slave_number, size, writesize);
 #endif
 
+               /*
+                * Handle ENOSPC as an EOT condition.
+                */
+               if (wrote < 0 && errno == ENOSPC) {
+                       wrote = 0;
+                       eot_count++;
+               }
+
                if (eot_count > 0)
                        size = 0;
 
-               /*
-                * fixme: Pyramids running OSx return ENOSPC
-                * at EOT on 1/2 inch drives.
-                */
-               if (size < 0) {
+               if (wrote < 0) {
                        (void) kill(master, SIGUSR1);
+                       sigemptyset(&sigset);
                        for (;;)
-                               (void) sigpause(0);
+                               sigsuspend(&sigset);
                } else {
                        /*
                         * pass size of write back to master
                         * (for EOT handling)
                         */
-                       (void) atomic(write, cmd, (char *)&size, sizeof size);
-               } 
+                       (void) atomic_write( cmd, (char *)&size, sizeof size);
+               }
 
                /*
                 * If partial write, don't want next slave to go.
@@ -901,15 +1102,31 @@ doslave(cmd, slave_number)
  * or a write may not write all we ask if we get a signal,
  * loop until the count is satisfied (or error).
  */
-static int
-atomic(func, fd, buf, count)
-       int (*func)(), fd;
-       char *buf;
-       int count;
+static ssize_t
+atomic_read(int fd, void *buf, size_t count)
+{
+       int got, need = count;
+
+       do {
+               while ((got = read(fd, buf, need)) > 0 && (need -= got) > 0)
+                       (char *)buf += got;
+       } while (got == -1 && errno == EINTR);
+       return (got < 0 ? got : count - need);
+}
+
+/*
+ * Since a read from a pipe may not return all we asked for,
+ * or a write may not write all we ask if we get a signal,
+ * loop until the count is satisfied (or error).
+ */
+static ssize_t
+atomic_write(int fd, const void *buf, size_t count)
 {
        int got, need = count;
 
-       while ((got = (*func)(fd, buf, need)) > 0 && (need -= got) > 0)
-               buf += got;
+       do {
+               while ((got = write(fd, buf, need)) > 0 && (need -= got) > 0)
+                       (char *)buf += got;
+       } while (got == -1 && errno == EINTR);
        return (got < 0 ? got : count - need);
 }