X-Git-Url: https://git.wh0rd.org/?p=dump.git;a=blobdiff_plain;f=dump%2Ftape.c;h=644ed8a2ba92ab6a555598b1c234086f6f34cf4c;hp=7790cc4e4bd6a30b8a8d6791699383265493195c;hb=caea5c768eb239f9b987791f0c665b10d7550741;hpb=d1c73b9a3cd598653eb8b13531e8ca3c5c740d90 diff --git a/dump/tape.c b/dump/tape.c index 7790cc4..644ed8a 100644 --- a/dump/tape.c +++ b/dump/tape.c @@ -2,7 +2,8 @@ * Ported to Linux's Second Extended File System as part of the * dump and restore backup suit * Remy Card , 1994-1997 - * Stelian Pop , 1999 + * Stelian Pop , 1999-2000 + * Stelian Pop - AlcĂ´ve , 2000 */ /*- @@ -40,22 +41,47 @@ #ifndef lint static const char rcsid[] = - "$Id: tape.c,v 1.9 1999/11/21 16:01:47 tiniou Exp $"; + "$Id: tape.c,v 1.56 2001/09/12 09:02:51 stelian Exp $"; #endif /* not lint */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __STDC__ +#include +#include +#include +#else +int write(), read(); +#endif + #ifdef __linux__ #include -#include +#include +#include #endif #include #include -#include #include +#include #ifdef __linux__ +#include +#undef atomic_read /* this get wrongly defined in kernel */ + /* headers and we don't want it */ +#ifdef HAVE_EXT2FS_EXT2_FS_H +#include +#else #include +#endif +#include #include -#else /* __linux__ */ -#ifdef sunos +#elif defined sunos #include #include @@ -63,27 +89,17 @@ static const char rcsid[] = #else #include #include -#endif #endif /* __linux__ */ #include -#include -#include -#include -#include -#include -#ifdef __STDC__ -#include -#include -#include -#else -int write(), read(); -#endif +#ifdef HAVE_ZLIB +#include +#endif /* HAVE_ZLIB */ -#ifdef __linux__ -#include -#endif +#ifdef HAVE_BZLIB +#include +#endif /* HAVE_BZLIB */ #include "dump.h" @@ -97,10 +113,12 @@ extern int cartridge; extern char *host; char *nexttape; extern pid_t rshpid; +int eot_code = 1; +long long tapea_bytes = 0; /* bytes_written at start of current volume */ 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 doslave __P((int, int, int)); static void enslave __P((void)); static void flushtape __P((void)); static void killall __P((void)); @@ -120,6 +138,11 @@ struct req { }; int reqsiz; +struct slave_results { + ssize_t unclen; /* uncompressed length */ + ssize_t clen; /* compressed length */ +}; + #define SLAVES 3 /* 1 slave writing, 1 reading, 1 for slack */ struct slave { int tapea; /* header number at start of this chunk */ @@ -141,12 +164,15 @@ 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 */ +int tenths; /* length of tape overhead 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 sigjmp_buf jmpbuf; /* where to jump to if we are ready when the */ /* SIGUSR2 arrives from the previous slave */ +#ifdef USE_QFA +static int gtperr = 0; +#endif int alloctape(void) @@ -164,8 +190,11 @@ alloctape(void) * variable, 0.30" to 0.45". The gap is maximal when the tape stops. */ if (blocksperfile == 0 && !unlimited) - tenths = writesize / density + - (cartridge ? 16 : density == 625 ? 5 : 8); + tenths = (cartridge ? 16 : density == 625 ? 5 : 8); + else { + tenths = 0; + density = 1; + } /* * Allocate tape buffer contiguous with the array of instruction * packets, so flushtape() can write them together with one write(). @@ -231,24 +260,28 @@ dumpblock(daddr_t blkno, int size) int nogripe = 0; static void -tperror(int signo) +tperror(int errnum) { if (pipeout) { - msg("write error on %s\n", tape); + msg("write error on %s: %s\n", tape, strerror(errnum)); quit("Cannot recover\n"); /* NOTREACHED */ } - msg("write error %d blocks into volume %d\n", blocksthisvol, tapeno); + msg("write error %d blocks into volume %d: %s\n", + blocksthisvol, tapeno, strerror(errnum)); broadcast("DUMP WRITE ERROR!\n"); - if (!query("Do you want to restart?")) - dumpabort(0); - msg("Closing this volume. Prepare to restart with new media;\n"); - msg("this dump volume will be rewritten.\n"); - killall(); - nogripe = 1; - close_rewind(); - Exit(X_REWRITE); + if (query("Do you want to rewrite this volume?")) { + msg("Closing this volume. Prepare to restart with new media;\n"); + msg("this dump volume will be rewritten.\n"); + killall(); + nogripe = 1; + close_rewind(); + Exit(X_REWRITE); + } + if (query("Do you want to start the next tape?")) + return; + dumpabort(0); } static void @@ -268,57 +301,74 @@ do_stats(void) time_t tnow, ttaken; int blocks; -#ifdef __linux__ - (void)time4(&tnow); -#else - (void)time(&tnow); -#endif + tnow = time(NULL); 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 + msg("Volume %d completed at: %s", tapeno, ctime(&tnow)); + if (! compressed) + msg("Volume %d %ld tape blocks (%.2fMB)\n", tapeno, + blocks, ((double)blocks * TP_BSIZE / 1048576)); if (ttaken > 0) { + long volkb = (bytes_written - tapea_bytes) / 1024; + long txfrate = volkb / ttaken; 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; + msg("Volume %d transfer rate: %ld kB/s\n", tapeno, + txfrate); + xferrate += txfrate; + if (compressed) { + double rate = .0005 + (double) blocks / (double) volkb; + msg("Volume %d %ldkB uncompressed, %ldkB compressed," + " %1.3f:1\n", + tapeno, blocks, volkb, rate); + } } return(tnow); } +char * +mktimeest(time_t tnow) +{ + static char msgbuf[128]; + time_t deltat; + + msgbuf[0] = '\0'; + + if (blockswritten < 500) + return NULL; + if (blockswritten > tapesize) + tapesize = blockswritten; + deltat = tstart_writing - tnow + (1.0 * (tnow - tstart_writing)) + / blockswritten * tapesize; + if (tnow > tstart_volume) + (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)); + else + (void)snprintf(msgbuf, sizeof(msgbuf), + "%3.2f%% done, finished in %d:%02d\n", + (blockswritten * 100.0) / tapesize, + (int)(deltat / 3600), (int)((deltat % 3600) / 60)); + + return msgbuf; +} + #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; + char *buf; - 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)); + buf = mktimeest(time(NULL)); + if (buf) + write(STDERR_FILENO, buf, strlen(buf)); errno = save_errno; } #endif @@ -328,6 +378,7 @@ flushtape(void) { int i, blks, got; long lastfirstrec; + struct slave_results returned; int siz = (char *)nextblock - (char *)slp->req; @@ -344,16 +395,24 @@ flushtape(void) /* Read results back from next slave */ if (slp->sent) { - if (atomic_read( slp->fd, (char *)&got, sizeof got) - != sizeof got) { + if (atomic_read( slp->fd, (char *)&returned, sizeof returned) + != sizeof returned) { perror(" DUMP: error reading command pipe in master"); dumpabort(0); } + got = returned.unclen; + bytes_written += returned.clen; + if (returned.unclen == returned.clen) + uncomprblks++; slp->sent = 0; - /* Check for end of tape */ - if (got < writesize) { - msg("End of tape detected\n"); + /* Check for errors or end of tape */ + if (got <= 0) { + /* Check for errors */ + if (got < 0) + tperror(-got); + else + msg("End of tape detected\n"); /* * Drain the results, don't care what the values were. @@ -362,8 +421,8 @@ flushtape(void) for (i = 0; i < SLAVES; i++) { if (slaves[i].sent) { if (atomic_read( slaves[i].fd, - (char *)&got, sizeof got) - != sizeof got) { + (char *)&returned, sizeof returned) + != sizeof returned) { perror(" DUMP: error reading command pipe in master"); dumpabort(0); } @@ -389,22 +448,31 @@ flushtape(void) slp->inode = curino; nextblock = slp->tblock; trecno = 0; - asize += tenths; + asize += tenths + returned.clen / density; blockswritten += ntrec; blocksthisvol += ntrec; - if (!pipeout && !unlimited && (blocksperfile ? - (blocksthisvol >= blocksperfile) : (asize > tsize))) { - close_rewind(); - startnewtape(0); + if (!pipeout && !unlimited) { + if (blocksperfile) { + if ( compressed ? (bytes_written - tapea_bytes + SLAVES * (writesize + sizeof(struct tapebuf))) >= blocksperfile * 1024 + : blocksthisvol >= blocksperfile ) { + close_rewind(); + startnewtape(0); + } + } + else if (asize > tsize) { + close_rewind(); + startnewtape(0); + } } timeest(); } -void +time_t trewind(void) { int f; int got; + struct slave_results returned; for (f = 0; f < SLAVES; f++) { /* @@ -416,13 +484,21 @@ trewind(void) * fixme: punt for now. */ if (slaves[f].sent) { - if (atomic_read( slaves[f].fd, (char *)&got, sizeof got) - != sizeof got) { + if (atomic_read( slaves[f].fd, (char *)&returned, sizeof returned) + != sizeof returned) { perror(" DUMP: error reading command pipe in master"); dumpabort(0); } + got = returned.unclen; + bytes_written += returned.clen; + if (returned.unclen == returned.clen) + uncomprblks++; slaves[f].sent = 0; - if (got != writesize) { + + if (got < 0) + tperror(-got); + + if (got == 0) { msg("EOT detected in last 2 tape records!\n"); msg("Use a longer tape, decrease the size estimate\n"); quit("or use no size estimate at all.\n"); @@ -433,32 +509,46 @@ trewind(void) 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); + if (!fifoout) { + 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(void) { - trewind(); - (void)do_stats(); - if (nexttape || Mflag) + (void)trewind(); + if (nexttape || Mflag || (eot_code == 0) ) return; if (!nogripe) { msg("Change Volumes: Mount volume #%d\n", tapeno+1); @@ -474,10 +564,11 @@ close_rewind(void) void rollforward(void) { - register struct req *p, *q, *prev; + register struct req *p, *q = NULL, *prev; register struct slave *tslp; int i, size, savedtapea, got; union u_spcl *ntb, *otb; + struct slave_results returned; #ifdef __linux__ int blks; long lastfirstrec; @@ -562,12 +653,13 @@ rollforward(void) } slp->req[0] = *q; nextblock = slp->tblock; - if (q->dblk == 0) + if (q->dblk == 0) { #ifdef __linux__ - *(union u_spcl *)(*(nextblock)++) = *(union u_spcl *)tslp->tblock; -#else - nextblock++; + /* 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; /* @@ -575,14 +667,21 @@ rollforward(void) * worked ok, otherwise the tape is much too short! */ if (slp->sent) { - if (atomic_read( slp->fd, (char *)&got, sizeof got) - != sizeof got) { + if (atomic_read( slp->fd, (char *)&returned, sizeof returned) + != sizeof returned) { perror(" DUMP: error reading command pipe in master"); dumpabort(0); } + got = returned.unclen; + bytes_written += returned.clen; + if (returned.clen == returned.unclen) + uncomprblks++; slp->sent = 0; - if (got != writesize) { + if (got < 0) + tperror(-got); + + if (got == 0) { quit("EOT detected at start of the tape!\n"); } } @@ -598,7 +697,7 @@ rollforward(void) slp->firstrec = lastfirstrec + ntrec; slp->count = lastspclrec + blks + 1 - spcl.c_tapea; slp->inode = curino; - asize += tenths; + asize += tenths + returned.clen / density; blockswritten += ntrec; blocksthisvol += ntrec; #endif @@ -621,27 +720,32 @@ startnewtape(int top) int status; int waitpid; char *p; + #ifdef __linux__ - void (*interrupt_save) __P((int signo)); + 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 + tapea_bytes = bytes_written; + tstart_volume = time(NULL); restore_check_point: +#ifdef __linux__ + sigprocmask(SIG_UNBLOCK, &sigs, NULL); +#else (void)signal(SIGINT, interrupt_save); +#endif /* * All signals are inherited... */ @@ -657,7 +761,11 @@ 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); @@ -713,8 +821,8 @@ restore_check_point: */ tapeno++; /* current tape sequence */ if (Mflag) { - snprintf(tape, NAME_MAX, "%s%03d", tapeprefix, tapeno); - tape[NAME_MAX - 1] = '\0'; + 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, ',')) { @@ -725,16 +833,17 @@ restore_check_point: nexttape = p + 1; } else nexttape = NULL; - strncpy(tape, tapeprefix, NAME_MAX); - tape[NAME_MAX - 1] = '\0'; + 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 : - open(tape, O_WRONLY|O_CREAT, 0666))) < 0) + while ((tapefd = (pipeout ? fileno(stdout) : + OPEN(tape, O_RDWR|O_CREAT, 0666))) < 0) #endif { msg("Cannot open output \"%s\".\n", tape); @@ -757,14 +866,13 @@ restore_check_point: spcl.c_volume++; spcl.c_type = TS_TAPE; spcl.c_flags |= DR_NEWHEADER; - writeheader((ino_t)slp->inode); + spcl.c_ntrec = ntrec; + if (compressed) + spcl.c_flags |= DR_COMPRESSED; + writeheader((dump_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 + msg("Volume %d started with block %ld at: %s", tapeno, + spcl.c_tapea, ctime(&tstart_volume)); if (tapeno > 1) msg("Volume %d begins with blocks from inode %d\n", tapeno, slp->inode); @@ -804,7 +912,6 @@ Exit(int status) static void proceed(int signo) { - if (ready) siglongjmp(jmpbuf, 1); caught++; @@ -822,10 +929,17 @@ enslave(void) 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; + memset(&sa, 0, sizeof sa); + sigemptyset(&sa.sa_mask); + sa.sa_handler = dumpabort; + sigaction(SIGTERM, &sa, NULL); /* Slave sends SIGTERM on dumpabort() */ + sa.sa_handler = sigpipe; + sigaction(SIGPIPE, &sa, NULL); + 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]) { @@ -842,21 +956,26 @@ enslave(void) 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) - signal(SIGINFO, SIG_IGN); + sigaddset(&sigs, SIGINFO); #endif + sigprocmask(SIG_BLOCK, &sigs, NULL); #ifdef LINUX_FORK_BUG if (atomic_write( cmd[0], (char *) &i, sizeof i) != sizeof i) quit("master/slave protocol botched 3\n"); #endif - doslave(cmd[0], i); + doslave(cmd[0], i, (slaves[i].pid == slp->pid)); Exit(X_FINOK); } + else + close(cmd[0]); } #ifdef LINUX_FORK_BUG @@ -891,30 +1010,47 @@ killall(void) } /* - * Synchronization - each process has a lockfile, and shares file - * descriptors to the following process's lockfile. When our write - * completes, we release our lock on the following process's lock- - * file, allowing the following process to lock it and proceed. We - * get the lock back for the next cycle by swapping descriptors. + * Synchronization - each process waits for a SIGUSR2 from the + * previous process before writing to the tape, and sends SIGUSR2 + * to the next process when the tape write completes. On tape errors + * a SIGUSR1 is sent to the master which then terminates all of the + * slaves. */ static void -doslave(int cmd, int slave_number) +doslave(int cmd, int slave_number, int first) { register int nread; - int nextslave, size, eot_count; + int nextslave, size, eot_count, bufsize; volatile int wrote = 0; - sigset_t sigset; + char *buffer; +#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) + struct tapebuf *comp_buf = NULL; + int compresult, do_compress = !first; + unsigned long worklen; +#ifdef HAVE_BZLIB + unsigned int worklen2; +#endif +#endif /* HAVE_ZLIB || HAVE_BZLIB */ + struct slave_results returns; #ifdef __linux__ errcode_t retval; #endif +#ifdef USE_QFA + long curtapepos; + union u_spcl *uspclptr; + struct s_spcl *spclptr; +#endif /* USE_QFA */ /* * Need our own seek pointer. */ (void) close(diskfd); - if ((diskfd = open(disk, O_RDONLY)) < 0) + if ((diskfd = OPEN(disk, O_RDONLY)) < 0) quit("slave couldn't reopen disk: %s\n", strerror(errno)); #ifdef __linux__ +#ifdef BLKFLSBUF + (void)ioctl(diskfd, BLKFLSBUF); +#endif ext2fs_close(fs); retval = dump_fs_open(disk, &fs); if (retval) @@ -929,6 +1065,19 @@ doslave(int cmd, int slave_number) quit("master/slave protocol botched - didn't get pid of next slave.\n"); } +#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) + /* if we're doing a compressed dump, allocate the compress buffer */ + if (compressed) { + comp_buf = malloc(sizeof(struct tapebuf) + TP_BSIZE + writesize); + if (comp_buf == NULL) + quit("couldn't allocate a compress buffer.\n"); + if (bzipflag) + comp_buf->flags = COMPRESS_BZLIB; + else + comp_buf->flags = COMPRESS_ZLIB; + } +#endif /* HAVE_ZLIB || HAVE_BZLIB */ + /* * Get list of blocks to dump, read the blocks into tape buffer */ @@ -937,17 +1086,95 @@ doslave(int cmd, int slave_number) for (trecno = 0; trecno < ntrec; trecno += p->count, p += p->count) { - if (p->dblk) { + if (p->dblk) { /* read a disk block */ bread(p->dblk, slp->tblock[trecno], p->count * TP_BSIZE); - } else { + } else { /* read record from pipe */ 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) { + + /* Try to write the data... */ + wrote = 0; + eot_count = 0; + size = 0; + buffer = (char *) slp->tblock[0]; /* set write pointer */ + bufsize = writesize; /* length to write */ + returns.clen = returns.unclen = bufsize; + +#if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) + /* + * When writing a compressed dump, each block except + * the first one on each tape is written + * from struct tapebuf with an 4 byte prefix + * followed by the data. This can be less than + * writesize. Restore, on a short read, can compare the + * length read to the compressed length in the header + * to verify that the read was good. Blocks which don't + * compress well are written uncompressed. + * The first block written by each slave is not compressed + * and does not have a prefix. + */ + + if (compressed && do_compress) { + comp_buf->length = bufsize; + worklen = TP_BSIZE + writesize; +#ifdef HAVE_ZLIB + if (!bzipflag) { + compresult = compress2(comp_buf->buf, + &worklen, + (char *)slp->tblock[0], + writesize, + compressed); + if (compresult == Z_OK) + compresult = 1; + else + compresult = 0; + } +#endif /* HAVE_ZLIB */ +#ifdef HAVE_BZLIB + if (bzipflag) { + worklen2 = worklen; + compresult = BZ2_bzBuffToBuffCompress( + comp_buf->buf, + &worklen2, + (char *)slp->tblock[0], + writesize, + compressed, + 0, 30); + worklen = worklen2; + if (compresult == BZ_OK) + compresult = 1; + else + compresult = 0; + } + +#endif /* HAVE_BZLIB */ + if (compresult && worklen <= (writesize - 16)) { + /* write the compressed buffer */ + comp_buf->length = worklen; + comp_buf->compressed = 1; + buffer = (char *) comp_buf; + returns.clen = bufsize = worklen + sizeof(struct tapebuf); + } + else { + /* write the data uncompressed */ + comp_buf->length = writesize; + comp_buf->compressed = 0; + buffer = (char *) comp_buf; + returns.clen = bufsize = writesize + sizeof(struct tapebuf); + returns.unclen = returns.clen; + memcpy(comp_buf->buf, (char *)slp->tblock[0], writesize); + } + } + /* compress the remaining blocks if we're compressing */ + do_compress = compressed; +#endif /* HAVE_ZLIB || HAVE_BZLIB */ + + if (sigsetjmp(jmpbuf, 1) == 0) { ready = 1; if (!caught) (void) pause(); @@ -955,20 +1182,37 @@ doslave(int cmd, int slave_number) ready = 0; caught = 0; - /* Try to write the data... */ - wrote = 0; - eot_count = 0; - size = 0; - - while (eot_count < 10 && size < writesize) { +#ifdef USE_QFA + if (gTapeposfd >= 0) { + uspclptr = (union u_spcl *)&slp->tblock[0]; + spclptr = &uspclptr->s_spcl; + if ((spclptr->c_magic == NFS_MAGIC) && + (spclptr->c_type == TS_INODE) && + (spclptr->c_date == gThisDumpDate)) { + /* if an error occured previously don't + * try again */ + if (gtperr == 0) { + if ((gtperr = GetTapePos(&curtapepos)) == 0) { +#ifdef DEBUG_QFA + msg("inode %ld at tapepos %ld\n", spclptr->c_inumber, curtapepos); +#endif + sprintf(gTps, "%ld\t%d\t%ld\n", (unsigned long)spclptr->c_inumber, tapeno, curtapepos); + if (write(gTapeposfd, gTps, strlen(gTps)) != strlen(gTps)) { + warn("error writing tapepos file.\n"); + } + } + } + } + } +#endif /* USE_QFA */ + + while (eot_count < 10 && size < bufsize) { #ifdef RDUMP if (host) - wrote = rmtwrite(slp->tblock[0]+size, - writesize-size); + wrote = rmtwrite(buffer + size, bufsize - size); else #endif - wrote = write(tapefd, slp->tblock[0]+size, - writesize-size); + wrote = write(tapefd, buffer + size, bufsize - size); #ifdef WRITEDEBUG printf("slave %d wrote %d\n", slave_number, wrote); #endif @@ -980,9 +1224,9 @@ doslave(int cmd, int slave_number) } #ifdef WRITEDEBUG - if (size != writesize) + if (size != bufsize) printf("slave %d only wrote %d out of %d bytes and gave up.\n", - slave_number, size, writesize); + slave_number, size, bufsize); #endif /* @@ -994,24 +1238,22 @@ doslave(int cmd, int slave_number) } if (eot_count > 0) - size = 0; + returns.clen = returns.unclen = 0; - if (wrote < 0) { - (void) kill(master, SIGUSR1); - sigemptyset(&sigset); - for (;;) - sigsuspend(&sigset); - } else { - /* - * pass size of write back to master - * (for EOT handling) - */ - (void) atomic_write( cmd, (char *)&size, sizeof size); - } + /* + * pass errno back to master for special handling + */ + if (wrote < 0) + returns.unclen = -errno; /* - * If partial write, don't want next slave to go. - * Also jolts him awake. + * pass size of data and size of write back to master + * (for EOT handling) + */ + (void) atomic_write( cmd, (char *)&returns, sizeof returns); + + /* + * Signal the next slave to go. */ (void) kill(nextslave, SIGUSR2); } @@ -1029,8 +1271,10 @@ 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; + 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); } @@ -1044,7 +1288,30 @@ atomic_write(int fd, const void *buf, size_t count) { int got, need = count; - while ((got = write(fd, buf, need)) > 0 && (need -= got) > 0) - (char *)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); } + + +#ifdef USE_QFA +/* + * read the current tape position + */ +int +GetTapePos(long *pos) +{ + int err = 0; + + *pos = 0; + if (ioctl(tapefd, MTIOCPOS, pos) == -1) { + err = errno; + msg("[%ld] error: %d (getting tapepos: %ld)\n", getpid(), + err, *pos); + return err; + } + return err; +} +#endif /* USE_QFA */