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