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