xref: /original-bsd/old/dump.4.1/dumptape.c (revision 0fc6f013)
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) 06/05/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 }
283