1*12082Smckusick static char *sccsid = "@(#)dumptape.c 1.3 (Berkeley) 04/28/83"; 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) ){ 60*12082Smckusick if (pipeout) { 61*12082Smckusick msg("Tape write error on %s\n", tape); 62*12082Smckusick msg("Cannot recover\n"); 63*12082Smckusick dumpabort(); 64*12082Smckusick /*NOTREACHED*/ 65*12082Smckusick } 661425Sroot msg("Tape write error on tape %d\n", tapeno); 671425Sroot broadcast("TAPE ERROR!\n"); 681425Sroot if (query("Do you want to restart?")){ 691425Sroot msg("This tape will rewind. After it is rewound,\n"); 701425Sroot msg("replace the faulty tape with a new one;\n"); 711925Swnj msg("this dump volume will be rewritten.\n"); 721425Sroot /* 731425Sroot * Temporarily change the tapeno identification 741425Sroot */ 751425Sroot tapeno--; 761425Sroot nogripe = 1; 771425Sroot close_rewind(); 781425Sroot nogripe = 0; 791425Sroot tapeno++; 801425Sroot Exit(X_REWRITE); 811425Sroot } else { 821425Sroot dumpabort(); 831425Sroot /*NOTREACHED*/ 841425Sroot } 851425Sroot } 861425Sroot 871425Sroot asize += sizeof(tblock)/density; 881425Sroot asize += 7; 891425Sroot blockswritten += NTREC; 90*12082Smckusick if (!pipeout && asize > tsize) { 911425Sroot close_rewind(); 921425Sroot otape(); 931425Sroot } 941425Sroot timeest(); 951425Sroot } 961425Sroot 971425Sroot rewind() 981425Sroot { 991425Sroot int secs; 1001425Sroot #ifdef DEBUG 1011425Sroot msg("Waiting 10 seconds to rewind.\n"); 1021425Sroot sleep(10); 1031425Sroot #else 1041425Sroot /* 1051425Sroot * It takes about 3 minutes, 25secs to rewind 2300' of tape 1061425Sroot */ 1071425Sroot secs = (( (60*3) + 25)*asize)/(2300L*12L*10L); 1081425Sroot msg("Waiting %d seconds to rewind.\n", secs); 1091425Sroot sleep(secs); 1101425Sroot #endif 1111425Sroot } 1121425Sroot 1131425Sroot close_rewind() 1141425Sroot { 115*12082Smckusick if (pipeout) 116*12082Smckusick return; 1171425Sroot close(to); 1181425Sroot if (!nogripe){ 1191425Sroot rewind(); 1201425Sroot msg("Change Tapes: Mount tape #%d\n", tapeno+1); 1211425Sroot broadcast("CHANGE TAPES!\7\7\n"); 1221425Sroot } 1231425Sroot do{ 1241425Sroot if (query ("Is the new tape mounted and ready to go?")) 1251425Sroot break; 1261425Sroot if (query ("Do you want to abort?")){ 1271425Sroot dumpabort(); 1281425Sroot /*NOTREACHED*/ 1291425Sroot } 1301425Sroot } while (1); 1311425Sroot } 1321425Sroot 1331425Sroot /* 1341425Sroot * We implement taking and restoring checkpoints on 1351425Sroot * the tape level. 1361425Sroot * When each tape is opened, a new process is created by forking; this 1371425Sroot * saves all of the necessary context in the parent. The child 1381425Sroot * continues the dump; the parent waits around, saving the context. 1391425Sroot * If the child returns X_REWRITE, then it had problems writing that tape; 1401425Sroot * this causes the parent to fork again, duplicating the context, and 1411425Sroot * everything continues as if nothing had happened. 1421425Sroot */ 1431425Sroot 1441425Sroot otape() 1451425Sroot { 1461425Sroot int parentpid; 1471425Sroot int childpid; 1481425Sroot int status; 1491425Sroot int waitpid; 1501425Sroot int sig_ign_parent(); 1511425Sroot int interrupt(); 1521425Sroot 1531425Sroot /* 1541425Sroot * Force the tape to be closed 1551425Sroot */ 156*12082Smckusick if (!pipeout) 157*12082Smckusick close(to); 1581425Sroot parentpid = getpid(); 1591425Sroot 1601425Sroot restore_check_point: 1611425Sroot signal(SIGINT, interrupt); 1621425Sroot /* 1631425Sroot * All signals are inherited... 1641425Sroot */ 1651425Sroot childpid = fork(); 1661425Sroot if (childpid < 0){ 1671425Sroot msg("Context save fork fails in parent %d\n", parentpid); 1681425Sroot Exit(X_ABORT); 1691425Sroot } 1701425Sroot if (childpid != 0){ 1711425Sroot /* 1721425Sroot * PARENT: 1731425Sroot * save the context by waiting 1741425Sroot * until the child doing all of the work returns. 1751425Sroot * don't catch the interrupt 1761425Sroot */ 1771425Sroot signal(SIGINT, SIG_IGN); 1781425Sroot #ifdef TDEBUG 1791425Sroot msg("Tape: %d; parent process: %d child process %d\n", 1801425Sroot tapeno+1, parentpid, childpid); 1811425Sroot #endif TDEBUG 1821425Sroot for (;;){ 1831425Sroot waitpid = wait(&status); 1841425Sroot if (waitpid != childpid){ 1851425Sroot msg("Parent %d waiting for child %d has another child %d return\n", 1861425Sroot parentpid, childpid, waitpid); 1871425Sroot } else 1881425Sroot break; 1891425Sroot } 1901425Sroot if (status & 0xFF){ 1911425Sroot msg("Child %d returns LOB status %o\n", 1921425Sroot childpid, status&0xFF); 1931425Sroot } 1941425Sroot status = (status >> 8) & 0xFF; 1951425Sroot #ifdef TDEBUG 1961425Sroot switch(status){ 1971425Sroot case X_FINOK: 1981425Sroot msg("Child %d finishes X_FINOK\n", childpid); 1991425Sroot break; 2001425Sroot case X_ABORT: 2011425Sroot msg("Child %d finishes X_ABORT\n", childpid); 2021425Sroot break; 2031425Sroot case X_REWRITE: 2041425Sroot msg("Child %d finishes X_REWRITE\n", childpid); 2051425Sroot break; 2061425Sroot default: 2071425Sroot msg("Child %d finishes unknown %d\n", childpid,status); 2081425Sroot break; 2091425Sroot } 2101425Sroot #endif TDEBUG 2111425Sroot switch(status){ 2121425Sroot case X_FINOK: 2131425Sroot Exit(X_FINOK); 2141425Sroot case X_ABORT: 2151425Sroot Exit(X_ABORT); 2161425Sroot case X_REWRITE: 2171425Sroot goto restore_check_point; 2181425Sroot default: 2191425Sroot msg("Bad return code from dump: %d\n", status); 2201425Sroot Exit(X_ABORT); 2211425Sroot } 2221425Sroot /*NOTREACHED*/ 2231425Sroot } else { /* we are the child; just continue */ 2241425Sroot #ifdef TDEBUG 2251425Sroot sleep(4); /* allow time for parent's message to get out */ 2261425Sroot msg("Child on Tape %d has parent %d, my pid = %d\n", 2271425Sroot tapeno+1, parentpid, getpid()); 2281425Sroot #endif 2291425Sroot do{ 230*12082Smckusick if (pipeout) 231*12082Smckusick to = 1; 232*12082Smckusick else 233*12082Smckusick to = creat(tape, 0666); 2341425Sroot if (to < 0) { 2351425Sroot if (!query("Cannot open tape. Do you want to retry the open?")) 2361425Sroot dumpabort(); 2371425Sroot } else break; 2381425Sroot } while (1); 2391425Sroot 2401425Sroot asize = 0; 2411425Sroot tapeno++; /* current tape sequence */ 2421425Sroot newtape++; /* new tape signal */ 2431425Sroot spcl.c_volume++; 2441425Sroot spcl.c_type = TS_TAPE; 2451425Sroot spclrec(); 2461425Sroot if (tapeno > 1) 2471425Sroot msg("Tape %d begins with blocks from ino %d\n", 2481425Sroot tapeno, ino); 2491425Sroot } 2501425Sroot } 2511425Sroot 2521425Sroot /* 2531425Sroot * The parent still catches interrupts, but does nothing with them 2541425Sroot */ 2551425Sroot sig_ign_parent() 2561425Sroot { 2571425Sroot msg("Waiting parent receives interrupt\n"); 2581425Sroot signal(SIGINT, sig_ign_parent); 2591425Sroot } 2601425Sroot 2611425Sroot dumpabort() 2621425Sroot { 2631925Swnj msg("The ENTIRE dump is aborted.\n"); 2641425Sroot Exit(X_ABORT); 2651425Sroot } 2661425Sroot 2671425Sroot Exit(status) 2681425Sroot { 2691425Sroot #ifdef TDEBUG 2701425Sroot msg("pid = %d exits with status %d\n", getpid(), status); 2711425Sroot #endif TDEBUG 2721925Swnj exit(status); 2731425Sroot } 274