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) 06/05/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 } 283