/* Copyright (c) 1981 Regents of the University of California */
char version
[] = "@(#)main.c 1.4 %G%";
/* Modified to include h option (recursively extract all files within
* a subtree) and m option (recreate the heirarchical structure of
* that subtree and move extracted files to their proper homes).
* 8/29/80 by Mike Litzkow
* Includes the s (skip files) option for use with multiple dumps on
/* static char *sccsid = "@(#)restor.c 4.3 (Berkeley) 6/3/81"; */
#include "../h/dumprestor.h"
#define MWORD(m,i) (m[(unsigned)(i-1)/MLEN])
#define MBIT(i) (1<<((unsigned)(i-1)%MLEN))
#define BIS(i,w) (MWORD(w,i) |= MBIT(i))
#define BIC(i,w) (MWORD(w,i) &= ~MBIT(i))
#define BIT(i,w) (MWORD(w,i) & MBIT(i))
char tapename
[] = "/dev/rmt8";
char *magtape
= tapename
;
char dirfile
[] = "rstXXXXXX";
char tbf
[NTREC
*TP_BSIZE
];
fprintf(stderr
, "Usage: restor x[s|m|h] file file..., restor r filesys, or restor t\n");
for (cp
= *argv
++; *cp
; cp
++) {
/* s dumpnum (skip to) for multifile dump tapes */
fprintf(stderr
, "Dump number must be a positive integer\n");
fprintf(stderr
, "Bad key character %c\n", *cp
);
if (signal(SIGINT
, done
) == SIG_IGN
)
if (signal(SIGTERM
, done
) == SIG_IGN
)
signal(SIGTERM
, SIG_IGN
);
df
= creat(dirfile
, 0666);
fprintf(stderr
, "restor: %s - cannot create directory temporary\n", dirfile
);
doit(command
, argc
, argv
);
doit(command
, argc
, argv
)
register struct xtrlist
*xp
;
int xtrfile(), skip(), null();
int rstrfile(), rstrskip();
register struct dinode
*dp
;
register struct inode
*ip
;
if ((mt
= open(magtape
, 0)) < 0) {
fprintf(stderr
, "%s: cannot open tape\n", magtape
);
tcom
.mt_count
= dumpnum
-1;
if( ioctl(mt
,MTIOCTOP
,&tcom
) < 0)
fprintf(stderr
, "Tape? ");
if (readhdr(&spcl
) == 0) {
fprintf(stderr
, "Tape is not a dump tape\n");
fprintf(stderr
, "Dump date: %s", ctime(&spcl
.c_date
));
fprintf(stderr
, "Dumped from: %s", ctime(&spcl
.c_ddate
));
if (readhdr(&spcl
) == 0) {
fprintf(stderr
, "Tape is not a dump tape\n");
if (checkvol(&spcl
, 1) == 0) {
fprintf(stderr
, "Tape is not volume 1 of the dump\n");
pass1(); /* This sets the various maps on the way by */
if( (d
= psearch(*argv
)) == 0 ||
fprintf(stderr
, "%s: not on tape\n", *argv
++ );
xtrlist
[xtrcnt
].x_ino
= d
;
xtrlist
[xtrcnt
].x_flags
|= XINUSE
;
xtrlist
[xtrcnt
].x_name
= ststore( *argv
);
fprintf(stderr
, "%s: inode %u\n", *argv
, d
);
if( ++xtrcnt
>= xsize
) getxtrlist();
ioctl(mt
,MTIOCTOP
,&tcom
);
ioctl(mt
,MTIOCTOP
,&tcom
);
fprintf(stderr
, "Mount desired tape volume: Specify volume #: ");
fprintf(stderr
, "Volume numbers are positive numerics\n");
if (readhdr(&spcl
) == 0) {
fprintf(stderr
, "tape is not dump tape\n");
if (checkvol(&spcl
, volno
) == 0) {
fprintf(stderr
, "Wrong volume (%d)\n", spcl
.c_volume
);
while (gethead(&spcl
) == 0)
if (checktype(&spcl
, TS_INODE
) == 1) {
fprintf(stderr
, "Can't find inode mask!\n");
if (checktype(&spcl
, TS_BITS
) == 0)
for (k
= 0; xtrlist
[k
].x_flags
; k
++) {
if (BIT(xtrlist
[k
].x_ino
, dumpmap
)) {
xtrlist
[k
].x_flags
|= ONTAPE
;
while(gethead(&spcl
) == 0)
if (checktype(&spcl
, TS_END
) == 1) {
fprintf(stderr
, "end of tape\n");
for (xp
= xtrlist
; xp
->x_flags
; xp
++) {
if ((xp
->x_flags
&XTRACTD
) == 0)
if ((xp
->x_flags
&LINKED
) == 0) {
fprintf(stderr
, "cannot find file %s\n",
fprintf(stderr
, "link %s to %s\n",
xtrlist
[xp
->x_linkedto
].x_name
,
if (xlink(xtrlist
[xp
->x_linkedto
].x_name
, xp
->x_name
) < 0)
fprintf(stderr
, "link failed\n");
if (checktype(&spcl
, TS_INODE
) == 0) {
for (k
= 0; xtrlist
[k
].x_flags
; k
++) {
if (d
== xtrlist
[k
].x_ino
) {
sprintf(name
, "%s", xtrlist
[k
].x_name
);
fprintf(stderr
, "extract file %s\n",name
);
fprintf(stderr
, "extract file %u\n", xtrlist
[k
].x_ino
);
sprintf(name
, "%u", xtrlist
[k
].x_ino
);
timep
[0] = spcl
.c_dinode
.di_atime
;
timep
[1] = spcl
.c_dinode
.di_mtime
;
mode
= spcl
.c_dinode
.di_mode
;
fprintf(stderr
, "%s: unknown file type\n");
fprintf(stderr
, "%s: missing directory\n", name
);
if (xmknod(name
, mode
, spcl
.c_dinode
.di_rdev
)) {
fprintf(stderr
, "%s: cannot create special file\n", name
);
if ((ofile
= xcreat(name
, 0666)) < 0) {
fprintf(stderr
, "%s: cannot create file\n", name
);
getfile(xtrfile
, skip
, spcl
.c_dinode
.di_size
);
xchown(name
, spcl
.c_dinode
.di_uid
, spcl
.c_dinode
.di_gid
);
xtrlist
[k
].x_flags
|= XTRACTD
;
getfile(null
, null
, spcl
.c_dinode
.di_size
);
iput(u
.u_cdir
); /* release root inode */
iput(u
.u_rdir
); /* release root inode */
fprintf(stderr
, "Disk? ");
fprintf(stderr
, "Enter starting volume number: ");
fprintf(stderr
, "Last chance before scribbling on %s. ",
while (getchar() != '\n');
maxi
= fs
->fs_ipg
* fs
->fs_ncg
;
if (readhdr(&spcl
) == 0) {
fprintf(stderr
, "Missing volume record\n");
if (checkvol(&spcl
, volno
) == 0) {
fprintf(stderr
, "Tape is not volume %d\n", volno
);
if (ishead(&spcl
) == 0) {
fprintf(stderr
, "Missing header block\n");
while (gethead(&spcl
) == 0)
if (checktype(&spcl
, TS_END
) == 1) {
fprintf(stderr
, "End of tape\n");
if (checktype(&spcl
, TS_CLRI
) == 1) {
for (ino
= 1; ino
<= maxi
; ino
++)
if (BIT(ino
, clrimap
) == 0) {
fprintf(stderr
, "can't find inode %u\n", ino
);
if (checktype(&spcl
, TS_BITS
) == 1) {
if (checktype(&spcl
, TS_INODE
) == 0) {
fprintf(stderr
, "Unknown header type\n");
fprintf(stderr
, "Resynced at inode %u\n", ino
);
fprintf(stderr
, "%u: ilist too small\n", ino
);
fprintf(stderr
, "can't find inode %u\n",
ip
= ialloc(dev
, ino
, dp
->di_mode
);
if (ip
== NULL
|| ip
->i_number
!= ino
) {
fprintf(stderr
, "can't create inode %u\n", ino
);
ip
->i_mode
= mode
= dp
->di_mode
;
ip
->i_nlink
= dp
->di_nlink
;
ip
->i_atime
= dp
->di_atime
;
ip
->i_mtime
= dp
->di_mtime
;
ip
->i_ctime
= dp
->di_ctime
;
if ((ip
->i_mode
& IFMT
) == IFCHR
||
(ip
->i_mode
& IFMT
) == IFBLK
)
ip
->i_rdev
= dp
->di_rdev
;
getfile(rstrfile
, rstrskip
, dp
->di_size
);
ip
->i_flag
&= ~(IUPD
|IACC
);
* Read the tape, bulding up a directory structure for extraction
while (gethead(&spcl
) == 0) {
fprintf(stderr
, "Can't find directory header!\n");
if (checktype(&spcl
, TS_BITS
) == 1) {
if (checktype(&spcl
, TS_CLRI
) == 1) {
if (checktype(&spcl
, TS_INODE
) == 0) {
inotab
[ipos
].t_ino
= spcl
.c_inumber
;
inotab
[ipos
++].t_seekpt
= seekpt
;
getfile(putdir
, null
, spcl
.c_dinode
.di_size
);
* Do the file extraction, calling the supplied functions
char buf
[BLKING
* FRAG
][TP_BSIZE
];
for (i
= 0; i
< addrblock
.s_spcl
.c_count
; i
++) {
if (addrblock
.s_spcl
.c_addr
[i
]) {
readtape(&buf
[curblk
++][0]);
if (curblk
== BLKING
* FRAG
) {
(*f1
)(buf
, size
> TP_BSIZE
?
(long) (BLKING
* FRAG
* TP_BSIZE
) :
(curblk
- 1) * TP_BSIZE
+ size
);
(*f1
)(buf
, size
> TP_BSIZE
?
(long) (curblk
* TP_BSIZE
) :
(curblk
- 1) * TP_BSIZE
+ size
);
(*f2
)(clearedbuf
, size
> TP_BSIZE
? (long) TP_BSIZE
: size
);
if ((size
-= TP_BSIZE
) <= 0) {
while (gethead(&spcl
) == 0)
if (checktype(&spcl
, TS_ADDR
) == 1)
if (gethead(&addrblock
.s_spcl
) == 0) {
fprintf(stderr
, "Missing address (header) block, ino%u\n", ino
);
if (checktype(&addrblock
.s_spcl
, TS_ADDR
) == 0) {
(*f1
)(buf
, (curblk
* TP_BSIZE
) + size
);
* Do the tape i/o, dealing with volume changes
for (i
= 0; i
< NTREC
; i
++)
((struct s_spcl
*)&tbf
[i
*TP_BSIZE
])->c_magic
= 0;
if ((i
= read(mt
, tbf
, NTREC
*TP_BSIZE
)) < 0) {
perror("Tape read error");
fprintf(stderr
, "Mount volume %d\n", volno
);
while (getchar() != '\n')
if ((mt
= open(magtape
, 0)) == -1) {
fprintf(stderr
, "Cannot open tape!\n");
if (readhdr(&tmpbuf
) == 0) {
fprintf(stderr
, "Not a dump tape.Try again\n");
if (checkvol(&tmpbuf
, volno
) == 0) {
fprintf(stderr
, "Wrong tape. Try again\n");
copy(&tbf
[(bct
++*TP_BSIZE
)], b
, TP_BSIZE
);
* Put and get the directory entries from the compressed
for (i
= 0; i
< sizeof(ino_t
); i
++)
for (i
= 0; i
< DIRSIZ
; i
++) {
for (i
= 0; i
< sizeof(ino_t
); i
++)
for (i
= 0; i
< DIRSIZ
; i
++)
if ((*bf
++ = readc()) == 0)
* read/write the directory file
write(df
, drblock
, BSIZE
);
nread
= read(df
, drblock
, BSIZE
);
write(df
, drblock
, bpt
+1);
* search the directory inode ino
for (i
= 0; i
< MAXINO
; i
++)
if (inotab
[i
].t_ino
== inum
) {
mseek(inotab
[i
].t_seekpt
);
if (direq(dir
.d_name
, "/"))
} while (direq(dir
.d_name
, cp
) == 0);
* Search the directory tree rooted at inode ROOTINO
* for the path pointed at by n
while (*cp1
!= '/' && *cp1
)
for (i
= 0; i
< DIRSIZ
; i
++)
* read the tape into buf, then return whether or
* or not it is a header block.
if (buf
->s_spcl
.c_magic
!= MAGIC
|| checksum((int *) &buf
->s_spcl
) == 0)
* return whether or not the buffer contains a header block
if (buf
->s_spcl
.c_magic
!= MAGIC
|| checksum((int *) &buf
->s_spcl
) == 0)
return(b
->s_spcl
.c_type
== t
);
j
= sizeof(union u_spcl
) / sizeof(int);
fprintf(stderr
, "Checksum error %o, ino %u\n", i
, ino
);
if (b
->s_spcl
.c_volume
== t
)
if (checktype(b
, TS_TAPE
) == 0)
* The next routines are called during file extraction to
* put the data into the right form and place.
xwrite(ofile
, buf
, (int) size
);
* tell whether an inode is allocated
* this is drawn from ialloccg in sys/alloc.c
if ((unsigned)ino
>= fs
->fs_ipg
*fs
->fs_ncg
)
bp
= bread(dev
, cgtod(cg
, fs
), BSIZE
);
if (bp
->b_flags
& B_ERROR
)
if (isclr(cgp
->cg_iused
, ino
)) {
register struct direct
*dp
;
for (dp
= (struct direct
*) buf
, i
= 0; i
< size
; dp
++, i
+= sizeof(*dp
)) {
* read a bit mask from the tape into m.
m
+= (TP_BSIZE
/(MLEN
/BITS
));
while (gethead(&spcl
) == 0)
stcopy( sourcep
, destp
, max
)
for( i
= 1; i
<= max
&& (*destp
++ = *sourcep
++); i
++ )
if( i
> max
) return( 0 );
append( sourcep
, destp
, max
)
if( ++i
<= max
) *destp
++ = '/';
while( ++i
<=max
&& (*destp
++ = *sourcep
++) )
if( i
> max
) return( 0 );
* Truncate the rightmost file or directory name from a pathname
if( *cp
== '/' ) lstslsh
= cp
;
struct xtrlist
*malloc(),
xtrlist
= malloc( SIZEINC
*sizeof(struct xtrlist
) );
xtrlist
= realloc( xtrlist
, (SIZEINC
+xsize
) *
sizeof(struct xtrlist
) );
* Check for access into each directory in the pathname of an extracted
* file and create such a directory if needed in preparation for moving
* the file to its proper home.
for (cp
= name
; *cp
; cp
++) {
if (xaccess(name
, 01) < 0) {
if ((pid
= fork()) == 0) {
execl("/bin/xmkdir", "xmkdir", name
, 0);
execl("/usr/bin/xmkdir", "xmkdir", name
, 0);
execl("./xmkdir", "xmkdir", name
, 0);
fprintf(stderr
, "xrestor: cannot find xmkdir!\n");
while ((rp
= wait(&i
)) >= 0 && rp
!= pid
)
xchown(name
, spcl
.c_dinode
.di_uid
, spcl
.c_dinode
.di_gid
);
* Store a string in core returning a pointer to it. Allocate space
while( spaceleft
-- && (*spacep
++ = *stringp
++) );
spacep
= (char *)malloc( spaceleft
);
return( ststore(savep
) );
* Recursively find names and inumbers of all files in subtree
* pname and put them in xtrlist[]
static int xtrcnt
= 0; /* number of entries to extract */
int n
, /* loop counter */
bptsave
, /* placeholder for pointer into drblock */
readsize
; /* nbytes read into drblock at cur level
char locname
[NSIZE
]; /* pname + an entry from drblock */
daddr_t dptsave
, /* disk loc where cur drblock came from */
disk_loc
; /* used to see if getent() causes a phys read */
ino_t d
; /* inode no of pname */
stcopy( pname
, locname
, NSIZE
);
if( (d
= psearch(locname
)) == 0 || BIT( d
, dumpmap
) == 0 ) {
fprintf(stderr
, "%s: not on the tape\n", locname
);
for( n
=0; n
<MAXINO
; n
++ ) {
if( inotab
[n
].t_ino
== d
) {
* locname is a directory name
/* phys disk read forced so reset readsize */
mseek( inotab
[n
].t_seekpt
);
/* "/" signals end of directory */
while( !direq(dir
.d_name
,"/") ) {
if( direq(dir
.d_name
,".") ) {
if( direq(dir
.d_name
,"..") ) {
if( append(dir
.d_name
,locname
,NSIZE
) == 0 ) {
fprintf(stderr
, "name exceedes %d char\n",NSIZE
);
/* info for rereading drblock later */
dptsave
= lseek( df
, 0L, 1 ) - readsize
;
/* reread drblock after recursion rtn */
read( df
, drblock
, BSIZE
);
if( trunc(locname
) == 0 ) {
fprintf(stderr
, "Trouble with name trunc\n" );
/* get next entry from drblock; reset
* readsize iff physical disk read */
disk_loc
= lseek( df
, 0L, 1 );
if( lseek(df
,0L,1) != disk_loc
)
* locname is name of a simple file
xtrlist
[xtrcnt
].x_ino
= d
;
xtrlist
[xtrcnt
].x_flags
|= XINUSE
;
xtrlist
[xtrcnt
].x_name
= (char *)ststore( locname
);
for (n
= 0; n
< xtrcnt
; n
++)
if (xtrlist
[n
].x_ino
== d
) {
xtrlist
[xtrcnt
].x_flags
|= LINKED
;
xtrlist
[xtrcnt
].x_linkedto
= n
;
if( ++xtrcnt
>= xsize
) getxtrlist();
fprintf(stderr
, "%s: inode %u\n", locname
, d
);