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