/* Copyright (c) 1981 Regents of the University of California */
char version
[] = "@(#)main.c 1.6 %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))
int eflag
= 0, hflag
= 0, mflag
= 0;
char tapename
[] = "/dev/rmt8";
char *magtape
= tapename
;
char dirfile
[] = "rstXXXXXX";
#define INOHASH(val) (val % MAXINO)
struct xtrlist
*x_linkedto
;
char tbf
[NTREC
*TP_BSIZE
];
if (signal(SIGINT
, done
) == SIG_IGN
)
if (signal(SIGTERM
, done
) == SIG_IGN
)
signal(SIGTERM
, SIG_IGN
);
fprintf(stderr
, "Usage: restor x[s|m|h|v] file file..., restor r|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
);
df
= fopen(dirfile
, "w");
fprintf(stderr
, "restor: %s - cannot create directory temporary\n", dirfile
);
doit(command
, argc
, argv
);
doit(command
, argc
, argv
)
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(stdout
, "Dump date: %s", ctime(&spcl
.c_date
));
fprintf(stdout
, "Dumped from: %s", ctime(&spcl
.c_ddate
));
extractfiles(argc
, argv
);
restorfiles(command
, argv
);
register struct xtrlist
*xp
;
int xtrfile(), skip(), null();
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 || BIT(d
,dumpmap
) == 0) {
fprintf(stdout
, "%s: not on tape\n", *argv
++);
allocxtr(d
, *argv
++, XINUSE
);
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)
while(gethead(&spcl
) == 0)
if (checktype(&spcl
, TS_END
) == 1) {
fprintf(stderr
, "end of tape\n");
if (checktype(&spcl
, TS_INODE
) == 0) {
for (xp
= xtrlist
[INOHASH(d
)]; xp
; xp
= xp
->x_next
) {
if (xp
->x_flags
& XLINKED
)
xp
->x_timep
[0] = spcl
.c_dinode
.di_atime
;
xp
->x_timep
[1] = spcl
.c_dinode
.di_mtime
;
mode
= spcl
.c_dinode
.di_mode
;
strcpy(name
, xp
->x_name
);
sprintf(name
, "%u", xp
->x_ino
);
fprintf(stderr
, "%s: unknown file type\n", name
);
fprintf(stdout
, "extract special file %s\n", name
);
if (xmknod(name
, mode
, spcl
.c_dinode
.di_rdev
)) {
fprintf(stderr
, "%s: cannot create special file\n", name
);
getfile(null
, null
, spcl
.c_dinode
.di_size
);
fprintf(stdout
, "extract directory %s\n", name
);
strncat(name
, "/.", BUFSIZ
);
xchown(xp
->x_name
, spcl
.c_dinode
.di_uid
, spcl
.c_dinode
.di_gid
);
getfile(null
, null
, spcl
.c_dinode
.di_size
);
fprintf(stdout
, "extract file %s\n", name
);
if ((ofile
= xcreat(name
, 0666)) < 0) {
fprintf(stderr
, "%s: cannot create file\n", name
);
xchown(name
, spcl
.c_dinode
.di_uid
, spcl
.c_dinode
.di_gid
);
getfile(xtrfile
, skip
, spcl
.c_dinode
.di_size
);
xutime(name
, xp
->x_timep
);
getfile(null
, null
, spcl
.c_dinode
.di_size
);
if (xtrcnt
== 0 && !mflag
)
for (xpp
= xtrlist
; xpp
< &xtrlist
[MAXINO
]; xpp
++) {
for (xp
= *xpp
; xp
; xp
= xp
->x_next
) {
if (mflag
&& (xp
->x_flags
& XISDIR
))
xutime(xp
->x_name
, xp
->x_timep
);
if (xp
->x_flags
& XTRACTD
)
if ((xp
->x_flags
& XLINKED
) == 0) {
fprintf(stderr
, "cannot find file %s\n",
fprintf(stdout
, "link %s to %s\n",
xp
->x_linkedto
->x_name
, xp
->x_name
);
if (xlink(xp
->x_linkedto
->x_name
, xp
->x_name
) < 0)
fprintf(stderr
, "link %s to %s failed\n",
xp
->x_linkedto
->x_name
, xp
->x_name
);
restorfiles(command
, argv
)
int rstrfile(), rstrskip();
register struct dinode
*dp
;
register struct inode
*ip
;
strncat(mount
, *argv
, BUFSIZ
);
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
register struct dinode
*ip
;
strncpy(nulldir
.d_name
, "/", DIRSIZ
);
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) {
freopen(dirfile
, "r", df
);
allocinotab(spcl
.c_inumber
, seekpt
);
getfile(putdir
, null
, spcl
.c_dinode
.di_size
);
* Put the directory entries in the directory file
register struct direct
*dp
;
for (dp
= (struct direct
*)buf
, i
= 0; i
< size
; dp
++, i
+= sizeof(*dp
))
fwrite(dp
, 1, sizeof(struct direct
), df
);
* Recursively find names and inumbers of all files in subtree
* pname and put them in xtrlist[]
register struct inotab
*itp
;
char locname
[BUFSIZ
+ 1];
if (BIT(ino
, dumpmap
) == 0) {
fprintf(stdout
, "%s: not on the tape\n", pname
);
for (itp
= inotab
[INOHASH(ino
)]; itp
; itp
= itp
->t_next
) {
* pname is a directory name
allocxtr(ino
, pname
, XISDIR
);
* begin search through the directory
* skipping over "." and ".."
strncpy(locname
, pname
, BUFSIZ
);
strncat(locname
, "/", BUFSIZ
);
namelen
= strlen(locname
);
fseek(df
, itp
->t_seekpt
, 0);
fread(&dir
, 1, sizeof(struct direct
), df
);
fread(&dir
, 1, sizeof(struct direct
), df
);
fread(&dir
, 1, sizeof(struct direct
), df
);
* "/" signals end of directory
while (strncmp(dir
.d_name
, "/", DIRSIZ
)) {
strncat(locname
, dir
.d_name
, DIRSIZ
);
if (strlen(locname
) >= BUFSIZ
) {
fprintf(stderr
, "%s: name exceedes %d char\n",
getleaves(dir
.d_ino
, locname
);
fread(&dir
, 1, sizeof(struct direct
), df
);
* locname is name of a simple file
allocxtr(ino
, pname
, XINUSE
);
* Search the directory tree rooted at inode ROOTINO
* for the path pointed at by n
while (*cp1
!= '/' && *cp1
)
* search the directory inode ino
register struct inotab
*itp
;
for (itp
= inotab
[INOHASH(inum
)]; itp
; itp
= itp
->t_next
)
fseek(df
, itp
->t_seekpt
, 0);
fread(&dir
, 1, sizeof(struct direct
), df
);
if (!strncmp(dir
.d_name
, "/", DIRSIZ
))
} while (strncmp(dir
.d_name
, cp
, DIRSIZ
));
* Do the file extraction, calling the supplied functions
char buf
[BLKING
* FRAG
][TP_BSIZE
];
# define addrblock addrblk.s_spcl
for (i
= 0; i
< addrblock
.c_count
; i
++) {
if (addrblock
.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
) == 0) {
fprintf(stderr
, "Missing address (header) block, ino%u\n", ino
);
if (checktype(&addrblock
, TS_ADDR
) == 0) {
(*f1
)(buf
, (curblk
* TP_BSIZE
) + size
);
* The next routines are called during file extraction to
* put the data into the right form and place.
if (xwrite(ofile
, buf
, (int) size
) == -1) {
perror("extract write:");
if (xseek(ofile
, size
, 1) == -1) {
* 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
);
if (checktype(b
, TS_TAPE
) == 0)
* read the tape into buf, then return whether or
* or not it is a header block.
if (buf
->c_magic
!= MAGIC
|| checksum((int *)buf
) == 0)
* return whether or not the buffer contains a header block
if (buf
->c_magic
!= MAGIC
|| checksum((int *)buf
) == 0)
j
= sizeof(union u_spcl
) / sizeof(int);
fprintf(stderr
, "Checksum error %o, ino %u\n", i
, ino
);
* 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
)) {
* read a bit mask from the tape into m.
m
+= (TP_BSIZE
/(MLEN
/BITS
));
while (gethead(&spcl
) == 0)
register struct inotab
*itp
;
itp
= (struct inotab
*)calloc(1, sizeof(struct inotab
));
itp
->t_next
= inotab
[INOHASH(ino
)];
inotab
[INOHASH(ino
)] = itp
;
allocxtr(ino
, name
, flags
)
register struct xtrlist
*xp
, *pxp
;
xp
= (struct xtrlist
*)calloc(1, sizeof(struct xtrlist
) + strlen(name
));
xp
->x_next
= xtrlist
[INOHASH(ino
)];
xtrlist
[INOHASH(ino
)] = xp
;
strcpy(xp
->x_name
, name
);
for (pxp
= xp
->x_next
; pxp
; pxp
= pxp
->x_next
)
if (pxp
->x_ino
== ino
&& (pxp
->x_flags
& XLINKED
) == 0) {
if (xp
->x_flags
& XLINKED
)
fprintf(stdout
, "%s: linked to %s\n", xp
->x_name
, pxp
->x_name
);
else if (xp
->x_flags
& XISDIR
)
fprintf(stdout
, "%s: directory inode %u\n", xp
->x_name
, ino
);
fprintf(stdout
, "%s: inode %u\n", xp
->x_name
, ino
);
* 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
)