xref: /csrg-svn/sbin/dump/tape.c (revision 17527)
1*17527Ssam #ifndef lint
2*17527Ssam static	char *sccsid = "@(#)tape.c	1.8 (Berkeley) 12/16/84";
3*17527Ssam #endif
4*17527Ssam 
51425Sroot #include "dump.h"
61425Sroot 
710911Ssam char	(*tblock)[TP_BSIZE];	/* Pointer to malloc()ed buffer for tape */
810911Ssam int	writesize;		/* Size of malloc()ed buffer for tape */
94774Smckusic int	trecno = 0;
1010911Ssam extern int ntrec;		/* blocking factor on tape */
111425Sroot 
1210911Ssam /*
1310911Ssam  * Allocate the buffer for tape operations.
1410911Ssam  *
1510911Ssam  * Depends on global variable ntrec, set from 'b' option in command line.
1610911Ssam  * Returns 1 if successful, 0 if failed.
1710911Ssam  *
1810911Ssam  * For later kernel performance improvement, this buffer should be allocated
1910911Ssam  * on a page boundary.
2010911Ssam  */
2110911Ssam alloctape()
2210911Ssam {
2310911Ssam 
2410911Ssam 	writesize = ntrec * TP_BSIZE;
2510911Ssam 	tblock = (char (*)[TP_BSIZE])malloc(writesize);
2610911Ssam 	return (tblock != NULL);
2710911Ssam }
2810911Ssam 
2910911Ssam 
301425Sroot taprec(dp)
315329Smckusic 	char *dp;
321425Sroot {
331425Sroot 
34*17527Ssam 	bcopy(dp, tblock[trecno], TP_BSIZE);
351425Sroot 	trecno++;
361425Sroot 	spcl.c_tapea++;
3710911Ssam 	if(trecno >= ntrec)
381425Sroot 		flusht();
391425Sroot }
401425Sroot 
414774Smckusic dmpblk(blkno, size)
424774Smckusic 	daddr_t blkno;
434774Smckusic 	int size;
441425Sroot {
455329Smckusic 	int avail, tpblks, dblkno;
461425Sroot 
475329Smckusic 	if (size % TP_BSIZE != 0)
484774Smckusic 		msg("bad size to dmpblk: %d\n", size);
4910911Ssam 	avail = ntrec - trecno;
505329Smckusic 	dblkno = fsbtodb(sblock, blkno);
515329Smckusic 	for (tpblks = size / TP_BSIZE; tpblks > avail; ) {
525329Smckusic 		bread(dblkno, tblock[trecno], TP_BSIZE * avail);
534774Smckusic 		trecno += avail;
544774Smckusic 		spcl.c_tapea += avail;
554774Smckusic 		flusht();
565329Smckusic 		dblkno += avail * (TP_BSIZE / DEV_BSIZE);
575329Smckusic 		tpblks -= avail;
5810911Ssam 		avail = ntrec - trecno;
594774Smckusic 	}
605329Smckusic 	bread(dblkno, tblock[trecno], TP_BSIZE * tpblks);
615329Smckusic 	trecno += tpblks;
625329Smckusic 	spcl.c_tapea += tpblks;
6310911Ssam 	if(trecno >= ntrec)
641425Sroot 		flusht();
651425Sroot }
661425Sroot 
671425Sroot int	nogripe = 0;
681425Sroot 
691425Sroot flusht()
701425Sroot {
711425Sroot 	register i, si;
721425Sroot 	daddr_t d;
731425Sroot 
741425Sroot 	trecno = 0;
7510911Ssam 	if (write(to, tblock[0], writesize) != writesize){
7612331Smckusick 		if (pipeout) {
7712331Smckusick 			msg("Tape write error on %s\n", tape);
7812331Smckusick 			msg("Cannot recover\n");
7912331Smckusick 			dumpabort();
8012331Smckusick 			/* NOTREACHED */
8112331Smckusick 		}
821425Sroot 		msg("Tape write error on tape %d\n", tapeno);
831425Sroot 		broadcast("TAPE ERROR!\n");
841425Sroot 		if (query("Do you want to restart?")){
851425Sroot 			msg("This tape will rewind.  After it is rewound,\n");
861425Sroot 			msg("replace the faulty tape with a new one;\n");
871925Swnj 			msg("this dump volume will be rewritten.\n");
881425Sroot 			/*
891425Sroot 			 *	Temporarily change the tapeno identification
901425Sroot 			 */
911425Sroot 			tapeno--;
921425Sroot 			nogripe = 1;
931425Sroot 			close_rewind();
941425Sroot 			nogripe = 0;
951425Sroot 			tapeno++;
961425Sroot 			Exit(X_REWRITE);
971425Sroot 		} else {
981425Sroot 			dumpabort();
991425Sroot 			/*NOTREACHED*/
1001425Sroot 		}
1011425Sroot 	}
1021425Sroot 
10310911Ssam 	asize += writesize/density;
1041425Sroot 	asize += 7;
10510911Ssam 	blockswritten += ntrec;
10612331Smckusick 	if (!pipeout && asize > tsize) {
1071425Sroot 		close_rewind();
1081425Sroot 		otape();
1091425Sroot 	}
1101425Sroot 	timeest();
1111425Sroot }
1121425Sroot 
1131425Sroot rewind()
1141425Sroot {
1151425Sroot 	int	secs;
1163214Swnj 	int f;
11712331Smckusick 
11812331Smckusick 	if (pipeout)
11912331Smckusick 		return;
1201425Sroot #ifdef DEBUG
1211425Sroot 	msg("Waiting 10 seconds to rewind.\n");
1221425Sroot 	sleep(10);
1231425Sroot #else
1241425Sroot 	/*
1251425Sroot 	 *	It takes about 3 minutes, 25secs to rewind 2300' of tape
1261425Sroot 	 */
1273214Swnj 	msg("Tape rewinding\n", secs);
1283214Swnj 	close(to);
1293214Swnj 	while ((f = open(tape, 0)) < 0)
1303214Swnj 		sleep (10);
1313214Swnj 	close(f);
1321425Sroot #endif
1331425Sroot }
1341425Sroot 
1351425Sroot close_rewind()
1361425Sroot {
13712331Smckusick 
13812331Smckusick 	if (pipeout)
13912331Smckusick 		return;
1401425Sroot 	close(to);
1411425Sroot 	if (!nogripe){
1421425Sroot 		rewind();
1431425Sroot 		msg("Change Tapes: Mount tape #%d\n", tapeno+1);
1441425Sroot 		broadcast("CHANGE TAPES!\7\7\n");
1451425Sroot 	}
1461425Sroot 	do{
1471425Sroot 		if (query ("Is the new tape mounted and ready to go?"))
1481425Sroot 			break;
1491425Sroot 		if (query ("Do you want to abort?")){
1501425Sroot 			dumpabort();
1511425Sroot 			/*NOTREACHED*/
1521425Sroot 		}
1531425Sroot 	} while (1);
1541425Sroot }
1551425Sroot 
1561425Sroot /*
1571425Sroot  *	We implement taking and restoring checkpoints on
1581425Sroot  *	the tape level.
1591425Sroot  *	When each tape is opened, a new process is created by forking; this
1601425Sroot  *	saves all of the necessary context in the parent.  The child
1611425Sroot  *	continues the dump; the parent waits around, saving the context.
1621425Sroot  *	If the child returns X_REWRITE, then it had problems writing that tape;
1631425Sroot  *	this causes the parent to fork again, duplicating the context, and
1641425Sroot  *	everything continues as if nothing had happened.
1651425Sroot  */
1661425Sroot 
1671425Sroot otape()
1681425Sroot {
1691425Sroot 	int	parentpid;
1701425Sroot 	int	childpid;
1711425Sroot 	int	status;
1721425Sroot 	int	waitpid;
1731425Sroot 	int	sig_ign_parent();
1741425Sroot 	int	interrupt();
1751425Sroot 
1761425Sroot 	/*
1771425Sroot 	 *	Force the tape to be closed
1781425Sroot 	 */
1791425Sroot 	close(to);
1801425Sroot 	parentpid = getpid();
1811425Sroot 
1821425Sroot     restore_check_point:
1831425Sroot 	signal(SIGINT, interrupt);
1841425Sroot 	/*
1851425Sroot 	 *	All signals are inherited...
1861425Sroot 	 */
1871425Sroot 	childpid = fork();
1881425Sroot 	if (childpid < 0){
1891425Sroot 		msg("Context save fork fails in parent %d\n", parentpid);
1901425Sroot 		Exit(X_ABORT);
1911425Sroot 	}
1921425Sroot 	if (childpid != 0){
1931425Sroot 		/*
1941425Sroot 		 *	PARENT:
1951425Sroot 		 *	save the context by waiting
1961425Sroot 		 *	until the child doing all of the work returns.
1971425Sroot 		 *	don't catch the interrupt
1981425Sroot 		 */
1991425Sroot 		signal(SIGINT, SIG_IGN);
2001425Sroot #ifdef TDEBUG
2011425Sroot 		msg("Tape: %d; parent process: %d child process %d\n",
2021425Sroot 			tapeno+1, parentpid, childpid);
2031425Sroot #endif TDEBUG
2041425Sroot 		for (;;){
2051425Sroot 			waitpid = wait(&status);
2061425Sroot 			if (waitpid != childpid){
2071425Sroot 				msg("Parent %d waiting for child %d has another child %d return\n",
2081425Sroot 					parentpid, childpid, waitpid);
2091425Sroot 			} else
2101425Sroot 				break;
2111425Sroot 		}
2121425Sroot 		if (status & 0xFF){
2131425Sroot 			msg("Child %d returns LOB status %o\n",
2141425Sroot 				childpid, status&0xFF);
2151425Sroot 		}
2161425Sroot 		status = (status >> 8) & 0xFF;
2171425Sroot #ifdef TDEBUG
2181425Sroot 		switch(status){
2191425Sroot 			case X_FINOK:
2201425Sroot 				msg("Child %d finishes X_FINOK\n", childpid);
2211425Sroot 				break;
2221425Sroot 			case X_ABORT:
2231425Sroot 				msg("Child %d finishes X_ABORT\n", childpid);
2241425Sroot 				break;
2251425Sroot 			case X_REWRITE:
2261425Sroot 				msg("Child %d finishes X_REWRITE\n", childpid);
2271425Sroot 				break;
2281425Sroot 			default:
2291425Sroot 				msg("Child %d finishes unknown %d\n", childpid,status);
2301425Sroot 				break;
2311425Sroot 		}
2321425Sroot #endif TDEBUG
2331425Sroot 		switch(status){
2341425Sroot 			case X_FINOK:
2351425Sroot 				Exit(X_FINOK);
2361425Sroot 			case X_ABORT:
2371425Sroot 				Exit(X_ABORT);
2381425Sroot 			case X_REWRITE:
2391425Sroot 				goto restore_check_point;
2401425Sroot 			default:
2411425Sroot 				msg("Bad return code from dump: %d\n", status);
2421425Sroot 				Exit(X_ABORT);
2431425Sroot 		}
2441425Sroot 		/*NOTREACHED*/
2451425Sroot 	} else {	/* we are the child; just continue */
2461425Sroot #ifdef TDEBUG
2471425Sroot 		sleep(4);	/* allow time for parent's message to get out */
2481425Sroot 		msg("Child on Tape %d has parent %d, my pid = %d\n",
2491425Sroot 			tapeno+1, parentpid, getpid());
2501425Sroot #endif
2511425Sroot 		do{
25212331Smckusick 			if (pipeout)
25312331Smckusick 				to = 1;
25412331Smckusick 			else
25512331Smckusick 				to = creat(tape, 0666);
2561425Sroot 			if (to < 0) {
2571425Sroot 				if (!query("Cannot open tape. Do you want to retry the open?"))
2581425Sroot 					dumpabort();
2591425Sroot 			} else break;
2601425Sroot 		} while (1);
2611425Sroot 
2621425Sroot 		asize = 0;
2631425Sroot 		tapeno++;		/* current tape sequence */
2641425Sroot 		newtape++;		/* new tape signal */
2651425Sroot 		spcl.c_volume++;
2661425Sroot 		spcl.c_type = TS_TAPE;
2671425Sroot 		spclrec();
2681425Sroot 		if (tapeno > 1)
2691425Sroot 			msg("Tape %d begins with blocks from ino %d\n",
2701425Sroot 				tapeno, ino);
2711425Sroot 	}
2721425Sroot }
2731425Sroot 
2741425Sroot /*
2751425Sroot  *	The parent still catches interrupts, but does nothing with them
2761425Sroot  */
2771425Sroot sig_ign_parent()
2781425Sroot {
2791425Sroot 	msg("Waiting parent receives interrupt\n");
2801425Sroot 	signal(SIGINT, sig_ign_parent);
2811425Sroot }
2821425Sroot 
2831425Sroot dumpabort()
2841425Sroot {
2851925Swnj 	msg("The ENTIRE dump is aborted.\n");
2861425Sroot 	Exit(X_ABORT);
2871425Sroot }
2881425Sroot 
2891425Sroot Exit(status)
2901425Sroot {
2911425Sroot #ifdef TDEBUG
2921425Sroot 	msg("pid = %d exits with status %d\n", getpid(), status);
2931425Sroot #endif TDEBUG
2941925Swnj 	exit(status);
2951425Sroot }
296