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