X-Git-Url: https://git.wh0rd.org/?a=blobdiff_plain;f=dump%2Ftape.c;h=741f2de25ad442a1fcf58cd183beea2945662556;hb=8d4197bb9ba5bbcef21409231ed8903b0cac353a;hp=ce150568df6af077126891da2cfb5ca118be253b;hpb=1227625a12a66e0ded78a1997c2d23f23202a382;p=dump.git diff --git a/dump/tape.c b/dump/tape.c index ce15056..741f2de 100644 --- a/dump/tape.c +++ b/dump/tape.c @@ -1,7 +1,8 @@ /* * Ported to Linux's Second Extended File System as part of the * dump and restore backup suit - * Remy Card , 1994, 1995, 1996 + * Remy Card , 1994-1997 + * Stelian Pop , 1999 * */ @@ -39,9 +40,17 @@ */ #ifndef lint +#if 0 static char sccsid[] = "@(#)tape.c 8.4 (Berkeley) 5/1/95"; +#endif +static const char rcsid[] = + "$Id: tape.c,v 1.4 1999/10/11 13:08:08 stelian Exp $"; #endif /* not lint */ +#ifdef __linux__ +#include +#include +#endif #include #include #include @@ -80,7 +89,6 @@ int write(), read(); #include #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 */ @@ -92,7 +100,8 @@ extern int cartridge; extern char *host; char *nexttape; -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)); @@ -130,16 +139,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 +165,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 +195,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 +212,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 +232,8 @@ dumpblock(blkno, size) int nogripe = 0; -void -tperror(signo) - int signo; +static void +tperror(int signo) { if (pipeout) { @@ -244,16 +253,80 @@ 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 + 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 +335,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 +346,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 +363,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 +394,7 @@ flushtape() asize += tenths; blockswritten += ntrec; blocksthisvol += ntrec; - if (!pipeout && (blocksperfile ? + if (!pipeout && !unlimited && (blocksperfile ? (blocksthisvol >= blocksperfile) : (asize > tsize))) { close_rewind(); startnewtape(0); @@ -330,22 +403,22 @@ flushtape() } void -trewind() +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); @@ -383,9 +456,10 @@ trewind() } void -close_rewind() +close_rewind(void) { trewind(); + (void)do_stats(); if (nexttape) return; if (!nogripe) { @@ -400,19 +474,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 +498,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 +530,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 +545,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 +554,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; @@ -484,7 +565,11 @@ rollforward() slp->req[0] = *q; nextblock = slp->tblock; if (q->dblk == 0) +#ifdef __linux__ + *(union u_spcl *)(*(nextblock)++) = *(union u_spcl *)tslp->tblock; +#else nextblock++; +#endif trecno = 1; /* @@ -492,7 +577,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 +588,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,8 +616,7 @@ rollforward() * everything continues as if nothing had happened. */ void -startnewtape(top) - int top; +startnewtape(int top) { int parentpid; int childpid; @@ -524,7 +624,7 @@ startnewtape(top) int waitpid; char *p; #ifdef __linux__ - void (*interrupt_save)(); + void (*interrupt_save) __P((int signo)); #else /* __linux__ */ #ifdef sunos void (*interrupt_save)(); @@ -535,6 +635,12 @@ startnewtape(top) 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: (void)signal(SIGINT, interrupt_save); @@ -571,7 +677,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: @@ -621,7 +727,7 @@ restore_check_point: while ((tapefd = (host ? rmtopen(tape, 2) : pipeout ? 1 : open(tape, O_WRONLY|O_CREAT, 0666))) < 0) #else - while ((tapefd = (pipeout ? 1 : + while ((tapefd = (pipeout ? 1 : open(tape, O_WRONLY|O_CREAT, 0666))) < 0) #endif { @@ -636,7 +742,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 +753,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 +766,7 @@ restore_check_point: } void -dumpabort(signo) - int signo; +dumpabort(int signo) { if (master != 0 && master != getpid()) @@ -671,9 +782,8 @@ dumpabort(signo) Exit(X_ABORT); } -__dead void -Exit(status) - int status; +void +Exit(int status) { #ifdef TDEBUG @@ -685,18 +795,17 @@ 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); + siglongjmp(jmpbuf, 1); caught++; } void -enslave() +enslave(void) { int cmd[2]; #ifdef LINUX_FORK_BUG @@ -730,8 +839,12 @@ enslave() for (j = 0; j <= i; j++) (void) close(slaves[j].fd); signal(SIGINT, SIG_IGN); /* Master handles this */ +#if defined(SIGINFO) + signal(SIGINFO, SIG_IGN); +#endif + #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 +860,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 +873,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 +892,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. */ @@ -807,7 +918,7 @@ doslave(cmd, slave_number) /* * 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 +926,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,8 +935,8 @@ 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"); } @@ -839,6 +950,7 @@ doslave(cmd, slave_number) caught = 0; /* Try to write the data... */ + wrote = 0; eot_count = 0; size = 0; @@ -852,9 +964,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 +974,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 +1018,27 @@ 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; + + while ((got = read(fd, buf, need)) > 0 && (need -= got) > 0) + (char *)buf += got; + 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; + while ((got = write(fd, buf, need)) > 0 && (need -= got) > 0) + (char *)buf += got; return (got < 0 ? got : count - need); }