tape.c revision 128073
1/*- 2 * Copyright (c) 1980, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 4. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#ifndef lint 31#if 0 32static char sccsid[] = "@(#)tape.c 8.4 (Berkeley) 5/1/95"; 33#endif 34static const char rcsid[] = 35 "$FreeBSD: head/sbin/dump/tape.c 128073 2004-04-09 19:58:40Z markm $"; 36#endif /* not lint */ 37 38#include <sys/param.h> 39#include <sys/socket.h> 40#include <sys/time.h> 41#include <sys/wait.h> 42#include <sys/stat.h> 43 44#include <ufs/ufs/dinode.h> 45#include <ufs/ffs/fs.h> 46 47#include <protocols/dumprestore.h> 48 49#include <errno.h> 50#include <fcntl.h> 51#include <limits.h> 52#include <setjmp.h> 53#include <signal.h> 54#include <stdio.h> 55#include <stdlib.h> 56#include <string.h> 57#include <unistd.h> 58 59#include "dump.h" 60 61int writesize; /* size of malloc()ed buffer for tape */ 62int64_t lastspclrec = -1; /* tape block number of last written header */ 63int trecno = 0; /* next record to write in current block */ 64extern long blocksperfile; /* number of blocks per output file */ 65long blocksthisvol; /* number of blocks on current output file */ 66extern int ntrec; /* blocking factor on tape */ 67extern int cartridge; 68extern char *host; 69char *nexttape; 70 71static int atomic(ssize_t (*)(), int, char *, int); 72static void doslave(int, int); 73static void enslave(void); 74static void flushtape(void); 75static void killall(void); 76static void rollforward(void); 77 78/* 79 * Concurrent dump mods (Caltech) - disk block reading and tape writing 80 * are exported to several slave processes. While one slave writes the 81 * tape, the others read disk blocks; they pass control of the tape in 82 * a ring via signals. The parent process traverses the file system and 83 * sends writeheader()'s and lists of daddr's to the slaves via pipes. 84 * The following structure defines the instruction packets sent to slaves. 85 */ 86struct req { 87 ufs2_daddr_t dblk; 88 int count; 89}; 90int reqsiz; 91 92#define SLAVES 3 /* 1 slave writing, 1 reading, 1 for slack */ 93struct slave { 94 int64_t tapea; /* header number at start of this chunk */ 95 int64_t firstrec; /* record number of this block */ 96 int count; /* count to next header (used for TS_TAPE */ 97 /* after EOT) */ 98 int inode; /* inode that we are currently dealing with */ 99 int fd; /* FD for this slave */ 100 int pid; /* PID for this slave */ 101 int sent; /* 1 == we've sent this slave requests */ 102 char (*tblock)[TP_BSIZE]; /* buffer for data blocks */ 103 struct req *req; /* buffer for requests */ 104} slaves[SLAVES+1]; 105struct slave *slp; 106 107char (*nextblock)[TP_BSIZE]; 108 109int master; /* pid of master, for sending error signals */ 110int tenths; /* length of tape used per block written */ 111static int caught; /* have we caught the signal to proceed? */ 112static int ready; /* have we reached the lock point without having */ 113 /* received the SIGUSR2 signal from the prev slave? */ 114static jmp_buf jmpbuf; /* where to jump to if we are ready when the */ 115 /* SIGUSR2 arrives from the previous slave */ 116 117int 118alloctape(void) 119{ 120 int pgoff = getpagesize() - 1; 121 char *buf; 122 int i; 123 124 writesize = ntrec * TP_BSIZE; 125 reqsiz = (ntrec + 1) * sizeof(struct req); 126 /* 127 * CDC 92181's and 92185's make 0.8" gaps in 1600-bpi start/stop mode 128 * (see DEC TU80 User's Guide). The shorter gaps of 6250-bpi require 129 * repositioning after stopping, i.e, streaming mode, where the gap is 130 * variable, 0.30" to 0.45". The gap is maximal when the tape stops. 131 */ 132 if (blocksperfile == 0 && !unlimited) 133 tenths = writesize / density + 134 (cartridge ? 16 : density == 625 ? 5 : 8); 135 /* 136 * Allocate tape buffer contiguous with the array of instruction 137 * packets, so flushtape() can write them together with one write(). 138 * Align tape buffer on page boundary to speed up tape write(). 139 */ 140 for (i = 0; i <= SLAVES; i++) { 141 buf = (char *) 142 malloc((unsigned)(reqsiz + writesize + pgoff + TP_BSIZE)); 143 if (buf == NULL) 144 return(0); 145 slaves[i].tblock = (char (*)[TP_BSIZE]) 146 (((long)&buf[ntrec + 1] + pgoff) &~ pgoff); 147 slaves[i].req = (struct req *)slaves[i].tblock - ntrec - 1; 148 } 149 slp = &slaves[0]; 150 slp->count = 1; 151 slp->tapea = 0; 152 slp->firstrec = 0; 153 nextblock = slp->tblock; 154 return(1); 155} 156 157void 158writerec(char *dp, int isspcl) 159{ 160 161 slp->req[trecno].dblk = (ufs2_daddr_t)0; 162 slp->req[trecno].count = 1; 163 /* Can't do a structure assignment due to alignment problems */ 164 bcopy(dp, *(nextblock)++, sizeof (union u_spcl)); 165 if (isspcl) 166 lastspclrec = spcl.c_tapea; 167 trecno++; 168 spcl.c_tapea++; 169 if (trecno >= ntrec) 170 flushtape(); 171} 172 173void 174dumpblock(ufs2_daddr_t blkno, int size) 175{ 176 int avail, tpblks; 177 ufs2_daddr_t dblkno; 178 179 dblkno = fsbtodb(sblock, blkno); 180 tpblks = size >> tp_bshift; 181 while ((avail = MIN(tpblks, ntrec - trecno)) > 0) { 182 slp->req[trecno].dblk = dblkno; 183 slp->req[trecno].count = avail; 184 trecno += avail; 185 spcl.c_tapea += avail; 186 if (trecno >= ntrec) 187 flushtape(); 188 dblkno += avail << (tp_bshift - dev_bshift); 189 tpblks -= avail; 190 } 191} 192 193int nogripe = 0; 194 195void 196tperror(int signo __unused) 197{ 198 199 if (pipeout) { 200 msg("write error on %s\n", tape); 201 quit("Cannot recover\n"); 202 /* NOTREACHED */ 203 } 204 msg("write error %ld blocks into volume %d\n", blocksthisvol, tapeno); 205 broadcast("DUMP WRITE ERROR!\n"); 206 if (!query("Do you want to restart?")) 207 dumpabort(0); 208 msg("Closing this volume. Prepare to restart with new media;\n"); 209 msg("this dump volume will be rewritten.\n"); 210 killall(); 211 nogripe = 1; 212 close_rewind(); 213 Exit(X_REWRITE); 214} 215 216void 217sigpipe(int signo __unused) 218{ 219 220 quit("Broken pipe\n"); 221} 222 223static void 224flushtape(void) 225{ 226 int i, blks, got; 227 int64_t lastfirstrec; 228 229 int siz = (char *)nextblock - (char *)slp->req; 230 231 slp->req[trecno].count = 0; /* Sentinel */ 232 233 if (atomic(write, slp->fd, (char *)slp->req, siz) != siz) 234 quit("error writing command pipe: %s\n", strerror(errno)); 235 slp->sent = 1; /* we sent a request, read the response later */ 236 237 lastfirstrec = slp->firstrec; 238 239 if (++slp >= &slaves[SLAVES]) 240 slp = &slaves[0]; 241 242 /* Read results back from next slave */ 243 if (slp->sent) { 244 if (atomic(read, slp->fd, (char *)&got, sizeof got) 245 != sizeof got) { 246 perror(" DUMP: error reading command pipe in master"); 247 dumpabort(0); 248 } 249 slp->sent = 0; 250 251 /* Check for end of tape */ 252 if (got < writesize) { 253 msg("End of tape detected\n"); 254 255 /* 256 * Drain the results, don't care what the values were. 257 * If we read them here then trewind won't... 258 */ 259 for (i = 0; i < SLAVES; i++) { 260 if (slaves[i].sent) { 261 if (atomic(read, slaves[i].fd, 262 (char *)&got, sizeof got) 263 != sizeof got) { 264 perror(" DUMP: error reading command pipe in master"); 265 dumpabort(0); 266 } 267 slaves[i].sent = 0; 268 } 269 } 270 271 close_rewind(); 272 rollforward(); 273 return; 274 } 275 } 276 277 blks = 0; 278 if (spcl.c_type != TS_END) { 279 for (i = 0; i < spcl.c_count; i++) 280 if (spcl.c_addr[i] != 0) 281 blks++; 282 } 283 slp->count = lastspclrec + blks + 1 - spcl.c_tapea; 284 slp->tapea = spcl.c_tapea; 285 slp->firstrec = lastfirstrec + ntrec; 286 slp->inode = curino; 287 nextblock = slp->tblock; 288 trecno = 0; 289 asize += tenths; 290 blockswritten += ntrec; 291 blocksthisvol += ntrec; 292 if (!pipeout && !unlimited && (blocksperfile ? 293 (blocksthisvol >= blocksperfile) : (asize > tsize))) { 294 close_rewind(); 295 startnewtape(0); 296 } 297 timeest(); 298} 299 300void 301trewind(void) 302{ 303 struct stat sb; 304 int f; 305 int got; 306 307 for (f = 0; f < SLAVES; f++) { 308 /* 309 * Drain the results, but unlike EOT we DO (or should) care 310 * what the return values were, since if we detect EOT after 311 * we think we've written the last blocks to the tape anyway, 312 * we have to replay those blocks with rollforward. 313 * 314 * fixme: punt for now. 315 */ 316 if (slaves[f].sent) { 317 if (atomic(read, slaves[f].fd, (char *)&got, sizeof got) 318 != sizeof got) { 319 perror(" DUMP: error reading command pipe in master"); 320 dumpabort(0); 321 } 322 slaves[f].sent = 0; 323 if (got != writesize) { 324 msg("EOT detected in last 2 tape records!\n"); 325 msg("Use a longer tape, decrease the size estimate\n"); 326 quit("or use no size estimate at all.\n"); 327 } 328 } 329 (void) close(slaves[f].fd); 330 } 331 while (wait((int *)NULL) >= 0) /* wait for any signals from slaves */ 332 /* void */; 333 334 if (pipeout) 335 return; 336 337 msg("Closing %s\n", tape); 338 339#ifdef RDUMP 340 if (host) { 341 rmtclose(); 342 while (rmtopen(tape, 0) < 0) 343 sleep(10); 344 rmtclose(); 345 return; 346 } 347#endif 348 if (fstat(tapefd, &sb) == 0 && S_ISFIFO(sb.st_mode)) { 349 (void)close(tapefd); 350 return; 351 } 352 (void) close(tapefd); 353 while ((f = open(tape, 0)) < 0) 354 sleep (10); 355 (void) close(f); 356} 357 358void 359close_rewind() 360{ 361 time_t tstart_changevol, tend_changevol; 362 363 trewind(); 364 if (nexttape) 365 return; 366 (void)time((time_t *)&(tstart_changevol)); 367 if (!nogripe) { 368 msg("Change Volumes: Mount volume #%d\n", tapeno+1); 369 broadcast("CHANGE DUMP VOLUMES!\a\a\n"); 370 } 371 while (!query("Is the new volume mounted and ready to go?")) 372 if (query("Do you want to abort?")) { 373 dumpabort(0); 374 /*NOTREACHED*/ 375 } 376 (void)time((time_t *)&(tend_changevol)); 377 if ((tstart_changevol != (time_t)-1) && (tend_changevol != (time_t)-1)) 378 tstart_writing += (tend_changevol - tstart_changevol); 379} 380 381void 382rollforward(void) 383{ 384 struct req *p, *q, *prev; 385 struct slave *tslp; 386 int i, size, got; 387 int64_t savedtapea; 388 union u_spcl *ntb, *otb; 389 tslp = &slaves[SLAVES]; 390 ntb = (union u_spcl *)tslp->tblock[1]; 391 392 /* 393 * Each of the N slaves should have requests that need to 394 * be replayed on the next tape. Use the extra slave buffers 395 * (slaves[SLAVES]) to construct request lists to be sent to 396 * each slave in turn. 397 */ 398 for (i = 0; i < SLAVES; i++) { 399 q = &tslp->req[1]; 400 otb = (union u_spcl *)slp->tblock; 401 402 /* 403 * For each request in the current slave, copy it to tslp. 404 */ 405 406 prev = NULL; 407 for (p = slp->req; p->count > 0; p += p->count) { 408 *q = *p; 409 if (p->dblk == 0) 410 *ntb++ = *otb++; /* copy the datablock also */ 411 prev = q; 412 q += q->count; 413 } 414 if (prev == NULL) 415 quit("rollforward: protocol botch"); 416 if (prev->dblk != 0) 417 prev->count -= 1; 418 else 419 ntb--; 420 q -= 1; 421 q->count = 0; 422 q = &tslp->req[0]; 423 if (i == 0) { 424 q->dblk = 0; 425 q->count = 1; 426 trecno = 0; 427 nextblock = tslp->tblock; 428 savedtapea = spcl.c_tapea; 429 spcl.c_tapea = slp->tapea; 430 startnewtape(0); 431 spcl.c_tapea = savedtapea; 432 lastspclrec = savedtapea - 1; 433 } 434 size = (char *)ntb - (char *)q; 435 if (atomic(write, slp->fd, (char *)q, size) != size) { 436 perror(" DUMP: error writing command pipe"); 437 dumpabort(0); 438 } 439 slp->sent = 1; 440 if (++slp >= &slaves[SLAVES]) 441 slp = &slaves[0]; 442 443 q->count = 1; 444 445 if (prev->dblk != 0) { 446 /* 447 * If the last one was a disk block, make the 448 * first of this one be the last bit of that disk 449 * block... 450 */ 451 q->dblk = prev->dblk + 452 prev->count * (TP_BSIZE / DEV_BSIZE); 453 ntb = (union u_spcl *)tslp->tblock; 454 } else { 455 /* 456 * It wasn't a disk block. Copy the data to its 457 * new location in the buffer. 458 */ 459 q->dblk = 0; 460 *((union u_spcl *)tslp->tblock) = *ntb; 461 ntb = (union u_spcl *)tslp->tblock[1]; 462 } 463 } 464 slp->req[0] = *q; 465 nextblock = slp->tblock; 466 if (q->dblk == 0) 467 nextblock++; 468 trecno = 1; 469 470 /* 471 * Clear the first slaves' response. One hopes that it 472 * worked ok, otherwise the tape is much too short! 473 */ 474 if (slp->sent) { 475 if (atomic(read, slp->fd, (char *)&got, sizeof got) 476 != sizeof got) { 477 perror(" DUMP: error reading command pipe in master"); 478 dumpabort(0); 479 } 480 slp->sent = 0; 481 482 if (got != writesize) { 483 quit("EOT detected at start of the tape!\n"); 484 } 485 } 486} 487 488/* 489 * We implement taking and restoring checkpoints on the tape level. 490 * When each tape is opened, a new process is created by forking; this 491 * saves all of the necessary context in the parent. The child 492 * continues the dump; the parent waits around, saving the context. 493 * If the child returns X_REWRITE, then it had problems writing that tape; 494 * this causes the parent to fork again, duplicating the context, and 495 * everything continues as if nothing had happened. 496 */ 497void 498startnewtape(int top) 499{ 500 int parentpid; 501 int childpid; 502 int status; 503 int waitpid; 504 char *p; 505 sig_t interrupt_save; 506 507 interrupt_save = signal(SIGINT, SIG_IGN); 508 parentpid = getpid(); 509 510restore_check_point: 511 (void)signal(SIGINT, interrupt_save); 512 /* 513 * All signals are inherited... 514 */ 515 setproctitle(NULL); /* Restore the proctitle. */ 516 childpid = fork(); 517 if (childpid < 0) { 518 msg("Context save fork fails in parent %d\n", parentpid); 519 Exit(X_ABORT); 520 } 521 if (childpid != 0) { 522 /* 523 * PARENT: 524 * save the context by waiting 525 * until the child doing all of the work returns. 526 * don't catch the interrupt 527 */ 528 signal(SIGINT, SIG_IGN); 529#ifdef TDEBUG 530 msg("Tape: %d; parent process: %d child process %d\n", 531 tapeno+1, parentpid, childpid); 532#endif /* TDEBUG */ 533 while ((waitpid = wait(&status)) != childpid) 534 msg("Parent %d waiting for child %d has another child %d return\n", 535 parentpid, childpid, waitpid); 536 if (status & 0xFF) { 537 msg("Child %d returns LOB status %o\n", 538 childpid, status&0xFF); 539 } 540 status = (status >> 8) & 0xFF; 541#ifdef TDEBUG 542 switch(status) { 543 case X_FINOK: 544 msg("Child %d finishes X_FINOK\n", childpid); 545 break; 546 case X_ABORT: 547 msg("Child %d finishes X_ABORT\n", childpid); 548 break; 549 case X_REWRITE: 550 msg("Child %d finishes X_REWRITE\n", childpid); 551 break; 552 default: 553 msg("Child %d finishes unknown %d\n", 554 childpid, status); 555 break; 556 } 557#endif /* TDEBUG */ 558 switch(status) { 559 case X_FINOK: 560 Exit(X_FINOK); 561 case X_ABORT: 562 Exit(X_ABORT); 563 case X_REWRITE: 564 goto restore_check_point; 565 default: 566 msg("Bad return code from dump: %d\n", status); 567 Exit(X_ABORT); 568 } 569 /*NOTREACHED*/ 570 } else { /* we are the child; just continue */ 571#ifdef TDEBUG 572 sleep(4); /* allow time for parent's message to get out */ 573 msg("Child on Tape %d has parent %d, my pid = %d\n", 574 tapeno+1, parentpid, getpid()); 575#endif /* TDEBUG */ 576 /* 577 * If we have a name like "/dev/rmt0,/dev/rmt1", 578 * use the name before the comma first, and save 579 * the remaining names for subsequent volumes. 580 */ 581 tapeno++; /* current tape sequence */ 582 if (nexttape || strchr(tape, ',')) { 583 if (nexttape && *nexttape) 584 tape = nexttape; 585 if ((p = strchr(tape, ',')) != NULL) { 586 *p = '\0'; 587 nexttape = p + 1; 588 } else 589 nexttape = NULL; 590 msg("Dumping volume %d on %s\n", tapeno, tape); 591 } 592#ifdef RDUMP 593 while ((tapefd = (host ? rmtopen(tape, 2) : 594 pipeout ? 1 : open(tape, O_WRONLY|O_CREAT, 0666))) < 0) 595#else 596 while ((tapefd = (pipeout ? 1 : 597 open(tape, O_WRONLY|O_CREAT, 0666))) < 0) 598#endif 599 { 600 msg("Cannot open output \"%s\".\n", tape); 601 if (!query("Do you want to retry the open?")) 602 dumpabort(0); 603 } 604 605 enslave(); /* Share open tape file descriptor with slaves */ 606 signal(SIGINFO, infosch); 607 608 asize = 0; 609 blocksthisvol = 0; 610 if (top) 611 newtape++; /* new tape signal */ 612 spcl.c_count = slp->count; 613 /* 614 * measure firstrec in TP_BSIZE units since restore doesn't 615 * know the correct ntrec value... 616 */ 617 spcl.c_firstrec = slp->firstrec; 618 spcl.c_volume++; 619 spcl.c_type = TS_TAPE; 620 writeheader((ino_t)slp->inode); 621 if (tapeno > 1) 622 msg("Volume %d begins with blocks from inode %d\n", 623 tapeno, slp->inode); 624 } 625} 626 627void 628dumpabort(int signo __unused) 629{ 630 631 if (master != 0 && master != getpid()) 632 /* Signals master to call dumpabort */ 633 (void) kill(master, SIGTERM); 634 else { 635 killall(); 636 msg("The ENTIRE dump is aborted.\n"); 637 } 638#ifdef RDUMP 639 rmtclose(); 640#endif 641 Exit(X_ABORT); 642} 643 644void 645Exit(status) 646 int status; 647{ 648 649#ifdef TDEBUG 650 msg("pid = %d exits with status %d\n", getpid(), status); 651#endif /* TDEBUG */ 652 exit(status); 653} 654 655/* 656 * proceed - handler for SIGUSR2, used to synchronize IO between the slaves. 657 */ 658void 659proceed(int signo __unused) 660{ 661 662 if (ready) 663 longjmp(jmpbuf, 1); 664 caught++; 665} 666 667void 668enslave(void) 669{ 670 int cmd[2]; 671 int i, j; 672 673 master = getpid(); 674 675 signal(SIGTERM, dumpabort); /* Slave sends SIGTERM on dumpabort() */ 676 signal(SIGPIPE, sigpipe); 677 signal(SIGUSR1, tperror); /* Slave sends SIGUSR1 on tape errors */ 678 signal(SIGUSR2, proceed); /* Slave sends SIGUSR2 to next slave */ 679 680 for (i = 0; i < SLAVES; i++) { 681 if (i == slp - &slaves[0]) { 682 caught = 1; 683 } else { 684 caught = 0; 685 } 686 687 if (socketpair(AF_UNIX, SOCK_STREAM, 0, cmd) < 0 || 688 (slaves[i].pid = fork()) < 0) 689 quit("too many slaves, %d (recompile smaller): %s\n", 690 i, strerror(errno)); 691 692 slaves[i].fd = cmd[1]; 693 slaves[i].sent = 0; 694 if (slaves[i].pid == 0) { /* Slave starts up here */ 695 for (j = 0; j <= i; j++) 696 (void) close(slaves[j].fd); 697 signal(SIGINT, SIG_IGN); /* Master handles this */ 698 doslave(cmd[0], i); 699 Exit(X_FINOK); 700 } 701 } 702 703 for (i = 0; i < SLAVES; i++) 704 (void) atomic(write, slaves[i].fd, 705 (char *) &slaves[(i + 1) % SLAVES].pid, 706 sizeof slaves[0].pid); 707 708 master = 0; 709} 710 711void 712killall(void) 713{ 714 int i; 715 716 for (i = 0; i < SLAVES; i++) 717 if (slaves[i].pid > 0) { 718 (void) kill(slaves[i].pid, SIGKILL); 719 slaves[i].sent = 0; 720 } 721} 722 723/* 724 * Synchronization - each process has a lockfile, and shares file 725 * descriptors to the following process's lockfile. When our write 726 * completes, we release our lock on the following process's lock- 727 * file, allowing the following process to lock it and proceed. We 728 * get the lock back for the next cycle by swapping descriptors. 729 */ 730static void 731doslave(int cmd, int slave_number) 732{ 733 int nread; 734 int nextslave, size, wrote, eot_count; 735 736 /* 737 * Need our own seek pointer. 738 */ 739 (void) close(diskfd); 740 if ((diskfd = open(disk, O_RDONLY)) < 0) 741 quit("slave couldn't reopen disk: %s\n", strerror(errno)); 742 743 /* 744 * Need the pid of the next slave in the loop... 745 */ 746 if ((nread = atomic(read, cmd, (char *)&nextslave, sizeof nextslave)) 747 != sizeof nextslave) { 748 quit("master/slave protocol botched - didn't get pid of next slave.\n"); 749 } 750 751 /* 752 * Get list of blocks to dump, read the blocks into tape buffer 753 */ 754 while ((nread = atomic(read, cmd, (char *)slp->req, reqsiz)) == reqsiz) { 755 struct req *p = slp->req; 756 757 for (trecno = 0; trecno < ntrec; 758 trecno += p->count, p += p->count) { 759 if (p->dblk) { 760 bread(p->dblk, slp->tblock[trecno], 761 p->count * TP_BSIZE); 762 } else { 763 if (p->count != 1 || atomic(read, cmd, 764 (char *)slp->tblock[trecno], 765 TP_BSIZE) != TP_BSIZE) 766 quit("master/slave protocol botched.\n"); 767 } 768 } 769 if (setjmp(jmpbuf) == 0) { 770 ready = 1; 771 if (!caught) 772 (void) pause(); 773 } 774 ready = 0; 775 caught = 0; 776 777 /* Try to write the data... */ 778 eot_count = 0; 779 size = 0; 780 781 wrote = 0; 782 while (eot_count < 10 && size < writesize) { 783#ifdef RDUMP 784 if (host) 785 wrote = rmtwrite(slp->tblock[0]+size, 786 writesize-size); 787 else 788#endif 789 wrote = write(tapefd, slp->tblock[0]+size, 790 writesize-size); 791#ifdef WRITEDEBUG 792 printf("slave %d wrote %d\n", slave_number, wrote); 793#endif 794 if (wrote < 0) 795 break; 796 if (wrote == 0) 797 eot_count++; 798 size += wrote; 799 } 800 801#ifdef WRITEDEBUG 802 if (size != writesize) 803 printf("slave %d only wrote %d out of %d bytes and gave up.\n", 804 slave_number, size, writesize); 805#endif 806 807 /* 808 * Handle ENOSPC as an EOT condition. 809 */ 810 if (wrote < 0 && errno == ENOSPC) { 811 wrote = 0; 812 eot_count++; 813 } 814 815 if (eot_count > 0) 816 size = 0; 817 818 if (wrote < 0) { 819 (void) kill(master, SIGUSR1); 820 for (;;) 821 (void) sigpause(0); 822 } else { 823 /* 824 * pass size of write back to master 825 * (for EOT handling) 826 */ 827 (void) atomic(write, cmd, (char *)&size, sizeof size); 828 } 829 830 /* 831 * If partial write, don't want next slave to go. 832 * Also jolts him awake. 833 */ 834 (void) kill(nextslave, SIGUSR2); 835 } 836 if (nread != 0) 837 quit("error reading command pipe: %s\n", strerror(errno)); 838} 839 840/* 841 * Since a read from a pipe may not return all we asked for, 842 * or a write may not write all we ask if we get a signal, 843 * loop until the count is satisfied (or error). 844 */ 845static int 846atomic(ssize_t (*func)(), int fd, char *buf, int count) 847{ 848 int got, need = count; 849 850 while ((got = (*func)(fd, buf, need)) > 0 && (need -= got) > 0) 851 buf += got; 852 return (got < 0 ? got : count - need); 853} 854