|
|
1.1 root 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) 6/5/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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.