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