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