1*1925Swnj static char *sccsid = "@(#)dumptape.c 1.2 (Berkeley) 12/18/80"; 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"); 65*1925Swnj 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; 941425Sroot #ifdef DEBUG 951425Sroot msg("Waiting 10 seconds to rewind.\n"); 961425Sroot sleep(10); 971425Sroot #else 981425Sroot /* 991425Sroot * It takes about 3 minutes, 25secs to rewind 2300' of tape 1001425Sroot */ 1011425Sroot secs = (( (60*3) + 25)*asize)/(2300L*12L*10L); 1021425Sroot msg("Waiting %d seconds to rewind.\n", secs); 1031425Sroot sleep(secs); 1041425Sroot #endif 1051425Sroot } 1061425Sroot 1071425Sroot close_rewind() 1081425Sroot { 1091425Sroot close(to); 1101425Sroot if (!nogripe){ 1111425Sroot rewind(); 1121425Sroot msg("Change Tapes: Mount tape #%d\n", tapeno+1); 1131425Sroot broadcast("CHANGE TAPES!\7\7\n"); 1141425Sroot } 1151425Sroot do{ 1161425Sroot if (query ("Is the new tape mounted and ready to go?")) 1171425Sroot break; 1181425Sroot if (query ("Do you want to abort?")){ 1191425Sroot dumpabort(); 1201425Sroot /*NOTREACHED*/ 1211425Sroot } 1221425Sroot } while (1); 1231425Sroot } 1241425Sroot 1251425Sroot /* 1261425Sroot * We implement taking and restoring checkpoints on 1271425Sroot * the tape level. 1281425Sroot * When each tape is opened, a new process is created by forking; this 1291425Sroot * saves all of the necessary context in the parent. The child 1301425Sroot * continues the dump; the parent waits around, saving the context. 1311425Sroot * If the child returns X_REWRITE, then it had problems writing that tape; 1321425Sroot * this causes the parent to fork again, duplicating the context, and 1331425Sroot * everything continues as if nothing had happened. 1341425Sroot */ 1351425Sroot 1361425Sroot otape() 1371425Sroot { 1381425Sroot int parentpid; 1391425Sroot int childpid; 1401425Sroot int status; 1411425Sroot int waitpid; 1421425Sroot int sig_ign_parent(); 1431425Sroot int interrupt(); 1441425Sroot 1451425Sroot /* 1461425Sroot * Force the tape to be closed 1471425Sroot */ 1481425Sroot close(to); 1491425Sroot parentpid = getpid(); 1501425Sroot 1511425Sroot restore_check_point: 1521425Sroot signal(SIGINT, interrupt); 1531425Sroot /* 1541425Sroot * All signals are inherited... 1551425Sroot */ 1561425Sroot childpid = fork(); 1571425Sroot if (childpid < 0){ 1581425Sroot msg("Context save fork fails in parent %d\n", parentpid); 1591425Sroot Exit(X_ABORT); 1601425Sroot } 1611425Sroot if (childpid != 0){ 1621425Sroot /* 1631425Sroot * PARENT: 1641425Sroot * save the context by waiting 1651425Sroot * until the child doing all of the work returns. 1661425Sroot * don't catch the interrupt 1671425Sroot */ 1681425Sroot signal(SIGINT, SIG_IGN); 1691425Sroot #ifdef TDEBUG 1701425Sroot msg("Tape: %d; parent process: %d child process %d\n", 1711425Sroot tapeno+1, parentpid, childpid); 1721425Sroot #endif TDEBUG 1731425Sroot for (;;){ 1741425Sroot waitpid = wait(&status); 1751425Sroot if (waitpid != childpid){ 1761425Sroot msg("Parent %d waiting for child %d has another child %d return\n", 1771425Sroot parentpid, childpid, waitpid); 1781425Sroot } else 1791425Sroot break; 1801425Sroot } 1811425Sroot if (status & 0xFF){ 1821425Sroot msg("Child %d returns LOB status %o\n", 1831425Sroot childpid, status&0xFF); 1841425Sroot } 1851425Sroot status = (status >> 8) & 0xFF; 1861425Sroot #ifdef TDEBUG 1871425Sroot switch(status){ 1881425Sroot case X_FINOK: 1891425Sroot msg("Child %d finishes X_FINOK\n", childpid); 1901425Sroot break; 1911425Sroot case X_ABORT: 1921425Sroot msg("Child %d finishes X_ABORT\n", childpid); 1931425Sroot break; 1941425Sroot case X_REWRITE: 1951425Sroot msg("Child %d finishes X_REWRITE\n", childpid); 1961425Sroot break; 1971425Sroot default: 1981425Sroot msg("Child %d finishes unknown %d\n", childpid,status); 1991425Sroot break; 2001425Sroot } 2011425Sroot #endif TDEBUG 2021425Sroot switch(status){ 2031425Sroot case X_FINOK: 2041425Sroot Exit(X_FINOK); 2051425Sroot case X_ABORT: 2061425Sroot Exit(X_ABORT); 2071425Sroot case X_REWRITE: 2081425Sroot goto restore_check_point; 2091425Sroot default: 2101425Sroot msg("Bad return code from dump: %d\n", status); 2111425Sroot Exit(X_ABORT); 2121425Sroot } 2131425Sroot /*NOTREACHED*/ 2141425Sroot } else { /* we are the child; just continue */ 2151425Sroot #ifdef TDEBUG 2161425Sroot sleep(4); /* allow time for parent's message to get out */ 2171425Sroot msg("Child on Tape %d has parent %d, my pid = %d\n", 2181425Sroot tapeno+1, parentpid, getpid()); 2191425Sroot #endif 2201425Sroot do{ 2211425Sroot to = creat(tape, 0666); 2221425Sroot if (to < 0) { 2231425Sroot if (!query("Cannot open tape. Do you want to retry the open?")) 2241425Sroot dumpabort(); 2251425Sroot } else break; 2261425Sroot } while (1); 2271425Sroot 2281425Sroot asize = 0; 2291425Sroot tapeno++; /* current tape sequence */ 2301425Sroot newtape++; /* new tape signal */ 2311425Sroot spcl.c_volume++; 2321425Sroot spcl.c_type = TS_TAPE; 2331425Sroot spclrec(); 2341425Sroot if (tapeno > 1) 2351425Sroot msg("Tape %d begins with blocks from ino %d\n", 2361425Sroot tapeno, ino); 2371425Sroot } 2381425Sroot } 2391425Sroot 2401425Sroot /* 2411425Sroot * The parent still catches interrupts, but does nothing with them 2421425Sroot */ 2431425Sroot sig_ign_parent() 2441425Sroot { 2451425Sroot msg("Waiting parent receives interrupt\n"); 2461425Sroot signal(SIGINT, sig_ign_parent); 2471425Sroot } 2481425Sroot 2491425Sroot dumpabort() 2501425Sroot { 251*1925Swnj msg("The ENTIRE dump is aborted.\n"); 2521425Sroot Exit(X_ABORT); 2531425Sroot } 2541425Sroot 2551425Sroot Exit(status) 2561425Sroot { 2571425Sroot #ifdef TDEBUG 2581425Sroot msg("pid = %d exits with status %d\n", getpid(), status); 2591425Sroot #endif TDEBUG 260*1925Swnj exit(status); 2611425Sroot } 262