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