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