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