X-Git-Url: https://git.wh0rd.org/?a=blobdiff_plain;f=dump%2Ftape.c;h=63b64260db1d73cf928b5dd426def5feaf650771;hb=bd73117103358c5ee4f02a8fad5dc45123c7a5cc;hp=9d57ddf9099d7d2b31ecb2dea9b08ac71a5205fb;hpb=b45f51d61e911ac8a040bef1efda6afd82261e03;p=dump.git diff --git a/dump/tape.c b/dump/tape.c index 9d57ddf..63b6426 100644 --- a/dump/tape.c +++ b/dump/tape.c @@ -2,8 +2,7 @@ * 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 */ /*- @@ -40,11 +39,8 @@ */ #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.2 1999/10/11 12:53:22 stelian Exp $"; + "$Id: tape.c,v 1.23 2000/08/30 08:55:21 stelian Exp $"; #endif /* not lint */ #ifdef __linux__ @@ -77,6 +73,7 @@ static const char rcsid[] = #include #include #include +#include #ifdef __STDC__ #include #include @@ -85,9 +82,10 @@ static const char rcsid[] = int write(), read(); #endif -#ifdef __linux__ +#ifdef __linux__ #include #endif + #include "dump.h" int writesize; /* size of malloc()ed buffer for tape */ @@ -99,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((ssize_t (*)(), 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 @@ -138,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; @@ -191,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++; @@ -208,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; @@ -230,9 +233,8 @@ dumpblock(blkno, size) int nogripe = 0; -void -tperror(signo) - int signo; +static void +tperror(int signo) { if (pipeout) { @@ -252,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; @@ -270,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 */ @@ -281,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); @@ -298,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"); @@ -337,8 +405,50 @@ 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()); +#if OLD_STYLE_FSCRIPT + snprintf(commandstr, sizeof(commandstr), "%s", command); +#else + snprintf(commandstr, sizeof(commandstr), "%s %s %d", command, device, volnum); +#endif + 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; @@ -353,7 +463,7 @@ trewind() * 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); @@ -370,39 +480,45 @@ 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) { - time_t tstart_changevol, tend_changevol; - - trewind(); - if (nexttape) + (void)trewind(); + if (nexttape || Mflag || (eot_code == 0) ) return; -#ifdef __linux__ - (void)time4(&(tstart_changevol)); -#else - (void)time((time_t *)&(tstart_changevol)); -#endif if (!nogripe) { msg("Change Volumes: Mount volume #%d\n", tapeno+1); broadcast("CHANGE DUMP VOLUMES!\7\7\n"); @@ -412,17 +528,10 @@ close_rewind() dumpabort(0); /*NOTREACHED*/ } -#ifdef __linux__ - (void)time4(&(tend_changevol)); -#else - (void)time((time_t *)&(tend_changevol)); -#endif - if ((tstart_changevol != (time_t)-1) && (tend_changevol != (time_t)-1)) - tstart_writing += (tend_changevol - tstart_changevol); } void -rollforward() +rollforward(void) { register struct req *p, *q, *prev; register struct slave *tslp; @@ -478,7 +587,7 @@ 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); } @@ -512,12 +621,13 @@ rollforward() } 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; /* @@ -525,7 +635,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); @@ -564,29 +674,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... */ @@ -602,13 +725,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", @@ -656,21 +784,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 { @@ -696,6 +832,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); @@ -703,8 +845,7 @@ restore_check_point: } void -dumpabort(signo) - int signo; +dumpabort(int signo) { if (master != 0 && master != getpid()) @@ -721,8 +862,7 @@ dumpabort(signo) } void -Exit(status) - int status; +Exit(int status) { #ifdef TDEBUG @@ -734,18 +874,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); + siglongjmp(jmpbuf, 1); caught++; } void -enslave() +enslave(void) { int cmd[2]; #ifdef LINUX_FORK_BUG @@ -756,10 +894,19 @@ 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; + 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 = 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]) { @@ -776,11 +923,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 @@ -796,12 +950,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 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); @@ -809,7 +963,7 @@ enslave() } void -killall() +killall(void) { register int i; @@ -828,12 +982,12 @@ 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 @@ -846,15 +1000,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"); } @@ -862,7 +1016,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; @@ -871,13 +1025,13 @@ doslave(cmd, slave_number) bread(p->dblk, slp->tblock[trecno], p->count * TP_BSIZE); } else { - if (p->count != 1 || atomic(read, cmd, + 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(); @@ -928,14 +1082,16 @@ doslave(cmd, slave_number) if (wrote < 0) { (void) kill(master, SIGUSR1); + sigemptyset(&sigset); + sigaddset(&sigset, SIGINT); 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); } /* @@ -953,16 +1109,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) - ssize_t (*func)(); - int 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); }