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