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