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