static char *sccsid
= "@(#)tape.c 1.8 (Berkeley) %G%";
char (*tblock
)[TP_BSIZE
]; /* Pointer to malloc()ed buffer for tape */
int writesize
; /* Size of malloc()ed buffer for tape */
extern int ntrec
; /* blocking factor on tape */
* Allocate the buffer for tape operations.
* Depends on global variable ntrec, set from 'b' option in command line.
* Returns 1 if successful, 0 if failed.
* For later kernel performance improvement, this buffer should be allocated
writesize
= ntrec
* TP_BSIZE
;
tblock
= (char (*)[TP_BSIZE
])malloc(writesize
);
bcopy(dp
, tblock
[trecno
], TP_BSIZE
);
int avail
, tpblks
, dblkno
;
if (size
% TP_BSIZE
!= 0)
msg("bad size to dmpblk: %d\n", size
);
dblkno
= fsbtodb(sblock
, blkno
);
for (tpblks
= size
/ TP_BSIZE
; tpblks
> avail
; ) {
bread(dblkno
, tblock
[trecno
], TP_BSIZE
* avail
);
dblkno
+= avail
* (TP_BSIZE
/ DEV_BSIZE
);
bread(dblkno
, tblock
[trecno
], TP_BSIZE
* tpblks
);
if (write(to
, tblock
[0], writesize
) != writesize
){
msg("Tape write error on %s\n", tape
);
msg("Tape write error on tape %d\n", tapeno
);
broadcast("TAPE ERROR!\n");
if (query("Do you want to restart?")){
msg("This tape will rewind. After it is rewound,\n");
msg("replace the faulty tape with a new one;\n");
msg("this dump volume will be rewritten.\n");
* Temporarily change the tapeno identification
asize
+= writesize
/density
;
if (!pipeout
&& asize
> tsize
) {
msg("Waiting 10 seconds to rewind.\n");
* It takes about 3 minutes, 25secs to rewind 2300' of tape
msg("Tape rewinding\n", secs
);
while ((f
= open(tape
, 0)) < 0)
msg("Change Tapes: Mount tape #%d\n", tapeno
+1);
broadcast("CHANGE TAPES!\7\7\n");
if (query ("Is the new tape mounted and ready to go?"))
if (query ("Do you want to abort?")){
* We implement taking and restoring checkpoints on
* When each tape is opened, a new process is created by forking; this
* saves all of the necessary context in the parent. The child
* continues the dump; the parent waits around, saving the context.
* If the child returns X_REWRITE, then it had problems writing that tape;
* this causes the parent to fork again, duplicating the context, and
* everything continues as if nothing had happened.
* Force the tape to be closed
signal(SIGINT
, interrupt
);
* All signals are inherited...
msg("Context save fork fails in parent %d\n", parentpid
);
* save the context by waiting
* until the child doing all of the work returns.
* don't catch the interrupt
msg("Tape: %d; parent process: %d child process %d\n",
tapeno
+1, parentpid
, childpid
);
if (waitpid
!= childpid
){
msg("Parent %d waiting for child %d has another child %d return\n",
parentpid
, childpid
, waitpid
);
msg("Child %d returns LOB status %o\n",
status
= (status
>> 8) & 0xFF;
msg("Child %d finishes X_FINOK\n", childpid
);
msg("Child %d finishes X_ABORT\n", childpid
);
msg("Child %d finishes X_REWRITE\n", childpid
);
msg("Child %d finishes unknown %d\n", childpid
,status
);
goto restore_check_point
;
msg("Bad return code from dump: %d\n", status
);
} else { /* we are the child; just continue */
sleep(4); /* allow time for parent's message to get out */
msg("Child on Tape %d has parent %d, my pid = %d\n",
tapeno
+1, parentpid
, getpid());
if (!query("Cannot open tape. Do you want to retry the open?"))
tapeno
++; /* current tape sequence */
newtape
++; /* new tape signal */
msg("Tape %d begins with blocks from ino %d\n",
* The parent still catches interrupts, but does nothing with them
msg("Waiting parent receives interrupt\n");
signal(SIGINT
, sig_ign_parent
);
msg("The ENTIRE dump is aborted.\n");
msg("pid = %d exits with status %d\n", getpid(), status
);