1 static char *sccsid = "@(#)tape.c 1.3 (Berkeley) 03/11/81"; 2 #include "dump.h" 3 4 char tblock[NTREC][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<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], 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 secs; 94 int f; 95 #ifdef DEBUG 96 msg("Waiting 10 seconds to rewind.\n"); 97 sleep(10); 98 #else 99 /* 100 * It takes about 3 minutes, 25secs to rewind 2300' of tape 101 */ 102 msg("Tape rewinding\n", secs); 103 close(to); 104 while ((f = open(tape, 0)) < 0) 105 sleep (10); 106 close(f); 107 #endif 108 } 109 110 close_rewind() 111 { 112 close(to); 113 if (!nogripe){ 114 rewind(); 115 msg("Change Tapes: Mount tape #%d\n", tapeno+1); 116 broadcast("CHANGE TAPES!\7\7\n"); 117 } 118 do{ 119 if (query ("Is the new tape mounted and ready to go?")) 120 break; 121 if (query ("Do you want to abort?")){ 122 dumpabort(); 123 /*NOTREACHED*/ 124 } 125 } while (1); 126 } 127 128 /* 129 * We implement taking and restoring checkpoints on 130 * the tape level. 131 * When each tape is opened, a new process is created by forking; this 132 * saves all of the necessary context in the parent. The child 133 * continues the dump; the parent waits around, saving the context. 134 * If the child returns X_REWRITE, then it had problems writing that tape; 135 * this causes the parent to fork again, duplicating the context, and 136 * everything continues as if nothing had happened. 137 */ 138 139 otape() 140 { 141 int parentpid; 142 int childpid; 143 int status; 144 int waitpid; 145 int sig_ign_parent(); 146 int interrupt(); 147 148 /* 149 * Force the tape to be closed 150 */ 151 close(to); 152 parentpid = getpid(); 153 154 restore_check_point: 155 signal(SIGINT, interrupt); 156 /* 157 * All signals are inherited... 158 */ 159 childpid = fork(); 160 if (childpid < 0){ 161 msg("Context save fork fails in parent %d\n", parentpid); 162 Exit(X_ABORT); 163 } 164 if (childpid != 0){ 165 /* 166 * PARENT: 167 * save the context by waiting 168 * until the child doing all of the work returns. 169 * don't catch the interrupt 170 */ 171 signal(SIGINT, SIG_IGN); 172 #ifdef TDEBUG 173 msg("Tape: %d; parent process: %d child process %d\n", 174 tapeno+1, parentpid, childpid); 175 #endif TDEBUG 176 for (;;){ 177 waitpid = wait(&status); 178 if (waitpid != childpid){ 179 msg("Parent %d waiting for child %d has another child %d return\n", 180 parentpid, childpid, waitpid); 181 } else 182 break; 183 } 184 if (status & 0xFF){ 185 msg("Child %d returns LOB status %o\n", 186 childpid, status&0xFF); 187 } 188 status = (status >> 8) & 0xFF; 189 #ifdef TDEBUG 190 switch(status){ 191 case X_FINOK: 192 msg("Child %d finishes X_FINOK\n", childpid); 193 break; 194 case X_ABORT: 195 msg("Child %d finishes X_ABORT\n", childpid); 196 break; 197 case X_REWRITE: 198 msg("Child %d finishes X_REWRITE\n", childpid); 199 break; 200 default: 201 msg("Child %d finishes unknown %d\n", childpid,status); 202 break; 203 } 204 #endif TDEBUG 205 switch(status){ 206 case X_FINOK: 207 Exit(X_FINOK); 208 case X_ABORT: 209 Exit(X_ABORT); 210 case X_REWRITE: 211 goto restore_check_point; 212 default: 213 msg("Bad return code from dump: %d\n", status); 214 Exit(X_ABORT); 215 } 216 /*NOTREACHED*/ 217 } else { /* we are the child; just continue */ 218 #ifdef TDEBUG 219 sleep(4); /* allow time for parent's message to get out */ 220 msg("Child on Tape %d has parent %d, my pid = %d\n", 221 tapeno+1, parentpid, getpid()); 222 #endif 223 do{ 224 to = creat(tape, 0666); 225 if (to < 0) { 226 if (!query("Cannot open tape. Do you want to retry the open?")) 227 dumpabort(); 228 } else break; 229 } while (1); 230 231 asize = 0; 232 tapeno++; /* current tape sequence */ 233 newtape++; /* new tape signal */ 234 spcl.c_volume++; 235 spcl.c_type = TS_TAPE; 236 spclrec(); 237 if (tapeno > 1) 238 msg("Tape %d begins with blocks from ino %d\n", 239 tapeno, ino); 240 } 241 } 242 243 /* 244 * The parent still catches interrupts, but does nothing with them 245 */ 246 sig_ign_parent() 247 { 248 msg("Waiting parent receives interrupt\n"); 249 signal(SIGINT, sig_ign_parent); 250 } 251 252 dumpabort() 253 { 254 msg("The ENTIRE dump is aborted.\n"); 255 Exit(X_ABORT); 256 } 257 258 Exit(status) 259 { 260 #ifdef TDEBUG 261 msg("pid = %d exits with status %d\n", getpid(), status); 262 #endif TDEBUG 263 exit(status); 264 } 265