xref: /csrg-svn/sbin/dump/tape.c (revision 4774)
1*4774Smckusic static	char *sccsid = "@(#)tape.c	1.4 (Berkeley) 11/07/81";
21425Sroot #include "dump.h"
31425Sroot 
4*4774Smckusic char	tblock[NTREC][TP_BSIZE];
5*4774Smckusic int	trecno = 0;
61425Sroot 
71425Sroot taprec(dp)
81425Sroot char *dp;
91425Sroot {
101425Sroot 	register i;
111425Sroot 
12*4774Smckusic 	for(i=0; i<TP_BSIZE; i++)
131425Sroot 		tblock[trecno][i] = *dp++;
141425Sroot 	trecno++;
151425Sroot 	spcl.c_tapea++;
161425Sroot 	if(trecno >= NTREC)
171425Sroot 		flusht();
181425Sroot }
191425Sroot 
20*4774Smckusic dmpblk(blkno, size)
21*4774Smckusic 	daddr_t blkno;
22*4774Smckusic 	int size;
231425Sroot {
24*4774Smckusic 	int avail, blks;
251425Sroot 
26*4774Smckusic 	if (size % FRAG != 0)
27*4774Smckusic 		msg("bad size to dmpblk: %d\n", size);
28*4774Smckusic 	avail = NTREC - trecno;
29*4774Smckusic 	for (blks = size / TP_BSIZE; blks > avail; ) {
30*4774Smckusic 		bread(blkno, tblock[trecno], TP_BSIZE * avail);
31*4774Smckusic 		trecno += avail;
32*4774Smckusic 		spcl.c_tapea += avail;
33*4774Smckusic 		flusht();
34*4774Smckusic 		blkno += avail;
35*4774Smckusic 		blks -= avail;
36*4774Smckusic 		avail = NTREC - trecno;
37*4774Smckusic 	}
38*4774Smckusic 	bread(blkno, tblock[trecno], TP_BSIZE * blks);
39*4774Smckusic 	trecno += blks;
40*4774Smckusic 	spcl.c_tapea += blks;
411425Sroot 	if(trecno >= NTREC)
421425Sroot 		flusht();
431425Sroot }
441425Sroot 
451425Sroot int	nogripe = 0;
461425Sroot 
471425Sroot flusht()
481425Sroot {
491425Sroot 	register i, si;
501425Sroot 	daddr_t d;
511425Sroot 
521425Sroot 	trecno = 0;
531425Sroot 	if (write(to, tblock[0], sizeof(tblock)) != sizeof(tblock) ){
541425Sroot 		msg("Tape write error on tape %d\n", tapeno);
551425Sroot 		broadcast("TAPE ERROR!\n");
561425Sroot 		if (query("Do you want to restart?")){
571425Sroot 			msg("This tape will rewind.  After it is rewound,\n");
581425Sroot 			msg("replace the faulty tape with a new one;\n");
591925Swnj 			msg("this dump volume will be rewritten.\n");
601425Sroot 			/*
611425Sroot 			 *	Temporarily change the tapeno identification
621425Sroot 			 */
631425Sroot 			tapeno--;
641425Sroot 			nogripe = 1;
651425Sroot 			close_rewind();
661425Sroot 			nogripe = 0;
671425Sroot 			tapeno++;
681425Sroot 			Exit(X_REWRITE);
691425Sroot 		} else {
701425Sroot 			dumpabort();
711425Sroot 			/*NOTREACHED*/
721425Sroot 		}
731425Sroot 	}
741425Sroot 
751425Sroot 	asize += sizeof(tblock)/density;
761425Sroot 	asize += 7;
771425Sroot 	blockswritten += NTREC;
781425Sroot 	if (asize > tsize) {
791425Sroot 		close_rewind();
801425Sroot 		otape();
811425Sroot 	}
821425Sroot 	timeest();
831425Sroot }
841425Sroot 
851425Sroot rewind()
861425Sroot {
871425Sroot 	int	secs;
883214Swnj 	int f;
891425Sroot #ifdef DEBUG
901425Sroot 	msg("Waiting 10 seconds to rewind.\n");
911425Sroot 	sleep(10);
921425Sroot #else
931425Sroot 	/*
941425Sroot 	 *	It takes about 3 minutes, 25secs to rewind 2300' of tape
951425Sroot 	 */
963214Swnj 	msg("Tape rewinding\n", secs);
973214Swnj 	close(to);
983214Swnj 	while ((f = open(tape, 0)) < 0)
993214Swnj 		sleep (10);
1003214Swnj 	close(f);
1011425Sroot #endif
1021425Sroot }
1031425Sroot 
1041425Sroot close_rewind()
1051425Sroot {
1061425Sroot 	close(to);
1071425Sroot 	if (!nogripe){
1081425Sroot 		rewind();
1091425Sroot 		msg("Change Tapes: Mount tape #%d\n", tapeno+1);
1101425Sroot 		broadcast("CHANGE TAPES!\7\7\n");
1111425Sroot 	}
1121425Sroot 	do{
1131425Sroot 		if (query ("Is the new tape mounted and ready to go?"))
1141425Sroot 			break;
1151425Sroot 		if (query ("Do you want to abort?")){
1161425Sroot 			dumpabort();
1171425Sroot 			/*NOTREACHED*/
1181425Sroot 		}
1191425Sroot 	} while (1);
1201425Sroot }
1211425Sroot 
1221425Sroot /*
1231425Sroot  *	We implement taking and restoring checkpoints on
1241425Sroot  *	the tape level.
1251425Sroot  *	When each tape is opened, a new process is created by forking; this
1261425Sroot  *	saves all of the necessary context in the parent.  The child
1271425Sroot  *	continues the dump; the parent waits around, saving the context.
1281425Sroot  *	If the child returns X_REWRITE, then it had problems writing that tape;
1291425Sroot  *	this causes the parent to fork again, duplicating the context, and
1301425Sroot  *	everything continues as if nothing had happened.
1311425Sroot  */
1321425Sroot 
1331425Sroot otape()
1341425Sroot {
1351425Sroot 	int	parentpid;
1361425Sroot 	int	childpid;
1371425Sroot 	int	status;
1381425Sroot 	int	waitpid;
1391425Sroot 	int	sig_ign_parent();
1401425Sroot 	int	interrupt();
1411425Sroot 
1421425Sroot 	/*
1431425Sroot 	 *	Force the tape to be closed
1441425Sroot 	 */
1451425Sroot 	close(to);
1461425Sroot 	parentpid = getpid();
1471425Sroot 
1481425Sroot     restore_check_point:
1491425Sroot 	signal(SIGINT, interrupt);
1501425Sroot 	/*
1511425Sroot 	 *	All signals are inherited...
1521425Sroot 	 */
1531425Sroot 	childpid = fork();
1541425Sroot 	if (childpid < 0){
1551425Sroot 		msg("Context save fork fails in parent %d\n", parentpid);
1561425Sroot 		Exit(X_ABORT);
1571425Sroot 	}
1581425Sroot 	if (childpid != 0){
1591425Sroot 		/*
1601425Sroot 		 *	PARENT:
1611425Sroot 		 *	save the context by waiting
1621425Sroot 		 *	until the child doing all of the work returns.
1631425Sroot 		 *	don't catch the interrupt
1641425Sroot 		 */
1651425Sroot 		signal(SIGINT, SIG_IGN);
1661425Sroot #ifdef TDEBUG
1671425Sroot 		msg("Tape: %d; parent process: %d child process %d\n",
1681425Sroot 			tapeno+1, parentpid, childpid);
1691425Sroot #endif TDEBUG
1701425Sroot 		for (;;){
1711425Sroot 			waitpid = wait(&status);
1721425Sroot 			if (waitpid != childpid){
1731425Sroot 				msg("Parent %d waiting for child %d has another child %d return\n",
1741425Sroot 					parentpid, childpid, waitpid);
1751425Sroot 			} else
1761425Sroot 				break;
1771425Sroot 		}
1781425Sroot 		if (status & 0xFF){
1791425Sroot 			msg("Child %d returns LOB status %o\n",
1801425Sroot 				childpid, status&0xFF);
1811425Sroot 		}
1821425Sroot 		status = (status >> 8) & 0xFF;
1831425Sroot #ifdef TDEBUG
1841425Sroot 		switch(status){
1851425Sroot 			case X_FINOK:
1861425Sroot 				msg("Child %d finishes X_FINOK\n", childpid);
1871425Sroot 				break;
1881425Sroot 			case X_ABORT:
1891425Sroot 				msg("Child %d finishes X_ABORT\n", childpid);
1901425Sroot 				break;
1911425Sroot 			case X_REWRITE:
1921425Sroot 				msg("Child %d finishes X_REWRITE\n", childpid);
1931425Sroot 				break;
1941425Sroot 			default:
1951425Sroot 				msg("Child %d finishes unknown %d\n", childpid,status);
1961425Sroot 				break;
1971425Sroot 		}
1981425Sroot #endif TDEBUG
1991425Sroot 		switch(status){
2001425Sroot 			case X_FINOK:
2011425Sroot 				Exit(X_FINOK);
2021425Sroot 			case X_ABORT:
2031425Sroot 				Exit(X_ABORT);
2041425Sroot 			case X_REWRITE:
2051425Sroot 				goto restore_check_point;
2061425Sroot 			default:
2071425Sroot 				msg("Bad return code from dump: %d\n", status);
2081425Sroot 				Exit(X_ABORT);
2091425Sroot 		}
2101425Sroot 		/*NOTREACHED*/
2111425Sroot 	} else {	/* we are the child; just continue */
2121425Sroot #ifdef TDEBUG
2131425Sroot 		sleep(4);	/* allow time for parent's message to get out */
2141425Sroot 		msg("Child on Tape %d has parent %d, my pid = %d\n",
2151425Sroot 			tapeno+1, parentpid, getpid());
2161425Sroot #endif
2171425Sroot 		do{
2181425Sroot 			to = creat(tape, 0666);
2191425Sroot 			if (to < 0) {
2201425Sroot 				if (!query("Cannot open tape. Do you want to retry the open?"))
2211425Sroot 					dumpabort();
2221425Sroot 			} else break;
2231425Sroot 		} while (1);
2241425Sroot 
2251425Sroot 		asize = 0;
2261425Sroot 		tapeno++;		/* current tape sequence */
2271425Sroot 		newtape++;		/* new tape signal */
2281425Sroot 		spcl.c_volume++;
2291425Sroot 		spcl.c_type = TS_TAPE;
2301425Sroot 		spclrec();
2311425Sroot 		if (tapeno > 1)
2321425Sroot 			msg("Tape %d begins with blocks from ino %d\n",
2331425Sroot 				tapeno, ino);
2341425Sroot 	}
2351425Sroot }
2361425Sroot 
2371425Sroot /*
2381425Sroot  *	The parent still catches interrupts, but does nothing with them
2391425Sroot  */
2401425Sroot sig_ign_parent()
2411425Sroot {
2421425Sroot 	msg("Waiting parent receives interrupt\n");
2431425Sroot 	signal(SIGINT, sig_ign_parent);
2441425Sroot }
2451425Sroot 
2461425Sroot dumpabort()
2471425Sroot {
2481925Swnj 	msg("The ENTIRE dump is aborted.\n");
2491425Sroot 	Exit(X_ABORT);
2501425Sroot }
2511425Sroot 
2521425Sroot Exit(status)
2531425Sroot {
2541425Sroot #ifdef TDEBUG
2551425Sroot 	msg("pid = %d exits with status %d\n", getpid(), status);
2561425Sroot #endif TDEBUG
2571925Swnj 	exit(status);
2581425Sroot }
259