1*1425Sroot static char *sccsid = "@(#)tape.c 1.1 (Berkeley) 10/13/80"; 2*1425Sroot #include "dump.h" 3*1425Sroot 4*1425Sroot char tblock[NTREC][BSIZE]; 5*1425Sroot daddr_t tdaddr[NTREC]; 6*1425Sroot int trecno; 7*1425Sroot 8*1425Sroot taprec(dp) 9*1425Sroot char *dp; 10*1425Sroot { 11*1425Sroot register i; 12*1425Sroot 13*1425Sroot for(i=0; i<BSIZE; i++) 14*1425Sroot tblock[trecno][i] = *dp++; 15*1425Sroot tdaddr[trecno] = 0; 16*1425Sroot trecno++; 17*1425Sroot spcl.c_tapea++; 18*1425Sroot if(trecno >= NTREC) 19*1425Sroot flusht(); 20*1425Sroot } 21*1425Sroot 22*1425Sroot tapsrec(d) 23*1425Sroot daddr_t d; 24*1425Sroot { 25*1425Sroot 26*1425Sroot if(d == 0) 27*1425Sroot return; 28*1425Sroot tdaddr[trecno] = d; 29*1425Sroot trecno++; 30*1425Sroot spcl.c_tapea++; 31*1425Sroot if(trecno >= NTREC) 32*1425Sroot flusht(); 33*1425Sroot } 34*1425Sroot 35*1425Sroot int nogripe = 0; 36*1425Sroot 37*1425Sroot flusht() 38*1425Sroot { 39*1425Sroot register i, si; 40*1425Sroot daddr_t d; 41*1425Sroot 42*1425Sroot while(trecno < NTREC) 43*1425Sroot tdaddr[trecno++] = 1; 44*1425Sroot 45*1425Sroot loop: 46*1425Sroot d = 0; 47*1425Sroot for(i=0; i<NTREC; i++) 48*1425Sroot if(tdaddr[i] != 0) 49*1425Sroot if(d == 0 || tdaddr[i] < d) { 50*1425Sroot si = i; 51*1425Sroot d = tdaddr[i]; 52*1425Sroot } 53*1425Sroot if(d != 0) { 54*1425Sroot bread(d, tblock[si], BSIZE); 55*1425Sroot tdaddr[si] = 0; 56*1425Sroot goto loop; 57*1425Sroot } 58*1425Sroot trecno = 0; 59*1425Sroot if (write(to, tblock[0], sizeof(tblock)) != sizeof(tblock) ){ 60*1425Sroot msg("Tape write error on tape %d\n", tapeno); 61*1425Sroot broadcast("TAPE ERROR!\n"); 62*1425Sroot if (query("Do you want to restart?")){ 63*1425Sroot msg("This tape will rewind. After it is rewound,\n"); 64*1425Sroot msg("replace the faulty tape with a new one;\n"); 65*1425Sroot msg("this dump volumne will be rewritten.\n"); 66*1425Sroot /* 67*1425Sroot * Temporarily change the tapeno identification 68*1425Sroot */ 69*1425Sroot tapeno--; 70*1425Sroot nogripe = 1; 71*1425Sroot close_rewind(); 72*1425Sroot nogripe = 0; 73*1425Sroot tapeno++; 74*1425Sroot Exit(X_REWRITE); 75*1425Sroot } else { 76*1425Sroot dumpabort(); 77*1425Sroot /*NOTREACHED*/ 78*1425Sroot } 79*1425Sroot } 80*1425Sroot 81*1425Sroot asize += sizeof(tblock)/density; 82*1425Sroot asize += 7; 83*1425Sroot blockswritten += NTREC; 84*1425Sroot if (asize > tsize) { 85*1425Sroot close_rewind(); 86*1425Sroot otape(); 87*1425Sroot } 88*1425Sroot timeest(); 89*1425Sroot } 90*1425Sroot 91*1425Sroot rewind() 92*1425Sroot { 93*1425Sroot int secs; 94*1425Sroot #ifdef DEBUG 95*1425Sroot msg("Waiting 10 seconds to rewind.\n"); 96*1425Sroot sleep(10); 97*1425Sroot #else 98*1425Sroot /* 99*1425Sroot * It takes about 3 minutes, 25secs to rewind 2300' of tape 100*1425Sroot */ 101*1425Sroot secs = (( (60*3) + 25)*asize)/(2300L*12L*10L); 102*1425Sroot msg("Waiting %d seconds to rewind.\n", secs); 103*1425Sroot sleep(secs); 104*1425Sroot #endif 105*1425Sroot } 106*1425Sroot 107*1425Sroot close_rewind() 108*1425Sroot { 109*1425Sroot close(to); 110*1425Sroot if (!nogripe){ 111*1425Sroot rewind(); 112*1425Sroot msg("Change Tapes: Mount tape #%d\n", tapeno+1); 113*1425Sroot broadcast("CHANGE TAPES!\7\7\n"); 114*1425Sroot } 115*1425Sroot do{ 116*1425Sroot if (query ("Is the new tape mounted and ready to go?")) 117*1425Sroot break; 118*1425Sroot if (query ("Do you want to abort?")){ 119*1425Sroot dumpabort(); 120*1425Sroot /*NOTREACHED*/ 121*1425Sroot } 122*1425Sroot } while (1); 123*1425Sroot } 124*1425Sroot 125*1425Sroot /* 126*1425Sroot * We implement taking and restoring checkpoints on 127*1425Sroot * the tape level. 128*1425Sroot * When each tape is opened, a new process is created by forking; this 129*1425Sroot * saves all of the necessary context in the parent. The child 130*1425Sroot * continues the dump; the parent waits around, saving the context. 131*1425Sroot * If the child returns X_REWRITE, then it had problems writing that tape; 132*1425Sroot * this causes the parent to fork again, duplicating the context, and 133*1425Sroot * everything continues as if nothing had happened. 134*1425Sroot */ 135*1425Sroot 136*1425Sroot otape() 137*1425Sroot { 138*1425Sroot int parentpid; 139*1425Sroot int childpid; 140*1425Sroot int status; 141*1425Sroot int waitpid; 142*1425Sroot int sig_ign_parent(); 143*1425Sroot int interrupt(); 144*1425Sroot 145*1425Sroot /* 146*1425Sroot * Force the tape to be closed 147*1425Sroot */ 148*1425Sroot close(to); 149*1425Sroot parentpid = getpid(); 150*1425Sroot 151*1425Sroot restore_check_point: 152*1425Sroot signal(SIGINT, interrupt); 153*1425Sroot /* 154*1425Sroot * All signals are inherited... 155*1425Sroot */ 156*1425Sroot childpid = fork(); 157*1425Sroot if (childpid < 0){ 158*1425Sroot msg("Context save fork fails in parent %d\n", parentpid); 159*1425Sroot Exit(X_ABORT); 160*1425Sroot } 161*1425Sroot if (childpid != 0){ 162*1425Sroot /* 163*1425Sroot * PARENT: 164*1425Sroot * save the context by waiting 165*1425Sroot * until the child doing all of the work returns. 166*1425Sroot * don't catch the interrupt 167*1425Sroot */ 168*1425Sroot signal(SIGINT, SIG_IGN); 169*1425Sroot #ifdef TDEBUG 170*1425Sroot msg("Tape: %d; parent process: %d child process %d\n", 171*1425Sroot tapeno+1, parentpid, childpid); 172*1425Sroot #endif TDEBUG 173*1425Sroot for (;;){ 174*1425Sroot waitpid = wait(&status); 175*1425Sroot if (waitpid != childpid){ 176*1425Sroot msg("Parent %d waiting for child %d has another child %d return\n", 177*1425Sroot parentpid, childpid, waitpid); 178*1425Sroot } else 179*1425Sroot break; 180*1425Sroot } 181*1425Sroot if (status & 0xFF){ 182*1425Sroot msg("Child %d returns LOB status %o\n", 183*1425Sroot childpid, status&0xFF); 184*1425Sroot } 185*1425Sroot status = (status >> 8) & 0xFF; 186*1425Sroot #ifdef TDEBUG 187*1425Sroot switch(status){ 188*1425Sroot case X_FINOK: 189*1425Sroot msg("Child %d finishes X_FINOK\n", childpid); 190*1425Sroot break; 191*1425Sroot case X_ABORT: 192*1425Sroot msg("Child %d finishes X_ABORT\n", childpid); 193*1425Sroot break; 194*1425Sroot case X_REWRITE: 195*1425Sroot msg("Child %d finishes X_REWRITE\n", childpid); 196*1425Sroot break; 197*1425Sroot default: 198*1425Sroot msg("Child %d finishes unknown %d\n", childpid,status); 199*1425Sroot break; 200*1425Sroot } 201*1425Sroot #endif TDEBUG 202*1425Sroot switch(status){ 203*1425Sroot case X_FINOK: 204*1425Sroot Exit(X_FINOK); 205*1425Sroot case X_ABORT: 206*1425Sroot Exit(X_ABORT); 207*1425Sroot case X_REWRITE: 208*1425Sroot goto restore_check_point; 209*1425Sroot default: 210*1425Sroot msg("Bad return code from dump: %d\n", status); 211*1425Sroot Exit(X_ABORT); 212*1425Sroot } 213*1425Sroot /*NOTREACHED*/ 214*1425Sroot } else { /* we are the child; just continue */ 215*1425Sroot #ifdef TDEBUG 216*1425Sroot sleep(4); /* allow time for parent's message to get out */ 217*1425Sroot msg("Child on Tape %d has parent %d, my pid = %d\n", 218*1425Sroot tapeno+1, parentpid, getpid()); 219*1425Sroot #endif 220*1425Sroot do{ 221*1425Sroot to = creat(tape, 0666); 222*1425Sroot if (to < 0) { 223*1425Sroot if (!query("Cannot open tape. Do you want to retry the open?")) 224*1425Sroot dumpabort(); 225*1425Sroot } else break; 226*1425Sroot } while (1); 227*1425Sroot 228*1425Sroot asize = 0; 229*1425Sroot tapeno++; /* current tape sequence */ 230*1425Sroot newtape++; /* new tape signal */ 231*1425Sroot spcl.c_volume++; 232*1425Sroot spcl.c_type = TS_TAPE; 233*1425Sroot spclrec(); 234*1425Sroot if (tapeno > 1) 235*1425Sroot msg("Tape %d begins with blocks from ino %d\n", 236*1425Sroot tapeno, ino); 237*1425Sroot } 238*1425Sroot } 239*1425Sroot 240*1425Sroot /* 241*1425Sroot * The parent still catches interrupts, but does nothing with them 242*1425Sroot */ 243*1425Sroot sig_ign_parent() 244*1425Sroot { 245*1425Sroot msg("Waiting parent receives interrupt\n"); 246*1425Sroot signal(SIGINT, sig_ign_parent); 247*1425Sroot } 248*1425Sroot 249*1425Sroot dumpabort() 250*1425Sroot { 251*1425Sroot msg("The ENTIRE dump is aborted. NO second chances (tough luck sucker).\n"); 252*1425Sroot Exit(X_ABORT); 253*1425Sroot } 254*1425Sroot 255*1425Sroot Exit(status) 256*1425Sroot { 257*1425Sroot #ifdef TDEBUG 258*1425Sroot msg("pid = %d exits with status %d\n", getpid(), status); 259*1425Sroot #endif TDEBUG 260*1425Sroot henryexit(status); 261*1425Sroot } 262*1425Sroot 263*1425Sroot #ifdef TDEBUG 264*1425Sroot exit(status) 265*1425Sroot /*ARGSUSED*/ 266*1425Sroot { 267*1425Sroot fflush(stdout); 268*1425Sroot fprintf(stderr, "Somebody called exit: halt executed\n"); 269*1425Sroot fflush(stderr); 270*1425Sroot abort(); 271*1425Sroot } 272*1425Sroot 273*1425Sroot _exit(status) 274*1425Sroot /*ARGSUSED*/ 275*1425Sroot { 276*1425Sroot fflush(stdout); 277*1425Sroot fprintf(stderr, "Somebody called _exit: halt executed\n"); 278*1425Sroot fflush(stderr); 279*1425Sroot abort(); 280*1425Sroot } 281*1425Sroot #endif TDEBUG 282*1425Sroot 283*1425Sroot henryexit(status) 284*1425Sroot /* ARGSUSED */ 285*1425Sroot { 286*1425Sroot _cleanup(); 287*1425Sroot asm(" chmk $1"); 288*1425Sroot asm("halt"); 289*1425Sroot } 290