1*22030Sdist /*
2*22030Sdist * Copyright (c) 1980 Regents of the University of California.
3*22030Sdist * All rights reserved. The Berkeley software License Agreement
4*22030Sdist * specifies the terms and conditions for redistribution.
5*22030Sdist */
6*22030Sdist
7*22030Sdist #ifndef lint
8*22030Sdist static char sccsid[] = "@(#)dumptape.c 5.1 (Berkeley) 06/05/85";
9*22030Sdist #endif not lint
10*22030Sdist
111425Sroot #include "dump.h"
121425Sroot
131425Sroot char tblock[NTREC][BSIZE];
141425Sroot daddr_t tdaddr[NTREC];
151425Sroot int trecno;
161425Sroot
taprec(dp)171425Sroot taprec(dp)
181425Sroot char *dp;
191425Sroot {
201425Sroot register i;
211425Sroot
221425Sroot for(i=0; i<BSIZE; i++)
231425Sroot tblock[trecno][i] = *dp++;
241425Sroot tdaddr[trecno] = 0;
251425Sroot trecno++;
261425Sroot spcl.c_tapea++;
271425Sroot if(trecno >= NTREC)
281425Sroot flusht();
291425Sroot }
301425Sroot
tapsrec(d)311425Sroot tapsrec(d)
321425Sroot daddr_t d;
331425Sroot {
341425Sroot
351425Sroot if(d == 0)
361425Sroot return;
371425Sroot tdaddr[trecno] = d;
381425Sroot trecno++;
391425Sroot spcl.c_tapea++;
401425Sroot if(trecno >= NTREC)
411425Sroot flusht();
421425Sroot }
431425Sroot
441425Sroot int nogripe = 0;
451425Sroot
flusht()461425Sroot flusht()
471425Sroot {
481425Sroot register i, si;
491425Sroot daddr_t d;
501425Sroot
511425Sroot while(trecno < NTREC)
521425Sroot tdaddr[trecno++] = 1;
531425Sroot
541425Sroot loop:
551425Sroot d = 0;
561425Sroot for(i=0; i<NTREC; i++)
571425Sroot if(tdaddr[i] != 0)
581425Sroot if(d == 0 || tdaddr[i] < d) {
591425Sroot si = i;
601425Sroot d = tdaddr[i];
611425Sroot }
621425Sroot if(d != 0) {
631425Sroot bread(d, tblock[si], BSIZE);
641425Sroot tdaddr[si] = 0;
651425Sroot goto loop;
661425Sroot }
671425Sroot trecno = 0;
681425Sroot if (write(to, tblock[0], sizeof(tblock)) != sizeof(tblock) ){
6912082Smckusick if (pipeout) {
7012082Smckusick msg("Tape write error on %s\n", tape);
7112082Smckusick msg("Cannot recover\n");
7212082Smckusick dumpabort();
7312082Smckusick /*NOTREACHED*/
7412082Smckusick }
751425Sroot msg("Tape write error on tape %d\n", tapeno);
761425Sroot broadcast("TAPE ERROR!\n");
771425Sroot if (query("Do you want to restart?")){
781425Sroot msg("This tape will rewind. After it is rewound,\n");
791425Sroot msg("replace the faulty tape with a new one;\n");
801925Swnj msg("this dump volume will be rewritten.\n");
811425Sroot /*
821425Sroot * Temporarily change the tapeno identification
831425Sroot */
841425Sroot tapeno--;
851425Sroot nogripe = 1;
861425Sroot close_rewind();
871425Sroot nogripe = 0;
881425Sroot tapeno++;
891425Sroot Exit(X_REWRITE);
901425Sroot } else {
911425Sroot dumpabort();
921425Sroot /*NOTREACHED*/
931425Sroot }
941425Sroot }
951425Sroot
961425Sroot asize += sizeof(tblock)/density;
971425Sroot asize += 7;
981425Sroot blockswritten += NTREC;
9912082Smckusick if (!pipeout && asize > tsize) {
1001425Sroot close_rewind();
1011425Sroot otape();
1021425Sroot }
1031425Sroot timeest();
1041425Sroot }
1051425Sroot
rewind()1061425Sroot rewind()
1071425Sroot {
1081425Sroot int secs;
1091425Sroot #ifdef DEBUG
1101425Sroot msg("Waiting 10 seconds to rewind.\n");
1111425Sroot sleep(10);
1121425Sroot #else
1131425Sroot /*
1141425Sroot * It takes about 3 minutes, 25secs to rewind 2300' of tape
1151425Sroot */
1161425Sroot secs = (( (60*3) + 25)*asize)/(2300L*12L*10L);
1171425Sroot msg("Waiting %d seconds to rewind.\n", secs);
1181425Sroot sleep(secs);
1191425Sroot #endif
1201425Sroot }
1211425Sroot
close_rewind()1221425Sroot close_rewind()
1231425Sroot {
12412082Smckusick if (pipeout)
12512082Smckusick return;
1261425Sroot close(to);
1271425Sroot if (!nogripe){
1281425Sroot rewind();
1291425Sroot msg("Change Tapes: Mount tape #%d\n", tapeno+1);
1301425Sroot broadcast("CHANGE TAPES!\7\7\n");
1311425Sroot }
1321425Sroot do{
1331425Sroot if (query ("Is the new tape mounted and ready to go?"))
1341425Sroot break;
1351425Sroot if (query ("Do you want to abort?")){
1361425Sroot dumpabort();
1371425Sroot /*NOTREACHED*/
1381425Sroot }
1391425Sroot } while (1);
1401425Sroot }
1411425Sroot
1421425Sroot /*
1431425Sroot * We implement taking and restoring checkpoints on
1441425Sroot * the tape level.
1451425Sroot * When each tape is opened, a new process is created by forking; this
1461425Sroot * saves all of the necessary context in the parent. The child
1471425Sroot * continues the dump; the parent waits around, saving the context.
1481425Sroot * If the child returns X_REWRITE, then it had problems writing that tape;
1491425Sroot * this causes the parent to fork again, duplicating the context, and
1501425Sroot * everything continues as if nothing had happened.
1511425Sroot */
1521425Sroot
otape()1531425Sroot otape()
1541425Sroot {
1551425Sroot int parentpid;
1561425Sroot int childpid;
1571425Sroot int status;
1581425Sroot int waitpid;
1591425Sroot int sig_ign_parent();
1601425Sroot int interrupt();
1611425Sroot
1621425Sroot /*
1631425Sroot * Force the tape to be closed
1641425Sroot */
16512082Smckusick if (!pipeout)
16612082Smckusick close(to);
1671425Sroot parentpid = getpid();
1681425Sroot
1691425Sroot restore_check_point:
1701425Sroot signal(SIGINT, interrupt);
1711425Sroot /*
1721425Sroot * All signals are inherited...
1731425Sroot */
1741425Sroot childpid = fork();
1751425Sroot if (childpid < 0){
1761425Sroot msg("Context save fork fails in parent %d\n", parentpid);
1771425Sroot Exit(X_ABORT);
1781425Sroot }
1791425Sroot if (childpid != 0){
1801425Sroot /*
1811425Sroot * PARENT:
1821425Sroot * save the context by waiting
1831425Sroot * until the child doing all of the work returns.
1841425Sroot * don't catch the interrupt
1851425Sroot */
1861425Sroot signal(SIGINT, SIG_IGN);
1871425Sroot #ifdef TDEBUG
1881425Sroot msg("Tape: %d; parent process: %d child process %d\n",
1891425Sroot tapeno+1, parentpid, childpid);
1901425Sroot #endif TDEBUG
1911425Sroot for (;;){
1921425Sroot waitpid = wait(&status);
1931425Sroot if (waitpid != childpid){
1941425Sroot msg("Parent %d waiting for child %d has another child %d return\n",
1951425Sroot parentpid, childpid, waitpid);
1961425Sroot } else
1971425Sroot break;
1981425Sroot }
1991425Sroot if (status & 0xFF){
2001425Sroot msg("Child %d returns LOB status %o\n",
2011425Sroot childpid, status&0xFF);
2021425Sroot }
2031425Sroot status = (status >> 8) & 0xFF;
2041425Sroot #ifdef TDEBUG
2051425Sroot switch(status){
2061425Sroot case X_FINOK:
2071425Sroot msg("Child %d finishes X_FINOK\n", childpid);
2081425Sroot break;
2091425Sroot case X_ABORT:
2101425Sroot msg("Child %d finishes X_ABORT\n", childpid);
2111425Sroot break;
2121425Sroot case X_REWRITE:
2131425Sroot msg("Child %d finishes X_REWRITE\n", childpid);
2141425Sroot break;
2151425Sroot default:
2161425Sroot msg("Child %d finishes unknown %d\n", childpid,status);
2171425Sroot break;
2181425Sroot }
2191425Sroot #endif TDEBUG
2201425Sroot switch(status){
2211425Sroot case X_FINOK:
2221425Sroot Exit(X_FINOK);
2231425Sroot case X_ABORT:
2241425Sroot Exit(X_ABORT);
2251425Sroot case X_REWRITE:
2261425Sroot goto restore_check_point;
2271425Sroot default:
2281425Sroot msg("Bad return code from dump: %d\n", status);
2291425Sroot Exit(X_ABORT);
2301425Sroot }
2311425Sroot /*NOTREACHED*/
2321425Sroot } else { /* we are the child; just continue */
2331425Sroot #ifdef TDEBUG
2341425Sroot sleep(4); /* allow time for parent's message to get out */
2351425Sroot msg("Child on Tape %d has parent %d, my pid = %d\n",
2361425Sroot tapeno+1, parentpid, getpid());
2371425Sroot #endif
2381425Sroot do{
23912082Smckusick if (pipeout)
24012082Smckusick to = 1;
24112082Smckusick else
24212082Smckusick to = creat(tape, 0666);
2431425Sroot if (to < 0) {
2441425Sroot if (!query("Cannot open tape. Do you want to retry the open?"))
2451425Sroot dumpabort();
2461425Sroot } else break;
2471425Sroot } while (1);
2481425Sroot
2491425Sroot asize = 0;
2501425Sroot tapeno++; /* current tape sequence */
2511425Sroot newtape++; /* new tape signal */
2521425Sroot spcl.c_volume++;
2531425Sroot spcl.c_type = TS_TAPE;
2541425Sroot spclrec();
2551425Sroot if (tapeno > 1)
2561425Sroot msg("Tape %d begins with blocks from ino %d\n",
2571425Sroot tapeno, ino);
2581425Sroot }
2591425Sroot }
2601425Sroot
2611425Sroot /*
2621425Sroot * The parent still catches interrupts, but does nothing with them
2631425Sroot */
sig_ign_parent()2641425Sroot sig_ign_parent()
2651425Sroot {
2661425Sroot msg("Waiting parent receives interrupt\n");
2671425Sroot signal(SIGINT, sig_ign_parent);
2681425Sroot }
2691425Sroot
dumpabort()2701425Sroot dumpabort()
2711425Sroot {
2721925Swnj msg("The ENTIRE dump is aborted.\n");
2731425Sroot Exit(X_ABORT);
2741425Sroot }
2751425Sroot
Exit(status)2761425Sroot Exit(status)
2771425Sroot {
2781425Sroot #ifdef TDEBUG
2791425Sroot msg("pid = %d exits with status %d\n", getpid(), status);
2801425Sroot #endif TDEBUG
2811925Swnj exit(status);
2821425Sroot }
283