1*4774Smckusic static char *sccsid = "@(#)tape.c 1.4 (Berkeley) 11/07/81"; 21425Sroot #include "dump.h" 31425Sroot 4*4774Smckusic char tblock[NTREC][TP_BSIZE]; 5*4774Smckusic int trecno = 0; 61425Sroot 71425Sroot taprec(dp) 81425Sroot char *dp; 91425Sroot { 101425Sroot register i; 111425Sroot 12*4774Smckusic for(i=0; i<TP_BSIZE; i++) 131425Sroot tblock[trecno][i] = *dp++; 141425Sroot trecno++; 151425Sroot spcl.c_tapea++; 161425Sroot if(trecno >= NTREC) 171425Sroot flusht(); 181425Sroot } 191425Sroot 20*4774Smckusic dmpblk(blkno, size) 21*4774Smckusic daddr_t blkno; 22*4774Smckusic int size; 231425Sroot { 24*4774Smckusic int avail, blks; 251425Sroot 26*4774Smckusic if (size % FRAG != 0) 27*4774Smckusic msg("bad size to dmpblk: %d\n", size); 28*4774Smckusic avail = NTREC - trecno; 29*4774Smckusic for (blks = size / TP_BSIZE; blks > avail; ) { 30*4774Smckusic bread(blkno, tblock[trecno], TP_BSIZE * avail); 31*4774Smckusic trecno += avail; 32*4774Smckusic spcl.c_tapea += avail; 33*4774Smckusic flusht(); 34*4774Smckusic blkno += avail; 35*4774Smckusic blks -= avail; 36*4774Smckusic avail = NTREC - trecno; 37*4774Smckusic } 38*4774Smckusic bread(blkno, tblock[trecno], TP_BSIZE * blks); 39*4774Smckusic trecno += blks; 40*4774Smckusic spcl.c_tapea += blks; 411425Sroot if(trecno >= NTREC) 421425Sroot flusht(); 431425Sroot } 441425Sroot 451425Sroot int nogripe = 0; 461425Sroot 471425Sroot flusht() 481425Sroot { 491425Sroot register i, si; 501425Sroot daddr_t d; 511425Sroot 521425Sroot trecno = 0; 531425Sroot if (write(to, tblock[0], sizeof(tblock)) != sizeof(tblock) ){ 541425Sroot msg("Tape write error on tape %d\n", tapeno); 551425Sroot broadcast("TAPE ERROR!\n"); 561425Sroot if (query("Do you want to restart?")){ 571425Sroot msg("This tape will rewind. After it is rewound,\n"); 581425Sroot msg("replace the faulty tape with a new one;\n"); 591925Swnj msg("this dump volume will be rewritten.\n"); 601425Sroot /* 611425Sroot * Temporarily change the tapeno identification 621425Sroot */ 631425Sroot tapeno--; 641425Sroot nogripe = 1; 651425Sroot close_rewind(); 661425Sroot nogripe = 0; 671425Sroot tapeno++; 681425Sroot Exit(X_REWRITE); 691425Sroot } else { 701425Sroot dumpabort(); 711425Sroot /*NOTREACHED*/ 721425Sroot } 731425Sroot } 741425Sroot 751425Sroot asize += sizeof(tblock)/density; 761425Sroot asize += 7; 771425Sroot blockswritten += NTREC; 781425Sroot if (asize > tsize) { 791425Sroot close_rewind(); 801425Sroot otape(); 811425Sroot } 821425Sroot timeest(); 831425Sroot } 841425Sroot 851425Sroot rewind() 861425Sroot { 871425Sroot int secs; 883214Swnj int f; 891425Sroot #ifdef DEBUG 901425Sroot msg("Waiting 10 seconds to rewind.\n"); 911425Sroot sleep(10); 921425Sroot #else 931425Sroot /* 941425Sroot * It takes about 3 minutes, 25secs to rewind 2300' of tape 951425Sroot */ 963214Swnj msg("Tape rewinding\n", secs); 973214Swnj close(to); 983214Swnj while ((f = open(tape, 0)) < 0) 993214Swnj sleep (10); 1003214Swnj close(f); 1011425Sroot #endif 1021425Sroot } 1031425Sroot 1041425Sroot close_rewind() 1051425Sroot { 1061425Sroot close(to); 1071425Sroot if (!nogripe){ 1081425Sroot rewind(); 1091425Sroot msg("Change Tapes: Mount tape #%d\n", tapeno+1); 1101425Sroot broadcast("CHANGE TAPES!\7\7\n"); 1111425Sroot } 1121425Sroot do{ 1131425Sroot if (query ("Is the new tape mounted and ready to go?")) 1141425Sroot break; 1151425Sroot if (query ("Do you want to abort?")){ 1161425Sroot dumpabort(); 1171425Sroot /*NOTREACHED*/ 1181425Sroot } 1191425Sroot } while (1); 1201425Sroot } 1211425Sroot 1221425Sroot /* 1231425Sroot * We implement taking and restoring checkpoints on 1241425Sroot * the tape level. 1251425Sroot * When each tape is opened, a new process is created by forking; this 1261425Sroot * saves all of the necessary context in the parent. The child 1271425Sroot * continues the dump; the parent waits around, saving the context. 1281425Sroot * If the child returns X_REWRITE, then it had problems writing that tape; 1291425Sroot * this causes the parent to fork again, duplicating the context, and 1301425Sroot * everything continues as if nothing had happened. 1311425Sroot */ 1321425Sroot 1331425Sroot otape() 1341425Sroot { 1351425Sroot int parentpid; 1361425Sroot int childpid; 1371425Sroot int status; 1381425Sroot int waitpid; 1391425Sroot int sig_ign_parent(); 1401425Sroot int interrupt(); 1411425Sroot 1421425Sroot /* 1431425Sroot * Force the tape to be closed 1441425Sroot */ 1451425Sroot close(to); 1461425Sroot parentpid = getpid(); 1471425Sroot 1481425Sroot restore_check_point: 1491425Sroot signal(SIGINT, interrupt); 1501425Sroot /* 1511425Sroot * All signals are inherited... 1521425Sroot */ 1531425Sroot childpid = fork(); 1541425Sroot if (childpid < 0){ 1551425Sroot msg("Context save fork fails in parent %d\n", parentpid); 1561425Sroot Exit(X_ABORT); 1571425Sroot } 1581425Sroot if (childpid != 0){ 1591425Sroot /* 1601425Sroot * PARENT: 1611425Sroot * save the context by waiting 1621425Sroot * until the child doing all of the work returns. 1631425Sroot * don't catch the interrupt 1641425Sroot */ 1651425Sroot signal(SIGINT, SIG_IGN); 1661425Sroot #ifdef TDEBUG 1671425Sroot msg("Tape: %d; parent process: %d child process %d\n", 1681425Sroot tapeno+1, parentpid, childpid); 1691425Sroot #endif TDEBUG 1701425Sroot for (;;){ 1711425Sroot waitpid = wait(&status); 1721425Sroot if (waitpid != childpid){ 1731425Sroot msg("Parent %d waiting for child %d has another child %d return\n", 1741425Sroot parentpid, childpid, waitpid); 1751425Sroot } else 1761425Sroot break; 1771425Sroot } 1781425Sroot if (status & 0xFF){ 1791425Sroot msg("Child %d returns LOB status %o\n", 1801425Sroot childpid, status&0xFF); 1811425Sroot } 1821425Sroot status = (status >> 8) & 0xFF; 1831425Sroot #ifdef TDEBUG 1841425Sroot switch(status){ 1851425Sroot case X_FINOK: 1861425Sroot msg("Child %d finishes X_FINOK\n", childpid); 1871425Sroot break; 1881425Sroot case X_ABORT: 1891425Sroot msg("Child %d finishes X_ABORT\n", childpid); 1901425Sroot break; 1911425Sroot case X_REWRITE: 1921425Sroot msg("Child %d finishes X_REWRITE\n", childpid); 1931425Sroot break; 1941425Sroot default: 1951425Sroot msg("Child %d finishes unknown %d\n", childpid,status); 1961425Sroot break; 1971425Sroot } 1981425Sroot #endif TDEBUG 1991425Sroot switch(status){ 2001425Sroot case X_FINOK: 2011425Sroot Exit(X_FINOK); 2021425Sroot case X_ABORT: 2031425Sroot Exit(X_ABORT); 2041425Sroot case X_REWRITE: 2051425Sroot goto restore_check_point; 2061425Sroot default: 2071425Sroot msg("Bad return code from dump: %d\n", status); 2081425Sroot Exit(X_ABORT); 2091425Sroot } 2101425Sroot /*NOTREACHED*/ 2111425Sroot } else { /* we are the child; just continue */ 2121425Sroot #ifdef TDEBUG 2131425Sroot sleep(4); /* allow time for parent's message to get out */ 2141425Sroot msg("Child on Tape %d has parent %d, my pid = %d\n", 2151425Sroot tapeno+1, parentpid, getpid()); 2161425Sroot #endif 2171425Sroot do{ 2181425Sroot to = creat(tape, 0666); 2191425Sroot if (to < 0) { 2201425Sroot if (!query("Cannot open tape. Do you want to retry the open?")) 2211425Sroot dumpabort(); 2221425Sroot } else break; 2231425Sroot } while (1); 2241425Sroot 2251425Sroot asize = 0; 2261425Sroot tapeno++; /* current tape sequence */ 2271425Sroot newtape++; /* new tape signal */ 2281425Sroot spcl.c_volume++; 2291425Sroot spcl.c_type = TS_TAPE; 2301425Sroot spclrec(); 2311425Sroot if (tapeno > 1) 2321425Sroot msg("Tape %d begins with blocks from ino %d\n", 2331425Sroot tapeno, ino); 2341425Sroot } 2351425Sroot } 2361425Sroot 2371425Sroot /* 2381425Sroot * The parent still catches interrupts, but does nothing with them 2391425Sroot */ 2401425Sroot sig_ign_parent() 2411425Sroot { 2421425Sroot msg("Waiting parent receives interrupt\n"); 2431425Sroot signal(SIGINT, sig_ign_parent); 2441425Sroot } 2451425Sroot 2461425Sroot dumpabort() 2471425Sroot { 2481925Swnj msg("The ENTIRE dump is aborted.\n"); 2491425Sroot Exit(X_ABORT); 2501425Sroot } 2511425Sroot 2521425Sroot Exit(status) 2531425Sroot { 2541425Sroot #ifdef TDEBUG 2551425Sroot msg("pid = %d exits with status %d\n", getpid(), status); 2561425Sroot #endif TDEBUG 2571925Swnj exit(status); 2581425Sroot } 259