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