Edit queue control files when running queue (assuming there are still
[unix-history] / usr / src / sbin / restore / main.c
CommitLineData
7d4dda01
KM
1/* Copyright (c) 1981 Regents of the University of California */
2
bcfabedf 3char version[] = "@(#)main.c 1.6 %G%";
7d4dda01
KM
4
5/* Modified to include h option (recursively extract all files within
6 * a subtree) and m option (recreate the heirarchical structure of
7 * that subtree and move extracted files to their proper homes).
8 * 8/29/80 by Mike Litzkow
9 *
10 * Includes the s (skip files) option for use with multiple dumps on
11 * a single tape.
12 */
13
e077bab5 14/* static char *sccsid = "@(#)restor.c 4.3 (Berkeley) 6/3/81"; */
7d4dda01
KM
15
16#define MAXINO 3000
17#define BITS 8
18#define NCACHE 3
7d4dda01
KM
19#define SIZEINC 10
20
21#ifndef STANDALONE
22#include <stdio.h>
23#include <signal.h>
24#endif
003a2a9e
KM
25#include "../h/param.h"
26#include "../h/inode.h"
27#include "../h/fs.h"
28#include "../h/buf.h"
29#include "../h/dir.h"
30#include "../h/user.h"
31#include "../h/dumprestor.h"
7d4dda01
KM
32
33#define MWORD(m,i) (m[(unsigned)(i-1)/MLEN])
34#define MBIT(i) (1<<((unsigned)(i-1)%MLEN))
35#define BIS(i,w) (MWORD(w,i) |= MBIT(i))
36#define BIC(i,w) (MWORD(w,i) &= ~MBIT(i))
37#define BIT(i,w) (MWORD(w,i) & MBIT(i))
38
003a2a9e 39ino_t ino, maxi;
7d4dda01 40
19ac1bc8
KM
41int mt;
42
bcfabedf 43int eflag = 0, hflag = 0, mflag = 0;
7d4dda01 44
003a2a9e
KM
45char mounted = 0;
46dev_t dev = 0;
7d4dda01
KM
47char tapename[] = "/dev/rmt8";
48char *magtape = tapename;
49
50#ifdef STANDALONE
51char mbuf[50];
52#endif
53
7d4dda01 54daddr_t seekpt;
0841dbb0
KM
55FILE *df;
56int ofile;
7d4dda01
KM
57char dirfile[] = "rstXXXXXX";
58
0841dbb0
KM
59#define INOHASH(val) (val % MAXINO)
60struct inotab {
61 struct inotab *t_next;
7d4dda01
KM
62 ino_t t_ino;
63 daddr_t t_seekpt;
0841dbb0 64} *inotab[MAXINO];
7d4dda01 65
0841dbb0 66#define XISDIR 1
7d4dda01
KM
67#define XTRACTD 2
68#define XINUSE 4
0841dbb0 69#define XLINKED 8
7d4dda01 70struct xtrlist {
0841dbb0
KM
71 struct xtrlist *x_next;
72 struct xtrlist *x_linkedto;
0841dbb0 73 time_t x_timep[2];
bcfabedf 74 ino_t x_ino;
0841dbb0 75 char x_flags;
bcfabedf
KM
76 char x_name[1];
77 /* actually longer */
0841dbb0 78} *xtrlist[MAXINO];
19ac1bc8 79int xtrcnt = 0;
7d4dda01 80
7d4dda01
KM
81#include <sys/mtio.h>
82struct mtop tcom;
83
7d4dda01
KM
84int dumpnum = 1;
85int volno = 1;
86
003a2a9e 87struct inode *cur_ip;
7d4dda01
KM
88
89short dumpmap[MSIZ];
90short clrimap[MSIZ];
003a2a9e 91char clearedbuf[BSIZE];
7d4dda01 92
19ac1bc8
KM
93int curblk = 0;
94
7d4dda01 95int bct = NTREC+1;
19ac1bc8 96char tbf[NTREC*TP_BSIZE];
7d4dda01 97
0841dbb0 98extern char *ctime();
bcfabedf 99ino_t search();
003a2a9e 100char **envp;
7d4dda01 101
003a2a9e
KM
102main(argc, argv, arge)
103 int argc;
104 char *argv[];
105 char **arge;
7d4dda01
KM
106{
107 register char *cp;
108 char command;
003a2a9e 109 int (*signal())();
7d4dda01
KM
110 int done();
111
bcfabedf
KM
112 if (signal(SIGINT, done) == SIG_IGN)
113 signal(SIGINT, SIG_IGN);
114 if (signal(SIGTERM, done) == SIG_IGN)
115 signal(SIGTERM, SIG_IGN);
7d4dda01 116#ifndef STANDALONE
003a2a9e
KM
117 envp = arge;
118 mktmp(dirfile);
7d4dda01
KM
119 if (argc < 2) {
120usage:
0841dbb0 121 fprintf(stderr, "Usage: restor x[s|m|h|v] file file..., restor r|R filesys, or restor t\n");
003a2a9e 122 done(1);
7d4dda01
KM
123 }
124 argv++;
125 argc -= 2;
126 for (cp = *argv++; *cp; cp++) {
127 switch (*cp) {
128 case '-':
129 break;
130 case 'f':
131 magtape = *argv++;
132 argc--;
133 break;
134 /* s dumpnum (skip to) for multifile dump tapes */
135 case 's':
136 dumpnum = atoi(*argv++);
137 if(dumpnum <= 0) {
003a2a9e
KM
138 fprintf(stderr, "Dump number must be a positive integer\n");
139 done(1);
7d4dda01
KM
140 }
141 argc--;
142 break;
143 case 'h':
144 hflag++;
145 break;
146 case 'm':
147 mflag++;
148 break;
149 case 'r':
150 case 'R':
151 case 't':
152 case 'x':
153 command = *cp;
154 break;
155 default:
003a2a9e 156 fprintf(stderr, "Bad key character %c\n", *cp);
7d4dda01
KM
157 goto usage;
158 }
159 }
160 if (command == 'x') {
0841dbb0
KM
161 df = fopen(dirfile, "w");
162 if (df == 0) {
003a2a9e
KM
163 fprintf(stderr, "restor: %s - cannot create directory temporary\n", dirfile);
164 done(1);
7d4dda01 165 }
003a2a9e
KM
166 xmount(envp);
167 mounted++;
7d4dda01
KM
168 }
169 doit(command, argc, argv);
003a2a9e 170 done(0);
7d4dda01
KM
171#else
172 magtape = "tape";
173 doit('r', 1, 0);
174#endif
175}
176
177doit(command, argc, argv)
003a2a9e
KM
178 char command;
179 int argc;
180 char *argv[];
7d4dda01 181{
7d4dda01 182#ifndef STANDALONE
7d4dda01 183 if ((mt = open(magtape, 0)) < 0) {
003a2a9e
KM
184 fprintf(stderr, "%s: cannot open tape\n", magtape);
185 done(1);
7d4dda01 186 }
bcfabedf 187 if (dumpnum != 1) {
7d4dda01
KM
188 tcom.mt_op = MTFSF;
189 tcom.mt_count = dumpnum -1;
bcfabedf 190 if (ioctl(mt,MTIOCTOP,&tcom) < 0)
7d4dda01
KM
191 perror("ioctl MTFSF");
192 }
193#else
194 do {
003a2a9e 195 fprintf(stderr, "Tape? ");
7d4dda01
KM
196 gets(mbuf);
197 mt = open(mbuf, 0);
198 } while (mt == -1);
199 magtape = mbuf;
003a2a9e 200 clearbuf(clearedbuf);
7d4dda01
KM
201#endif
202 switch(command) {
203#ifndef STANDALONE
204 case 't':
205 if (readhdr(&spcl) == 0) {
003a2a9e
KM
206 fprintf(stderr, "Tape is not a dump tape\n");
207 done(1);
7d4dda01 208 }
bcfabedf
KM
209 fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date));
210 fprintf(stdout, "Dumped from: %s", ctime(&spcl.c_ddate));
7d4dda01
KM
211 return;
212 case 'x':
0841dbb0
KM
213 extractfiles(argc, argv);
214 return;
215 case 'r':
216 case 'R':
217 restorfiles(command, argv);
218 return;
219 }
220#endif
221}
222
223#ifndef STANDALONE
224extractfiles(argc, argv)
225 int argc;
226 char **argv;
227{
bcfabedf 228 char *ststore();
0841dbb0
KM
229 register struct xtrlist *xp;
230 struct xtrlist **xpp;
231 ino_t d;
232 int xtrfile(), skip(), null();
bcfabedf
KM
233 int mode;
234 char name[BUFSIZ + 1];
0841dbb0
KM
235
236 if (readhdr(&spcl) == 0) {
237 fprintf(stderr, "Tape is not a dump tape\n");
238 done(1);
239 }
240 if (checkvol(&spcl, 1) == 0) {
241 fprintf(stderr, "Tape is not volume 1 of the dump\n");
242 }
243 pass1(); /* This sets the various maps on the way by */
bcfabedf 244 while (argc--) {
0841dbb0 245 if ((d = psearch(*argv)) == 0 || BIT(d,dumpmap) == 0) {
bcfabedf 246 fprintf(stdout, "%s: not on tape\n", *argv++);
0841dbb0 247 continue;
7d4dda01 248 }
bcfabedf
KM
249 if (mflag)
250 checkdir(*argv);
0841dbb0
KM
251 if(hflag)
252 getleaves(d, *argv++);
bcfabedf
KM
253 else
254 allocxtr(d, *argv++, XINUSE);
0841dbb0 255 }
7d4dda01
KM
256
257
0841dbb0
KM
258 if(dumpnum > 1)
259 tcom.mt_op = MTBSF;
260 else tcom.mt_op = MTREW;
261 tcom.mt_count = 1;
7d4dda01
KM
262
263newvol:
0841dbb0
KM
264 flsht();
265 ioctl(mt,MTIOCTOP,&tcom);
bcfabedf 266 if (dumpnum > 1) {
0841dbb0
KM
267 tcom.mt_op = MTFSF;
268 tcom.mt_count = 1;
7d4dda01 269 ioctl(mt,MTIOCTOP,&tcom);
0841dbb0
KM
270 }
271 lseek(mt, (long)0, 0);
7d4dda01
KM
272
273
274getvol:
0841dbb0
KM
275 fprintf(stderr, "Mount desired tape volume: Specify volume #: ");
276 if (gets(tbf) == NULL)
277 return;
278 volno = atoi(tbf);
279 if (volno <= 0) {
280 fprintf(stderr, "Volume numbers are positive numerics\n");
281 goto getvol;
282 }
283 if (readhdr(&spcl) == 0) {
284 fprintf(stderr, "tape is not dump tape\n");
285 goto newvol;
286 }
287 if (checkvol(&spcl, volno) == 0) {
288 fprintf(stderr, "Wrong volume (%d)\n", spcl.c_volume);
289 goto newvol;
290 }
7d4dda01 291rbits:
0841dbb0
KM
292 while (gethead(&spcl) == 0)
293 ;
294 if (checktype(&spcl, TS_INODE) == 1) {
295 fprintf(stderr, "Can't find inode mask!\n");
296 goto newvol;
297 }
298 if (checktype(&spcl, TS_BITS) == 0)
299 goto rbits;
300 readbits(dumpmap);
301 while (xtrcnt > 0) {
302again:
303 if (ishead(&spcl) == 0)
304 while(gethead(&spcl) == 0)
305 ;
306 if (checktype(&spcl, TS_END) == 1) {
307 fprintf(stderr, "end of tape\n");
308 break;
7d4dda01 309 }
0841dbb0
KM
310 if (checktype(&spcl, TS_INODE) == 0) {
311 gethead(&spcl);
312 goto again;
7d4dda01 313 }
0841dbb0
KM
314 d = spcl.c_inumber;
315 for (xp = xtrlist[INOHASH(d)]; xp; xp = xp->x_next) {
316 if (d != xp->x_ino)
317 continue;
318 if (xp->x_flags & XLINKED)
319 continue;
320 xp->x_timep[0] = spcl.c_dinode.di_atime;
321 xp->x_timep[1] = spcl.c_dinode.di_mtime;
322 mode = spcl.c_dinode.di_mode;
323 if (mflag)
bcfabedf 324 strcpy(name, xp->x_name);
0841dbb0
KM
325 else
326 sprintf(name, "%u", xp->x_ino);
327 switch (mode & IFMT) {
328 default:
bcfabedf 329 fprintf(stderr, "%s: unknown file type\n", name);
0841dbb0
KM
330 xp->x_flags |= XTRACTD;
331 xtrcnt--;
332 goto skipfile;
333 case IFCHR:
334 case IFBLK:
bcfabedf 335 fprintf(stdout, "extract special file %s\n", name);
0841dbb0
KM
336 if (xmknod(name, mode, spcl.c_dinode.di_rdev)) {
337 fprintf(stderr, "%s: cannot create special file\n", name);
338 xp->x_flags |= XTRACTD;
339 xtrcnt--;
340 goto skipfile;
19ac1bc8 341 }
0841dbb0
KM
342 getfile(null, null, spcl.c_dinode.di_size);
343 break;
344 case IFDIR:
345 if (mflag) {
bcfabedf 346 fprintf(stdout, "extract directory %s\n", name);
0841dbb0 347 strncat(name, "/.", BUFSIZ);
bcfabedf
KM
348 checkdir(name);
349 xchown(xp->x_name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
0841dbb0
KM
350 getfile(null, null, spcl.c_dinode.di_size);
351 break;
352 }
353 /* else fall through */
354 case IFREG:
bcfabedf 355 fprintf(stdout, "extract file %s\n", name);
0841dbb0
KM
356 if ((ofile = xcreat(name, 0666)) < 0) {
357 fprintf(stderr, "%s: cannot create file\n", name);
358 xp->x_flags |= XTRACTD;
359 xtrcnt--;
360 goto skipfile;
7d4dda01 361 }
0841dbb0
KM
362 xchown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
363 getfile(xtrfile, skip, spcl.c_dinode.di_size);
364 xclose(ofile);
365 break;
7d4dda01 366 }
0841dbb0
KM
367 xchmod(name, mode);
368 xutime(name, xp->x_timep);
369 xp->x_flags |= XTRACTD;
370 xtrcnt--;
371 goto finished;
372 }
373skipfile:
374 getfile(null, null, spcl.c_dinode.di_size);
003a2a9e 375finished:
0841dbb0
KM
376 ;
377 }
378 if (xtrcnt == 0 && !mflag)
379 return;
380 for (xpp = xtrlist; xpp < &xtrlist[MAXINO]; xpp++) {
381 for (xp = *xpp; xp; xp = xp->x_next) {
382 if (mflag && (xp->x_flags & XISDIR))
383 xutime(xp->x_name, xp->x_timep);
384 if (xp->x_flags & XTRACTD)
385 continue;
386 if ((xp->x_flags & XLINKED) == 0) {
387 fprintf(stderr, "cannot find file %s\n",
388 xp->x_name);
389 continue;
390 }
bcfabedf
KM
391 if (!mflag)
392 continue;
393 fprintf(stdout, "link %s to %s\n",
394 xp->x_linkedto->x_name, xp->x_name);
0841dbb0 395 if (xlink(xp->x_linkedto->x_name, xp->x_name) < 0)
bcfabedf
KM
396 fprintf(stderr, "link %s to %s failed\n",
397 xp->x_linkedto->x_name, xp->x_name);
7d4dda01 398 }
0841dbb0
KM
399 }
400}
7d4dda01 401#endif
0841dbb0
KM
402
403restorfiles(command, argv)
404 char command;
405 char **argv;
406{
407 int rstrfile(), rstrskip();
408 register struct dinode *dp;
409 register struct inode *ip;
410 struct fs *fs;
411 int mode;
412 char mount[BUFSIZ + 1];
413 char *ptr[2];
414
7d4dda01 415#ifndef STANDALONE
0841dbb0
KM
416 mount[0] = '\0';
417 strcpy(mount, "MOUNT=");
418 strncat(mount, *argv, BUFSIZ);
419 ptr[0] = mount;
420 ptr[1] = 0;
421 xmount(ptr);
422 iput(u.u_cdir); /* release root inode */
423 iput(u.u_rdir); /* release root inode */
424 mounted++;
7d4dda01 425#else
0841dbb0
KM
426 do {
427 fprintf(stderr, "Disk? ");
428 gets(mount);
429 fi = open(mount, 2);
430 } while (fi == -1);
7d4dda01
KM
431#endif
432#ifndef STANDALONE
0841dbb0
KM
433 if (command == 'R') {
434 fprintf(stderr, "Enter starting volume number: ");
435 if (gets(tbf) == EOF) {
436 volno = 1;
437 fprintf(stderr, "\n");
7d4dda01
KM
438 }
439 else
0841dbb0
KM
440 volno = atoi(tbf);
441 }
442 else
7d4dda01 443#endif
0841dbb0
KM
444 volno = 1;
445 fprintf(stderr, "Last chance before scribbling on %s. ",
7d4dda01 446#ifdef STANDALONE
0841dbb0 447 "disk");
7d4dda01 448#else
0841dbb0 449 *argv);
7d4dda01 450#endif
0841dbb0
KM
451 while (getchar() != '\n');
452 fs = getfs(dev);
453 maxi = fs->fs_ipg * fs->fs_ncg;
454 if (readhdr(&spcl) == 0) {
455 fprintf(stderr, "Missing volume record\n");
456 done(1);
457 }
458 if (checkvol(&spcl, volno) == 0) {
459 fprintf(stderr, "Tape is not volume %d\n", volno);
460 done(1);
461 }
462 gethead(&spcl);
463 for (;;) {
464ragain:
465 if (ishead(&spcl) == 0) {
466 fprintf(stderr, "Missing header block\n");
467 while (gethead(&spcl) == 0)
468 ;
469 eflag++;
7d4dda01 470 }
0841dbb0
KM
471 if (checktype(&spcl, TS_END) == 1) {
472 fprintf(stderr, "End of tape\n");
473 close(mt);
474 return;
7d4dda01 475 }
0841dbb0
KM
476 if (checktype(&spcl, TS_CLRI) == 1) {
477 readbits(clrimap);
478 for (ino = 1; ino <= maxi; ino++)
479 if (BIT(ino, clrimap) == 0) {
480 if (!iexist(dev, ino))
481 continue;
482 ip = iget(dev, ino);
483 if (ip == NULL) {
484 fprintf(stderr, "can't find inode %u\n", ino);
485 done(1);
7d4dda01 486 }
0841dbb0
KM
487 ip->i_nlink = 0;
488 ip->i_flag |= ICHG;
489 iput(ip);
003a2a9e 490 }
0841dbb0
KM
491 goto ragain;
492 }
493 if (checktype(&spcl, TS_BITS) == 1) {
494 readbits(dumpmap);
495 goto ragain;
496 }
497 if (checktype(&spcl, TS_INODE) == 0) {
498 fprintf(stderr, "Unknown header type\n");
499 eflag++;
500 gethead(&spcl);
501 goto ragain;
502 }
503 ino = spcl.c_inumber;
504 if (eflag)
505 fprintf(stderr, "Resynced at inode %u\n", ino);
506 eflag = 0;
507 if (ino > maxi) {
508 fprintf(stderr, "%u: ilist too small\n", ino);
509 gethead(&spcl);
510 goto ragain;
511 }
512 if (iexist(dev, ino)) {
513 ip = iget(dev, ino);
514 if (ip == NULL) {
515 fprintf(stderr, "can't find inode %u\n",
516 ino);
003a2a9e
KM
517 done(1);
518 }
0841dbb0 519 ip->i_nlink = 0;
003a2a9e
KM
520 ip->i_flag |= ICHG;
521 iput(ip);
7d4dda01 522 }
0841dbb0
KM
523 dp = &spcl.c_dinode;
524 ip = ialloc(dev, ino, dp->di_mode);
525 if (ip == NULL || ip->i_number != ino) {
526 fprintf(stderr, "can't create inode %u\n", ino);
527 done(1);
528 }
529 ip->i_mode = mode = dp->di_mode;
530 ip->i_nlink = dp->di_nlink;
531 ip->i_uid = dp->di_uid;
532 ip->i_gid = dp->di_gid;
533 ip->i_atime = dp->di_atime;
534 ip->i_mtime = dp->di_mtime;
535 ip->i_ctime = dp->di_ctime;
536 if ((ip->i_mode & IFMT) == IFCHR ||
537 (ip->i_mode & IFMT) == IFBLK)
538 ip->i_rdev = dp->di_rdev;
539 ip->i_size = 0;
540 cur_ip = ip;
541 u.u_offset = 0;
542 u.u_segflg = 1;
543 getfile(rstrfile, rstrskip, dp->di_size);
544 ip->i_mode = mode;
545 ip->i_flag &= ~(IUPD|IACC);
546 ip->i_flag |= ICHG;
547 iput(ip);
7d4dda01
KM
548 }
549}
550
551/*
552 * Read the tape, bulding up a directory structure for extraction
553 * by name
554 */
555#ifndef STANDALONE
556pass1()
557{
19ac1bc8 558 register int i;
0841dbb0
KM
559 register struct dinode *ip;
560 struct direct nulldir;
7d4dda01
KM
561 int putdir(), null();
562
0841dbb0
KM
563 nulldir.d_ino = 0;
564 strncpy(nulldir.d_name, "/", DIRSIZ);
7d4dda01 565 while (gethead(&spcl) == 0) {
003a2a9e 566 fprintf(stderr, "Can't find directory header!\n");
7d4dda01
KM
567 }
568 for (;;) {
569 if (checktype(&spcl, TS_BITS) == 1) {
570 readbits(dumpmap);
571 continue;
572 }
573 if (checktype(&spcl, TS_CLRI) == 1) {
574 readbits(clrimap);
575 continue;
576 }
577 if (checktype(&spcl, TS_INODE) == 0) {
578finish:
7d4dda01
KM
579/*
580 close(mt);
581*/
0841dbb0 582 freopen(dirfile, "r", df);
7d4dda01
KM
583 return;
584 }
585 ip = &spcl.c_dinode;
586 i = ip->di_mode & IFMT;
587 if (i != IFDIR) {
588 goto finish;
589 }
bcfabedf 590 allocinotab(spcl.c_inumber, seekpt);
003a2a9e 591 getfile(putdir, null, spcl.c_dinode.di_size);
0841dbb0 592 putent(&nulldir);
7d4dda01
KM
593 }
594}
595#endif
596
bcfabedf
KM
597/*
598 * Put the directory entries in the directory file
599 */
600#ifndef STANDALONE
601putdir(buf, size)
602 char *buf;
603 int size;
604{
605 register struct direct *dp;
606 register int i;
607
608 for (dp = (struct direct *)buf, i = 0; i < size; dp++, i += sizeof(*dp))
609 if (dp->d_ino != 0)
610 putent(dp);
611}
612
613putent(dp)
614 struct direct *dp;
615{
616 fwrite(dp, 1, sizeof(struct direct), df);
617 seekpt = ftell(df);
618}
619
620/*
621 * Recursively find names and inumbers of all files in subtree
622 * pname and put them in xtrlist[]
623 */
624getleaves(ino, pname)
625 ino_t ino;
626 char *pname;
627{
628 register struct inotab *itp;
629 int namelen;
630 daddr_t bpt;
631 struct direct dir;
632 char locname[BUFSIZ + 1];
633
634 if (BIT(ino, dumpmap) == 0) {
635 fprintf(stdout, "%s: not on the tape\n", pname);
636 return;
637 }
638 for (itp = inotab[INOHASH(ino)]; itp; itp = itp->t_next) {
639 if (itp->t_ino != ino)
640 continue;
641 /*
642 * pname is a directory name
643 */
644 allocxtr(ino, pname, XISDIR);
645 /*
646 * begin search through the directory
647 * skipping over "." and ".."
648 */
649 strncpy(locname, pname, BUFSIZ);
650 strncat(locname, "/", BUFSIZ);
651 namelen = strlen(locname);
652 fseek(df, itp->t_seekpt, 0);
653 fread(&dir, 1, sizeof(struct direct), df);
654 fread(&dir, 1, sizeof(struct direct), df);
655 fread(&dir, 1, sizeof(struct direct), df);
656 bpt = ftell(df);
657 /*
658 * "/" signals end of directory
659 */
660 while (strncmp(dir.d_name, "/", DIRSIZ)) {
661 locname[namelen] = '\0';
662 strncat(locname, dir.d_name, DIRSIZ);
663 if (strlen(locname) >= BUFSIZ) {
664 fprintf(stderr, "%s: name exceedes %d char\n",
665 locname, BUFSIZ);
666 continue;
667 }
668 getleaves(dir.d_ino, locname);
669 fseek(df, bpt, 0);
670 fread(&dir, 1, sizeof(struct direct), df);
671 bpt = ftell(df);
672 }
673 return;
674 }
675 /*
676 * locname is name of a simple file
677 */
678 allocxtr(ino, pname, XINUSE);
679}
680
681/*
682 * Search the directory tree rooted at inode ROOTINO
683 * for the path pointed at by n
684 */
685psearch(n)
686 char *n;
687{
688 register char *cp, *cp1;
689 char c;
690
691 ino = ROOTINO;
692 if (*(cp = n) == '/')
693 cp++;
694next:
695 cp1 = cp + 1;
696 while (*cp1 != '/' && *cp1)
697 cp1++;
698 c = *cp1;
699 *cp1 = 0;
700 ino = search(ino, cp);
701 if (ino == 0) {
702 *cp1 = c;
703 return(0);
704 }
705 *cp1 = c;
706 if (c == '/') {
707 cp = cp1+1;
708 goto next;
709 }
710 return(ino);
711}
712
713/*
714 * search the directory inode ino
715 * looking for entry cp
716 */
717ino_t
718search(inum, cp)
719 ino_t inum;
720 char *cp;
721{
722 struct direct dir;
723 register struct inotab *itp;
724
725 for (itp = inotab[INOHASH(inum)]; itp; itp = itp->t_next)
726 if (itp->t_ino == inum)
727 goto found;
728 return(0);
729found:
730 fseek(df, itp->t_seekpt, 0);
731 do {
732 fread(&dir, 1, sizeof(struct direct), df);
733 if (!strncmp(dir.d_name, "/", DIRSIZ))
734 return(0);
735 } while (strncmp(dir.d_name, cp, DIRSIZ));
736 return(dir.d_ino);
737}
738#endif
739
7d4dda01
KM
740/*
741 * Do the file extraction, calling the supplied functions
742 * with the blocks
743 */
003a2a9e
KM
744getfile(f1, f2, size)
745 int (*f2)(), (*f1)();
746 long size;
7d4dda01 747{
19ac1bc8 748 register int i;
19ac1bc8 749 char buf[BLKING * FRAG][TP_BSIZE];
0841dbb0
KM
750 union u_spcl addrblk;
751# define addrblock addrblk.s_spcl
7d4dda01 752
0841dbb0 753 addrblock = spcl;
7d4dda01 754 for (;;) {
0841dbb0
KM
755 for (i = 0; i < addrblock.c_count; i++) {
756 if (addrblock.c_addr[i]) {
19ac1bc8
KM
757 readtape(&buf[curblk++][0]);
758 if (curblk == BLKING * FRAG) {
759 (*f1)(buf, size > TP_BSIZE ?
760 (long) (BLKING * FRAG * TP_BSIZE) :
761 (curblk - 1) * TP_BSIZE + size);
762 curblk = 0;
763 }
7d4dda01
KM
764 }
765 else {
19ac1bc8
KM
766 if (curblk > 0) {
767 (*f1)(buf, size > TP_BSIZE ?
768 (long) (curblk * TP_BSIZE) :
769 (curblk - 1) * TP_BSIZE + size);
770 curblk = 0;
771 }
772 (*f2)(clearedbuf, size > TP_BSIZE ? (long) TP_BSIZE : size);
7d4dda01 773 }
19ac1bc8 774 if ((size -= TP_BSIZE) <= 0) {
7d4dda01
KM
775eloop:
776 while (gethead(&spcl) == 0)
777 ;
778 if (checktype(&spcl, TS_ADDR) == 1)
779 goto eloop;
19ac1bc8 780 goto out;
7d4dda01
KM
781 }
782 }
0841dbb0 783 if (gethead(&addrblock) == 0) {
19ac1bc8 784 fprintf(stderr, "Missing address (header) block, ino%u\n", ino);
003a2a9e
KM
785 goto eloop;
786 }
0841dbb0
KM
787 if (checktype(&addrblock, TS_ADDR) == 0) {
788 spcl = addrblock;
19ac1bc8 789 goto out;
003a2a9e 790 }
7d4dda01 791 }
19ac1bc8
KM
792out:
793 if (curblk > 0) {
794 (*f1)(buf, (curblk * TP_BSIZE) + size);
795 curblk = 0;
796 }
7d4dda01
KM
797}
798
bcfabedf
KM
799/*
800 * The next routines are called during file extraction to
801 * put the data into the right form and place.
802 */
803#ifndef STANDALONE
804xtrfile(buf, size)
805 char *buf;
806 long size;
807{
808 if (xwrite(ofile, buf, (int) size) == -1) {
809 perror("extract write:");
810 done(1);
811 }
812}
813
814skip(buf, size)
815 char *buf;
816 long size;
817{
818 if (xseek(ofile, size, 1) == -1) {
819 perror("extract seek:");
820 done(1);
821 }
822}
823#endif
824
825
826rstrfile(buf, size)
827 char *buf;
828 long size;
829{
830 u.u_base = buf;
831 u.u_count = size;
832 writei(cur_ip);
833 if (u.u_error) {
834 perror("restor write:");
835 done(1);
836 }
837}
838
839rstrskip(buf, size)
840 char *buf;
841 long size;
842{
843 u.u_offset += size;
844}
845
846null() {;}
847
7d4dda01 848/*
19ac1bc8 849 * Do the tape i/o, dealing with volume changes
7d4dda01
KM
850 * etc..
851 */
852readtape(b)
003a2a9e 853 char *b;
7d4dda01 854{
19ac1bc8 855 register int i;
0841dbb0 856 struct s_spcl tmpbuf;
7d4dda01
KM
857
858 if (bct >= NTREC) {
859 for (i = 0; i < NTREC; i++)
19ac1bc8 860 ((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0;
7d4dda01 861 bct = 0;
19ac1bc8 862 if ((i = read(mt, tbf, NTREC*TP_BSIZE)) < 0) {
003a2a9e 863 perror("Tape read error");
7d4dda01 864 eflag++;
003a2a9e 865 done(1);
7d4dda01
KM
866 }
867 if (i == 0) {
868 bct = NTREC + 1;
869 volno++;
870loop:
871 flsht();
872 close(mt);
003a2a9e 873 fprintf(stderr, "Mount volume %d\n", volno);
7d4dda01
KM
874 while (getchar() != '\n')
875 ;
876 if ((mt = open(magtape, 0)) == -1) {
003a2a9e 877 fprintf(stderr, "Cannot open tape!\n");
7d4dda01
KM
878 goto loop;
879 }
880 if (readhdr(&tmpbuf) == 0) {
003a2a9e 881 fprintf(stderr, "Not a dump tape.Try again\n");
7d4dda01
KM
882 goto loop;
883 }
884 if (checkvol(&tmpbuf, volno) == 0) {
003a2a9e 885 fprintf(stderr, "Wrong tape. Try again\n");
7d4dda01
KM
886 goto loop;
887 }
888 readtape(b);
889 return;
890 }
891 }
19ac1bc8 892 copy(&tbf[(bct++*TP_BSIZE)], b, TP_BSIZE);
7d4dda01
KM
893}
894
895flsht()
896{
897 bct = NTREC+1;
898}
899
900copy(f, t, s)
003a2a9e 901 register char *f, *t;
7d4dda01 902{
19ac1bc8 903 register int i;
7d4dda01
KM
904
905 i = s;
906 do
907 *t++ = *f++;
908 while (--i);
909}
910
bcfabedf
KM
911checkvol(b, t)
912 struct s_spcl *b;
913 int t;
7d4dda01 914{
bcfabedf
KM
915 if (b->c_volume == t)
916 return(1);
7d4dda01 917 return(0);
7d4dda01
KM
918}
919
bcfabedf
KM
920readhdr(b)
921 struct s_spcl *b;
7d4dda01 922{
bcfabedf 923 if (gethead(b) == 0)
7d4dda01 924 return(0);
bcfabedf
KM
925 if (checktype(b, TS_TAPE) == 0)
926 return(0);
927 return(1);
7d4dda01 928}
7d4dda01 929
7d4dda01
KM
930/*
931 * read the tape into buf, then return whether or
932 * or not it is a header block.
933 */
934gethead(buf)
0841dbb0 935 struct s_spcl *buf;
7d4dda01
KM
936{
937 readtape((char *)buf);
0841dbb0 938 if (buf->c_magic != MAGIC || checksum((int *)buf) == 0)
7d4dda01
KM
939 return(0);
940 return(1);
941}
942
943/*
944 * return whether or not the buffer contains a header block
945 */
946ishead(buf)
0841dbb0 947 struct s_spcl *buf;
7d4dda01 948{
0841dbb0 949 if (buf->c_magic != MAGIC || checksum((int *)buf) == 0)
7d4dda01
KM
950 return(0);
951 return(1);
952}
953
954checktype(b, t)
0841dbb0 955 struct s_spcl *b;
003a2a9e 956 int t;
7d4dda01 957{
0841dbb0 958 return(b->c_type == t);
7d4dda01
KM
959}
960
961
962checksum(b)
003a2a9e 963 int *b;
7d4dda01 964{
19ac1bc8 965 register int i, j;
7d4dda01 966
19ac1bc8 967 j = sizeof(union u_spcl) / sizeof(int);
7d4dda01
KM
968 i = 0;
969 do
970 i += *b++;
971 while (--j);
972 if (i != CHECKSUM) {
19ac1bc8 973 fprintf(stderr, "Checksum error %o, ino %u\n", i, ino);
7d4dda01
KM
974 return(0);
975 }
976 return(1);
977}
978
003a2a9e
KM
979/*
980 * tell whether an inode is allocated
981 * this is drawn from ialloccg in sys/alloc.c
982 */
983iexist(dev, ino)
984 dev_t dev;
985 ino_t ino;
7d4dda01 986{
003a2a9e
KM
987 register struct fs *fs;
988 register struct cg *cgp;
989 register struct buf *bp;
990 int cg;
991
992 fs = getfs(dev);
993 if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg)
994 return (0);
995 cg = itog(ino, fs);
996 bp = bread(dev, cgtod(cg, fs), BSIZE);
997 if (bp->b_flags & B_ERROR)
998 return(0);
999 cgp = bp->b_un.b_cg;
1000 ino %= fs->fs_ipg;
1001 if (isclr(cgp->cg_iused, ino)) {
1002 brelse(bp);
1003 return(0);
1004 }
1005 brelse(bp);
1006 return (1);
7d4dda01
KM
1007}
1008
7d4dda01
KM
1009/*
1010 * read a bit mask from the tape into m.
1011 */
1012readbits(m)
003a2a9e 1013 short *m;
7d4dda01 1014{
19ac1bc8 1015 register int i;
7d4dda01
KM
1016
1017 i = spcl.c_count;
1018
1019 while (i--) {
1020 readtape((char *) m);
19ac1bc8 1021 m += (TP_BSIZE/(MLEN/BITS));
7d4dda01
KM
1022 }
1023 while (gethead(&spcl) == 0)
1024 ;
1025}
1026
003a2a9e
KM
1027done(exitcode)
1028 int exitcode;
7d4dda01
KM
1029{
1030#ifndef STANDALONE
1031 unlink(dirfile);
1032#endif
003a2a9e
KM
1033 if (mounted)
1034 xumount();
1035 exit(exitcode);
7d4dda01
KM
1036}
1037
bcfabedf 1038allocinotab(ino, seekpt)
0841dbb0 1039 ino_t ino;
bcfabedf 1040 daddr_t seekpt;
7d4dda01 1041{
0841dbb0 1042 register struct inotab *itp;
19ac1bc8 1043
0841dbb0
KM
1044 itp = (struct inotab *)calloc(1, sizeof(struct inotab));
1045 itp->t_next = inotab[INOHASH(ino)];
1046 inotab[INOHASH(ino)] = itp;
1047 itp->t_ino = ino;
bcfabedf 1048 itp->t_seekpt = seekpt;
7d4dda01
KM
1049}
1050
bcfabedf 1051allocxtr(ino, name, flags)
0841dbb0 1052 ino_t ino;
bcfabedf
KM
1053 char *name;
1054 char flags;
7d4dda01 1055{
bcfabedf 1056 register struct xtrlist *xp, *pxp;
0841dbb0 1057
bcfabedf 1058 xp = (struct xtrlist *)calloc(1, sizeof(struct xtrlist) + strlen(name));
0841dbb0
KM
1059 xp->x_next = xtrlist[INOHASH(ino)];
1060 xtrlist[INOHASH(ino)] = xp;
1061 xp->x_ino = ino;
bcfabedf 1062 strcpy(xp->x_name, name);
0841dbb0 1063 xtrcnt++;
bcfabedf
KM
1064 xp->x_flags = flags;
1065 for (pxp = xp->x_next; pxp; pxp = pxp->x_next)
1066 if (pxp->x_ino == ino && (pxp->x_flags & XLINKED) == 0) {
1067 xp->x_flags |= XLINKED;
1068 xp->x_linkedto = pxp;
1069 xtrcnt--;
1070 break;
1071 }
1072 if (xp->x_flags & XLINKED)
1073 fprintf(stdout, "%s: linked to %s\n", xp->x_name, pxp->x_name);
1074 else if (xp->x_flags & XISDIR)
1075 fprintf(stdout, "%s: directory inode %u\n", xp->x_name, ino);
1076 else
1077 fprintf(stdout, "%s: inode %u\n", xp->x_name, ino);
7d4dda01
KM
1078}
1079
1080/*
1081 * Check for access into each directory in the pathname of an extracted
1082 * file and create such a directory if needed in preparation for moving
1083 * the file to its proper home.
1084 */
1085checkdir(name)
003a2a9e 1086 register char *name;
7d4dda01
KM
1087{
1088 register char *cp;
1089 int i;
19ac1bc8 1090
7d4dda01
KM
1091 for (cp = name; *cp; cp++) {
1092 if (*cp == '/') {
1093 *cp = '\0';
003a2a9e 1094 if (xaccess(name, 01) < 0) {
7d4dda01
KM
1095 register int pid, rp;
1096
003a2a9e 1097 xumount();
7d4dda01 1098 if ((pid = fork()) == 0) {
003a2a9e
KM
1099 execl("/bin/xmkdir", "xmkdir", name, 0);
1100 execl("/usr/bin/xmkdir", "xmkdir", name, 0);
1101 execl("./xmkdir", "xmkdir", name, 0);
1102 fprintf(stderr, "xrestor: cannot find xmkdir!\n");
7d4dda01
KM
1103 done(0);
1104 }
1105 while ((rp = wait(&i)) >= 0 && rp != pid)
1106 ;
003a2a9e 1107 xmount(envp);
7d4dda01
KM
1108 }
1109 *cp = '/';
1110 }
1111 }
1112}