Commit | Line | Data |
---|---|---|
76797561 DF |
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) %G%"; | |
9 | #endif not lint | |
10 | ||
ae4b153c BJ |
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) ){ | |
2a729b17 KM |
69 | if (pipeout) { |
70 | msg("Tape write error on %s\n", tape); | |
71 | msg("Cannot recover\n"); | |
72 | dumpabort(); | |
73 | /*NOTREACHED*/ | |
74 | } | |
ae4b153c BJ |
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"); | |
ed7c701e | 80 | msg("this dump volume will be rewritten.\n"); |
ae4b153c BJ |
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; | |
2a729b17 | 99 | if (!pipeout && asize > tsize) { |
ae4b153c BJ |
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 | { | |
2a729b17 KM |
124 | if (pipeout) |
125 | return; | |
ae4b153c BJ |
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 | */ | |
2a729b17 KM |
165 | if (!pipeout) |
166 | close(to); | |
ae4b153c BJ |
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{ | |
2a729b17 KM |
239 | if (pipeout) |
240 | to = 1; | |
241 | else | |
242 | to = creat(tape, 0666); | |
ae4b153c BJ |
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 | { | |
ed7c701e | 272 | msg("The ENTIRE dump is aborted.\n"); |
ae4b153c BJ |
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 | |
ed7c701e | 281 | exit(status); |
ae4b153c | 282 | } |