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