14610Smckusick /* Copyright (c) 1981 Regents of the University of California */ 24610Smckusick 3*4843Smckusic char version[] = "@(#)main.c 1.6 11/10/81"; 44610Smckusick 54610Smckusick /* Modified to include h option (recursively extract all files within 64610Smckusick * a subtree) and m option (recreate the heirarchical structure of 74610Smckusick * that subtree and move extracted files to their proper homes). 84610Smckusick * 8/29/80 by Mike Litzkow 94610Smckusick * 104610Smckusick * Includes the s (skip files) option for use with multiple dumps on 114610Smckusick * a single tape. 124610Smckusick */ 134610Smckusick 144611Smckusic /* static char *sccsid = "@(#)restor.c 4.3 (Berkeley) 6/3/81"; */ 154610Smckusick 164610Smckusick #define MAXINO 3000 174610Smckusick #define BITS 8 184610Smckusick #define NCACHE 3 194610Smckusick #define SIZEINC 10 204610Smckusick 214610Smckusick #ifndef STANDALONE 224610Smckusick #include <stdio.h> 234610Smckusick #include <signal.h> 244610Smckusick #endif 254700Smckusic #include "../h/param.h" 264700Smckusic #include "../h/inode.h" 274700Smckusic #include "../h/fs.h" 284700Smckusic #include "../h/buf.h" 294700Smckusic #include "../h/dir.h" 304700Smckusic #include "../h/user.h" 314700Smckusic #include "../h/dumprestor.h" 324610Smckusick 334610Smckusick #define MWORD(m,i) (m[(unsigned)(i-1)/MLEN]) 344610Smckusick #define MBIT(i) (1<<((unsigned)(i-1)%MLEN)) 354610Smckusick #define BIS(i,w) (MWORD(w,i) |= MBIT(i)) 364610Smckusick #define BIC(i,w) (MWORD(w,i) &= ~MBIT(i)) 374610Smckusick #define BIT(i,w) (MWORD(w,i) & MBIT(i)) 384610Smckusick 394700Smckusic ino_t ino, maxi; 404610Smckusick 414776Smckusic int mt; 424776Smckusic 43*4843Smckusic int eflag = 0, hflag = 0, mflag = 0; 444610Smckusick 454700Smckusic char mounted = 0; 464700Smckusic dev_t dev = 0; 474610Smckusick char tapename[] = "/dev/rmt8"; 484610Smckusick char *magtape = tapename; 494610Smckusick 504610Smckusick #ifdef STANDALONE 514610Smckusick char mbuf[50]; 524610Smckusick #endif 534610Smckusick 544610Smckusick daddr_t seekpt; 554837Smckusic FILE *df; 564837Smckusic int ofile; 574610Smckusick char dirfile[] = "rstXXXXXX"; 584610Smckusick 594837Smckusic #define INOHASH(val) (val % MAXINO) 604837Smckusic struct inotab { 614837Smckusic struct inotab *t_next; 624610Smckusick ino_t t_ino; 634610Smckusick daddr_t t_seekpt; 644837Smckusic } *inotab[MAXINO]; 654610Smckusick 664837Smckusic #define XISDIR 1 674610Smckusick #define XTRACTD 2 684610Smckusick #define XINUSE 4 694837Smckusic #define XLINKED 8 704610Smckusick struct xtrlist { 714837Smckusic struct xtrlist *x_next; 724837Smckusic struct xtrlist *x_linkedto; 73*4843Smckusic time_t x_timep[2]; 744837Smckusic ino_t x_ino; 754837Smckusic char x_flags; 76*4843Smckusic char x_name[1]; 77*4843Smckusic /* actually longer */ 784837Smckusic } *xtrlist[MAXINO]; 794776Smckusic int xtrcnt = 0; 804610Smckusick 814610Smckusick #include <sys/mtio.h> 824610Smckusick struct mtop tcom; 834610Smckusick 844610Smckusick int dumpnum = 1; 854610Smckusick int volno = 1; 864610Smckusick 874700Smckusic struct inode *cur_ip; 884610Smckusick 894610Smckusick short dumpmap[MSIZ]; 904610Smckusick short clrimap[MSIZ]; 914700Smckusic char clearedbuf[BSIZE]; 924610Smckusick 934776Smckusic int curblk = 0; 944776Smckusic 954610Smckusick int bct = NTREC+1; 964776Smckusic char tbf[NTREC*TP_BSIZE]; 974610Smckusick 984837Smckusic extern char *ctime(); 99*4843Smckusic ino_t search(); 1004700Smckusic char **envp; 1014610Smckusick 1024700Smckusic main(argc, argv, arge) 1034700Smckusic int argc; 1044700Smckusic char *argv[]; 1054700Smckusic char **arge; 1064610Smckusick { 1074610Smckusick register char *cp; 1084610Smckusick char command; 1094700Smckusic int (*signal())(); 1104610Smckusick int done(); 1114610Smckusick 112*4843Smckusic if (signal(SIGINT, done) == SIG_IGN) 113*4843Smckusic signal(SIGINT, SIG_IGN); 114*4843Smckusic if (signal(SIGTERM, done) == SIG_IGN) 115*4843Smckusic signal(SIGTERM, SIG_IGN); 1164610Smckusick #ifndef STANDALONE 1174700Smckusic envp = arge; 1184700Smckusic mktmp(dirfile); 1194610Smckusick if (argc < 2) { 1204610Smckusick usage: 1214837Smckusic fprintf(stderr, "Usage: restor x[s|m|h|v] file file..., restor r|R filesys, or restor t\n"); 1224700Smckusic done(1); 1234610Smckusick } 1244610Smckusick argv++; 1254610Smckusick argc -= 2; 1264610Smckusick for (cp = *argv++; *cp; cp++) { 1274610Smckusick switch (*cp) { 1284610Smckusick case '-': 1294610Smckusick break; 1304610Smckusick case 'f': 1314610Smckusick magtape = *argv++; 1324610Smckusick argc--; 1334610Smckusick break; 1344610Smckusick /* s dumpnum (skip to) for multifile dump tapes */ 1354610Smckusick case 's': 1364610Smckusick dumpnum = atoi(*argv++); 1374610Smckusick if(dumpnum <= 0) { 1384700Smckusic fprintf(stderr, "Dump number must be a positive integer\n"); 1394700Smckusic done(1); 1404610Smckusick } 1414610Smckusick argc--; 1424610Smckusick break; 1434610Smckusick case 'h': 1444610Smckusick hflag++; 1454610Smckusick break; 1464610Smckusick case 'm': 1474610Smckusick mflag++; 1484610Smckusick break; 1494610Smckusick case 'r': 1504610Smckusick case 'R': 1514610Smckusick case 't': 1524610Smckusick case 'x': 1534610Smckusick command = *cp; 1544610Smckusick break; 1554610Smckusick default: 1564700Smckusic fprintf(stderr, "Bad key character %c\n", *cp); 1574610Smckusick goto usage; 1584610Smckusick } 1594610Smckusick } 1604610Smckusick if (command == 'x') { 1614837Smckusic df = fopen(dirfile, "w"); 1624837Smckusic if (df == 0) { 1634700Smckusic fprintf(stderr, "restor: %s - cannot create directory temporary\n", dirfile); 1644700Smckusic done(1); 1654610Smckusick } 1664700Smckusic xmount(envp); 1674700Smckusic mounted++; 1684610Smckusick } 1694610Smckusick doit(command, argc, argv); 1704700Smckusic done(0); 1714610Smckusick #else 1724610Smckusick magtape = "tape"; 1734610Smckusick doit('r', 1, 0); 1744610Smckusick #endif 1754610Smckusick } 1764610Smckusick 1774610Smckusick doit(command, argc, argv) 1784700Smckusic char command; 1794700Smckusic int argc; 1804700Smckusic char *argv[]; 1814610Smckusick { 1824610Smckusick #ifndef STANDALONE 1834610Smckusick if ((mt = open(magtape, 0)) < 0) { 1844700Smckusic fprintf(stderr, "%s: cannot open tape\n", magtape); 1854700Smckusic done(1); 1864610Smckusick } 187*4843Smckusic if (dumpnum != 1) { 1884610Smckusick tcom.mt_op = MTFSF; 1894610Smckusick tcom.mt_count = dumpnum -1; 190*4843Smckusic if (ioctl(mt,MTIOCTOP,&tcom) < 0) 1914610Smckusick perror("ioctl MTFSF"); 1924610Smckusick } 1934610Smckusick #else 1944610Smckusick do { 1954700Smckusic fprintf(stderr, "Tape? "); 1964610Smckusick gets(mbuf); 1974610Smckusick mt = open(mbuf, 0); 1984610Smckusick } while (mt == -1); 1994610Smckusick magtape = mbuf; 2004700Smckusic clearbuf(clearedbuf); 2014610Smckusick #endif 2024610Smckusick switch(command) { 2034610Smckusick #ifndef STANDALONE 2044610Smckusick case 't': 2054610Smckusick if (readhdr(&spcl) == 0) { 2064700Smckusic fprintf(stderr, "Tape is not a dump tape\n"); 2074700Smckusic done(1); 2084610Smckusick } 209*4843Smckusic fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date)); 210*4843Smckusic fprintf(stdout, "Dumped from: %s", ctime(&spcl.c_ddate)); 2114610Smckusick return; 2124610Smckusick case 'x': 2134837Smckusic extractfiles(argc, argv); 2144837Smckusic return; 2154837Smckusic case 'r': 2164837Smckusic case 'R': 2174837Smckusic restorfiles(command, argv); 2184837Smckusic return; 2194837Smckusic } 2204837Smckusic #endif 2214837Smckusic } 2224837Smckusic 2234837Smckusic #ifndef STANDALONE 2244837Smckusic extractfiles(argc, argv) 2254837Smckusic int argc; 2264837Smckusic char **argv; 2274837Smckusic { 228*4843Smckusic char *ststore(); 2294837Smckusic register struct xtrlist *xp; 2304837Smckusic struct xtrlist **xpp; 2314837Smckusic ino_t d; 2324837Smckusic int xtrfile(), skip(), null(); 233*4843Smckusic int mode; 234*4843Smckusic char name[BUFSIZ + 1]; 2354837Smckusic 2364837Smckusic if (readhdr(&spcl) == 0) { 2374837Smckusic fprintf(stderr, "Tape is not a dump tape\n"); 2384837Smckusic done(1); 2394837Smckusic } 2404837Smckusic if (checkvol(&spcl, 1) == 0) { 2414837Smckusic fprintf(stderr, "Tape is not volume 1 of the dump\n"); 2424837Smckusic } 2434837Smckusic pass1(); /* This sets the various maps on the way by */ 244*4843Smckusic while (argc--) { 2454837Smckusic if ((d = psearch(*argv)) == 0 || BIT(d,dumpmap) == 0) { 246*4843Smckusic fprintf(stdout, "%s: not on tape\n", *argv++); 2474837Smckusic continue; 2484610Smckusick } 249*4843Smckusic if (mflag) 250*4843Smckusic checkdir(*argv); 2514837Smckusic if(hflag) 2524837Smckusic getleaves(d, *argv++); 253*4843Smckusic else 254*4843Smckusic allocxtr(d, *argv++, XINUSE); 2554837Smckusic } 2564610Smckusick 2574610Smckusick 2584837Smckusic if(dumpnum > 1) 2594837Smckusic tcom.mt_op = MTBSF; 2604837Smckusic else tcom.mt_op = MTREW; 2614837Smckusic tcom.mt_count = 1; 2624610Smckusick 2634610Smckusick newvol: 2644837Smckusic flsht(); 2654837Smckusic ioctl(mt,MTIOCTOP,&tcom); 266*4843Smckusic if (dumpnum > 1) { 2674837Smckusic tcom.mt_op = MTFSF; 2684837Smckusic tcom.mt_count = 1; 2694610Smckusick ioctl(mt,MTIOCTOP,&tcom); 2704837Smckusic } 2714837Smckusic lseek(mt, (long)0, 0); 2724610Smckusick 2734610Smckusick 2744610Smckusick getvol: 2754837Smckusic fprintf(stderr, "Mount desired tape volume: Specify volume #: "); 2764837Smckusic if (gets(tbf) == NULL) 2774837Smckusic return; 2784837Smckusic volno = atoi(tbf); 2794837Smckusic if (volno <= 0) { 2804837Smckusic fprintf(stderr, "Volume numbers are positive numerics\n"); 2814837Smckusic goto getvol; 2824837Smckusic } 2834837Smckusic if (readhdr(&spcl) == 0) { 2844837Smckusic fprintf(stderr, "tape is not dump tape\n"); 2854837Smckusic goto newvol; 2864837Smckusic } 2874837Smckusic if (checkvol(&spcl, volno) == 0) { 2884837Smckusic fprintf(stderr, "Wrong volume (%d)\n", spcl.c_volume); 2894837Smckusic goto newvol; 2904837Smckusic } 2914610Smckusick rbits: 2924837Smckusic while (gethead(&spcl) == 0) 2934837Smckusic ; 2944837Smckusic if (checktype(&spcl, TS_INODE) == 1) { 2954837Smckusic fprintf(stderr, "Can't find inode mask!\n"); 2964837Smckusic goto newvol; 2974837Smckusic } 2984837Smckusic if (checktype(&spcl, TS_BITS) == 0) 2994837Smckusic goto rbits; 3004837Smckusic readbits(dumpmap); 3014837Smckusic while (xtrcnt > 0) { 3024837Smckusic again: 3034837Smckusic if (ishead(&spcl) == 0) 3044837Smckusic while(gethead(&spcl) == 0) 3054837Smckusic ; 3064837Smckusic if (checktype(&spcl, TS_END) == 1) { 3074837Smckusic fprintf(stderr, "end of tape\n"); 3084837Smckusic break; 3094610Smckusick } 3104837Smckusic if (checktype(&spcl, TS_INODE) == 0) { 3114837Smckusic gethead(&spcl); 3124837Smckusic goto again; 3134610Smckusick } 3144837Smckusic d = spcl.c_inumber; 3154837Smckusic for (xp = xtrlist[INOHASH(d)]; xp; xp = xp->x_next) { 3164837Smckusic if (d != xp->x_ino) 3174837Smckusic continue; 3184837Smckusic if (xp->x_flags & XLINKED) 3194837Smckusic continue; 3204837Smckusic xp->x_timep[0] = spcl.c_dinode.di_atime; 3214837Smckusic xp->x_timep[1] = spcl.c_dinode.di_mtime; 3224837Smckusic mode = spcl.c_dinode.di_mode; 3234837Smckusic if (mflag) 324*4843Smckusic strcpy(name, xp->x_name); 3254837Smckusic else 3264837Smckusic sprintf(name, "%u", xp->x_ino); 3274837Smckusic switch (mode & IFMT) { 3284837Smckusic default: 329*4843Smckusic fprintf(stderr, "%s: unknown file type\n", name); 3304837Smckusic xp->x_flags |= XTRACTD; 3314837Smckusic xtrcnt--; 3324837Smckusic goto skipfile; 3334837Smckusic case IFCHR: 3344837Smckusic case IFBLK: 335*4843Smckusic fprintf(stdout, "extract special file %s\n", name); 3364837Smckusic if (xmknod(name, mode, spcl.c_dinode.di_rdev)) { 3374837Smckusic fprintf(stderr, "%s: cannot create special file\n", name); 3384837Smckusic xp->x_flags |= XTRACTD; 3394837Smckusic xtrcnt--; 3404837Smckusic goto skipfile; 3414776Smckusic } 3424837Smckusic getfile(null, null, spcl.c_dinode.di_size); 3434837Smckusic break; 3444837Smckusic case IFDIR: 3454837Smckusic if (mflag) { 346*4843Smckusic fprintf(stdout, "extract directory %s\n", name); 3474837Smckusic strncat(name, "/.", BUFSIZ); 348*4843Smckusic checkdir(name); 349*4843Smckusic xchown(xp->x_name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid); 3504837Smckusic getfile(null, null, spcl.c_dinode.di_size); 3514837Smckusic break; 3524610Smckusick } 3534837Smckusic /* else fall through */ 3544837Smckusic case IFREG: 355*4843Smckusic fprintf(stdout, "extract file %s\n", name); 3564837Smckusic if ((ofile = xcreat(name, 0666)) < 0) { 3574837Smckusic fprintf(stderr, "%s: cannot create file\n", name); 3584837Smckusic xp->x_flags |= XTRACTD; 3594837Smckusic xtrcnt--; 3604837Smckusic goto skipfile; 3614837Smckusic } 3624837Smckusic xchown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid); 3634837Smckusic getfile(xtrfile, skip, spcl.c_dinode.di_size); 3644837Smckusic xclose(ofile); 3654837Smckusic break; 3664610Smckusick } 3674837Smckusic xchmod(name, mode); 3684837Smckusic xutime(name, xp->x_timep); 3694837Smckusic xp->x_flags |= XTRACTD; 3704837Smckusic xtrcnt--; 3714837Smckusic goto finished; 3724837Smckusic } 3734837Smckusic skipfile: 3744837Smckusic getfile(null, null, spcl.c_dinode.di_size); 3754700Smckusic finished: 3764837Smckusic ; 3774837Smckusic } 3784837Smckusic if (xtrcnt == 0 && !mflag) 3794837Smckusic return; 3804837Smckusic for (xpp = xtrlist; xpp < &xtrlist[MAXINO]; xpp++) { 3814837Smckusic for (xp = *xpp; xp; xp = xp->x_next) { 3824837Smckusic if (mflag && (xp->x_flags & XISDIR)) 3834837Smckusic xutime(xp->x_name, xp->x_timep); 3844837Smckusic if (xp->x_flags & XTRACTD) 3854837Smckusic continue; 3864837Smckusic if ((xp->x_flags & XLINKED) == 0) { 3874837Smckusic fprintf(stderr, "cannot find file %s\n", 3884837Smckusic xp->x_name); 3894837Smckusic continue; 3904837Smckusic } 391*4843Smckusic if (!mflag) 392*4843Smckusic continue; 393*4843Smckusic fprintf(stdout, "link %s to %s\n", 394*4843Smckusic xp->x_linkedto->x_name, xp->x_name); 395*4843Smckusic if (xlink(xp->x_linkedto->x_name, xp->x_name) < 0) 396*4843Smckusic fprintf(stderr, "link %s to %s failed\n", 3974837Smckusic xp->x_linkedto->x_name, xp->x_name); 3984610Smckusick } 3994837Smckusic } 4004837Smckusic } 4014610Smckusick #endif 4024837Smckusic 4034837Smckusic restorfiles(command, argv) 4044837Smckusic char command; 4054837Smckusic char **argv; 4064837Smckusic { 4074837Smckusic int rstrfile(), rstrskip(); 4084837Smckusic register struct dinode *dp; 4094837Smckusic register struct inode *ip; 4104837Smckusic struct fs *fs; 4114837Smckusic int mode; 4124837Smckusic char mount[BUFSIZ + 1]; 4134837Smckusic char *ptr[2]; 4144837Smckusic 4154610Smckusick #ifndef STANDALONE 4164837Smckusic mount[0] = '\0'; 4174837Smckusic strcpy(mount, "MOUNT="); 4184837Smckusic strncat(mount, *argv, BUFSIZ); 4194837Smckusic ptr[0] = mount; 4204837Smckusic ptr[1] = 0; 4214837Smckusic xmount(ptr); 4224837Smckusic iput(u.u_cdir); /* release root inode */ 4234837Smckusic iput(u.u_rdir); /* release root inode */ 4244837Smckusic mounted++; 4254610Smckusick #else 4264837Smckusic do { 4274837Smckusic fprintf(stderr, "Disk? "); 4284837Smckusic gets(mount); 4294837Smckusic fi = open(mount, 2); 4304837Smckusic } while (fi == -1); 4314610Smckusick #endif 4324610Smckusick #ifndef STANDALONE 4334837Smckusic if (command == 'R') { 4344837Smckusic fprintf(stderr, "Enter starting volume number: "); 4354837Smckusic if (gets(tbf) == EOF) { 4364837Smckusic volno = 1; 4374837Smckusic fprintf(stderr, "\n"); 4384610Smckusick } 4394610Smckusick else 4404837Smckusic volno = atoi(tbf); 4414837Smckusic } 4424837Smckusic else 4434610Smckusick #endif 4444837Smckusic volno = 1; 4454837Smckusic fprintf(stderr, "Last chance before scribbling on %s. ", 4464610Smckusick #ifdef STANDALONE 4474837Smckusic "disk"); 4484610Smckusick #else 4494837Smckusic *argv); 4504610Smckusick #endif 4514837Smckusic while (getchar() != '\n'); 4524837Smckusic fs = getfs(dev); 4534837Smckusic maxi = fs->fs_ipg * fs->fs_ncg; 4544837Smckusic if (readhdr(&spcl) == 0) { 4554837Smckusic fprintf(stderr, "Missing volume record\n"); 4564837Smckusic done(1); 4574837Smckusic } 4584837Smckusic if (checkvol(&spcl, volno) == 0) { 4594837Smckusic fprintf(stderr, "Tape is not volume %d\n", volno); 4604837Smckusic done(1); 4614837Smckusic } 4624837Smckusic gethead(&spcl); 4634837Smckusic for (;;) { 4644837Smckusic ragain: 4654837Smckusic if (ishead(&spcl) == 0) { 4664837Smckusic fprintf(stderr, "Missing header block\n"); 4674837Smckusic while (gethead(&spcl) == 0) 4684837Smckusic ; 4694837Smckusic eflag++; 4704610Smckusick } 4714837Smckusic if (checktype(&spcl, TS_END) == 1) { 4724837Smckusic fprintf(stderr, "End of tape\n"); 4734837Smckusic close(mt); 4744837Smckusic return; 4754610Smckusick } 4764837Smckusic if (checktype(&spcl, TS_CLRI) == 1) { 4774837Smckusic readbits(clrimap); 4784837Smckusic for (ino = 1; ino <= maxi; ino++) 4794837Smckusic if (BIT(ino, clrimap) == 0) { 4804837Smckusic if (!iexist(dev, ino)) 4814837Smckusic continue; 4824837Smckusic ip = iget(dev, ino); 4834837Smckusic if (ip == NULL) { 4844837Smckusic fprintf(stderr, "can't find inode %u\n", ino); 4854837Smckusic done(1); 4864610Smckusick } 4874837Smckusic ip->i_nlink = 0; 4884837Smckusic ip->i_flag |= ICHG; 4894837Smckusic iput(ip); 4904700Smckusic } 4914837Smckusic goto ragain; 4924837Smckusic } 4934837Smckusic if (checktype(&spcl, TS_BITS) == 1) { 4944837Smckusic readbits(dumpmap); 4954837Smckusic goto ragain; 4964837Smckusic } 4974837Smckusic if (checktype(&spcl, TS_INODE) == 0) { 4984837Smckusic fprintf(stderr, "Unknown header type\n"); 4994837Smckusic eflag++; 5004837Smckusic gethead(&spcl); 5014837Smckusic goto ragain; 5024837Smckusic } 5034837Smckusic ino = spcl.c_inumber; 5044837Smckusic if (eflag) 5054837Smckusic fprintf(stderr, "Resynced at inode %u\n", ino); 5064837Smckusic eflag = 0; 5074837Smckusic if (ino > maxi) { 5084837Smckusic fprintf(stderr, "%u: ilist too small\n", ino); 5094837Smckusic gethead(&spcl); 5104837Smckusic goto ragain; 5114837Smckusic } 5124837Smckusic if (iexist(dev, ino)) { 5134837Smckusic ip = iget(dev, ino); 5144837Smckusic if (ip == NULL) { 5154837Smckusic fprintf(stderr, "can't find inode %u\n", 5164837Smckusic ino); 5174700Smckusic done(1); 5184700Smckusic } 5194837Smckusic ip->i_nlink = 0; 5204700Smckusic ip->i_flag |= ICHG; 5214700Smckusic iput(ip); 5224610Smckusick } 5234837Smckusic dp = &spcl.c_dinode; 5244837Smckusic ip = ialloc(dev, ino, dp->di_mode); 5254837Smckusic if (ip == NULL || ip->i_number != ino) { 5264837Smckusic fprintf(stderr, "can't create inode %u\n", ino); 5274837Smckusic done(1); 5284837Smckusic } 5294837Smckusic ip->i_mode = mode = dp->di_mode; 5304837Smckusic ip->i_nlink = dp->di_nlink; 5314837Smckusic ip->i_uid = dp->di_uid; 5324837Smckusic ip->i_gid = dp->di_gid; 5334837Smckusic ip->i_atime = dp->di_atime; 5344837Smckusic ip->i_mtime = dp->di_mtime; 5354837Smckusic ip->i_ctime = dp->di_ctime; 5364837Smckusic if ((ip->i_mode & IFMT) == IFCHR || 5374837Smckusic (ip->i_mode & IFMT) == IFBLK) 5384837Smckusic ip->i_rdev = dp->di_rdev; 5394837Smckusic ip->i_size = 0; 5404837Smckusic cur_ip = ip; 5414837Smckusic u.u_offset = 0; 5424837Smckusic u.u_segflg = 1; 5434837Smckusic getfile(rstrfile, rstrskip, dp->di_size); 5444837Smckusic ip->i_mode = mode; 5454837Smckusic ip->i_flag &= ~(IUPD|IACC); 5464837Smckusic ip->i_flag |= ICHG; 5474837Smckusic iput(ip); 5484610Smckusick } 5494610Smckusick } 5504610Smckusick 5514610Smckusick /* 5524610Smckusick * Read the tape, bulding up a directory structure for extraction 5534610Smckusick * by name 5544610Smckusick */ 5554610Smckusick #ifndef STANDALONE 5564610Smckusick pass1() 5574610Smckusick { 5584776Smckusic register int i; 5594837Smckusic register struct dinode *ip; 5604837Smckusic struct direct nulldir; 5614610Smckusick int putdir(), null(); 5624610Smckusick 5634837Smckusic nulldir.d_ino = 0; 5644837Smckusic strncpy(nulldir.d_name, "/", DIRSIZ); 5654610Smckusick while (gethead(&spcl) == 0) { 5664700Smckusic fprintf(stderr, "Can't find directory header!\n"); 5674610Smckusick } 5684610Smckusick for (;;) { 5694610Smckusick if (checktype(&spcl, TS_BITS) == 1) { 5704610Smckusick readbits(dumpmap); 5714610Smckusick continue; 5724610Smckusick } 5734610Smckusick if (checktype(&spcl, TS_CLRI) == 1) { 5744610Smckusick readbits(clrimap); 5754610Smckusick continue; 5764610Smckusick } 5774610Smckusick if (checktype(&spcl, TS_INODE) == 0) { 5784610Smckusick finish: 5794610Smckusick /* 5804610Smckusick close(mt); 5814610Smckusick */ 5824837Smckusic freopen(dirfile, "r", df); 5834610Smckusick return; 5844610Smckusick } 5854610Smckusick ip = &spcl.c_dinode; 5864610Smckusick i = ip->di_mode & IFMT; 5874610Smckusick if (i != IFDIR) { 5884610Smckusick goto finish; 5894610Smckusick } 590*4843Smckusic allocinotab(spcl.c_inumber, seekpt); 5914700Smckusic getfile(putdir, null, spcl.c_dinode.di_size); 5924837Smckusic putent(&nulldir); 5934610Smckusick } 5944610Smckusick } 5954610Smckusick #endif 5964610Smckusick 5974610Smckusick /* 598*4843Smckusic * Put the directory entries in the directory file 599*4843Smckusic */ 600*4843Smckusic #ifndef STANDALONE 601*4843Smckusic putdir(buf, size) 602*4843Smckusic char *buf; 603*4843Smckusic int size; 604*4843Smckusic { 605*4843Smckusic register struct direct *dp; 606*4843Smckusic register int i; 607*4843Smckusic 608*4843Smckusic for (dp = (struct direct *)buf, i = 0; i < size; dp++, i += sizeof(*dp)) 609*4843Smckusic if (dp->d_ino != 0) 610*4843Smckusic putent(dp); 611*4843Smckusic } 612*4843Smckusic 613*4843Smckusic putent(dp) 614*4843Smckusic struct direct *dp; 615*4843Smckusic { 616*4843Smckusic fwrite(dp, 1, sizeof(struct direct), df); 617*4843Smckusic seekpt = ftell(df); 618*4843Smckusic } 619*4843Smckusic 620*4843Smckusic /* 621*4843Smckusic * Recursively find names and inumbers of all files in subtree 622*4843Smckusic * pname and put them in xtrlist[] 623*4843Smckusic */ 624*4843Smckusic getleaves(ino, pname) 625*4843Smckusic ino_t ino; 626*4843Smckusic char *pname; 627*4843Smckusic { 628*4843Smckusic register struct inotab *itp; 629*4843Smckusic int namelen; 630*4843Smckusic daddr_t bpt; 631*4843Smckusic struct direct dir; 632*4843Smckusic char locname[BUFSIZ + 1]; 633*4843Smckusic 634*4843Smckusic if (BIT(ino, dumpmap) == 0) { 635*4843Smckusic fprintf(stdout, "%s: not on the tape\n", pname); 636*4843Smckusic return; 637*4843Smckusic } 638*4843Smckusic for (itp = inotab[INOHASH(ino)]; itp; itp = itp->t_next) { 639*4843Smckusic if (itp->t_ino != ino) 640*4843Smckusic continue; 641*4843Smckusic /* 642*4843Smckusic * pname is a directory name 643*4843Smckusic */ 644*4843Smckusic allocxtr(ino, pname, XISDIR); 645*4843Smckusic /* 646*4843Smckusic * begin search through the directory 647*4843Smckusic * skipping over "." and ".." 648*4843Smckusic */ 649*4843Smckusic strncpy(locname, pname, BUFSIZ); 650*4843Smckusic strncat(locname, "/", BUFSIZ); 651*4843Smckusic namelen = strlen(locname); 652*4843Smckusic fseek(df, itp->t_seekpt, 0); 653*4843Smckusic fread(&dir, 1, sizeof(struct direct), df); 654*4843Smckusic fread(&dir, 1, sizeof(struct direct), df); 655*4843Smckusic fread(&dir, 1, sizeof(struct direct), df); 656*4843Smckusic bpt = ftell(df); 657*4843Smckusic /* 658*4843Smckusic * "/" signals end of directory 659*4843Smckusic */ 660*4843Smckusic while (strncmp(dir.d_name, "/", DIRSIZ)) { 661*4843Smckusic locname[namelen] = '\0'; 662*4843Smckusic strncat(locname, dir.d_name, DIRSIZ); 663*4843Smckusic if (strlen(locname) >= BUFSIZ) { 664*4843Smckusic fprintf(stderr, "%s: name exceedes %d char\n", 665*4843Smckusic locname, BUFSIZ); 666*4843Smckusic continue; 667*4843Smckusic } 668*4843Smckusic getleaves(dir.d_ino, locname); 669*4843Smckusic fseek(df, bpt, 0); 670*4843Smckusic fread(&dir, 1, sizeof(struct direct), df); 671*4843Smckusic bpt = ftell(df); 672*4843Smckusic } 673*4843Smckusic return; 674*4843Smckusic } 675*4843Smckusic /* 676*4843Smckusic * locname is name of a simple file 677*4843Smckusic */ 678*4843Smckusic allocxtr(ino, pname, XINUSE); 679*4843Smckusic } 680*4843Smckusic 681*4843Smckusic /* 682*4843Smckusic * Search the directory tree rooted at inode ROOTINO 683*4843Smckusic * for the path pointed at by n 684*4843Smckusic */ 685*4843Smckusic psearch(n) 686*4843Smckusic char *n; 687*4843Smckusic { 688*4843Smckusic register char *cp, *cp1; 689*4843Smckusic char c; 690*4843Smckusic 691*4843Smckusic ino = ROOTINO; 692*4843Smckusic if (*(cp = n) == '/') 693*4843Smckusic cp++; 694*4843Smckusic next: 695*4843Smckusic cp1 = cp + 1; 696*4843Smckusic while (*cp1 != '/' && *cp1) 697*4843Smckusic cp1++; 698*4843Smckusic c = *cp1; 699*4843Smckusic *cp1 = 0; 700*4843Smckusic ino = search(ino, cp); 701*4843Smckusic if (ino == 0) { 702*4843Smckusic *cp1 = c; 703*4843Smckusic return(0); 704*4843Smckusic } 705*4843Smckusic *cp1 = c; 706*4843Smckusic if (c == '/') { 707*4843Smckusic cp = cp1+1; 708*4843Smckusic goto next; 709*4843Smckusic } 710*4843Smckusic return(ino); 711*4843Smckusic } 712*4843Smckusic 713*4843Smckusic /* 714*4843Smckusic * search the directory inode ino 715*4843Smckusic * looking for entry cp 716*4843Smckusic */ 717*4843Smckusic ino_t 718*4843Smckusic search(inum, cp) 719*4843Smckusic ino_t inum; 720*4843Smckusic char *cp; 721*4843Smckusic { 722*4843Smckusic struct direct dir; 723*4843Smckusic register struct inotab *itp; 724*4843Smckusic 725*4843Smckusic for (itp = inotab[INOHASH(inum)]; itp; itp = itp->t_next) 726*4843Smckusic if (itp->t_ino == inum) 727*4843Smckusic goto found; 728*4843Smckusic return(0); 729*4843Smckusic found: 730*4843Smckusic fseek(df, itp->t_seekpt, 0); 731*4843Smckusic do { 732*4843Smckusic fread(&dir, 1, sizeof(struct direct), df); 733*4843Smckusic if (!strncmp(dir.d_name, "/", DIRSIZ)) 734*4843Smckusic return(0); 735*4843Smckusic } while (strncmp(dir.d_name, cp, DIRSIZ)); 736*4843Smckusic return(dir.d_ino); 737*4843Smckusic } 738*4843Smckusic #endif 739*4843Smckusic 740*4843Smckusic /* 7414610Smckusick * Do the file extraction, calling the supplied functions 7424610Smckusick * with the blocks 7434610Smckusick */ 7444700Smckusic getfile(f1, f2, size) 7454700Smckusic int (*f2)(), (*f1)(); 7464700Smckusic long size; 7474610Smckusick { 7484776Smckusic register int i; 7494776Smckusic char buf[BLKING * FRAG][TP_BSIZE]; 7504837Smckusic union u_spcl addrblk; 7514837Smckusic # define addrblock addrblk.s_spcl 7524610Smckusick 7534837Smckusic addrblock = spcl; 7544610Smckusick for (;;) { 7554837Smckusic for (i = 0; i < addrblock.c_count; i++) { 7564837Smckusic if (addrblock.c_addr[i]) { 7574776Smckusic readtape(&buf[curblk++][0]); 7584776Smckusic if (curblk == BLKING * FRAG) { 7594776Smckusic (*f1)(buf, size > TP_BSIZE ? 7604776Smckusic (long) (BLKING * FRAG * TP_BSIZE) : 7614776Smckusic (curblk - 1) * TP_BSIZE + size); 7624776Smckusic curblk = 0; 7634776Smckusic } 7644610Smckusick } 7654610Smckusick else { 7664776Smckusic if (curblk > 0) { 7674776Smckusic (*f1)(buf, size > TP_BSIZE ? 7684776Smckusic (long) (curblk * TP_BSIZE) : 7694776Smckusic (curblk - 1) * TP_BSIZE + size); 7704776Smckusic curblk = 0; 7714776Smckusic } 7724776Smckusic (*f2)(clearedbuf, size > TP_BSIZE ? (long) TP_BSIZE : size); 7734610Smckusick } 7744776Smckusic if ((size -= TP_BSIZE) <= 0) { 7754610Smckusick eloop: 7764610Smckusick while (gethead(&spcl) == 0) 7774610Smckusick ; 7784610Smckusick if (checktype(&spcl, TS_ADDR) == 1) 7794610Smckusick goto eloop; 7804776Smckusic goto out; 7814610Smckusick } 7824610Smckusick } 7834837Smckusic if (gethead(&addrblock) == 0) { 7844776Smckusic fprintf(stderr, "Missing address (header) block, ino%u\n", ino); 7854700Smckusic goto eloop; 7864700Smckusic } 7874837Smckusic if (checktype(&addrblock, TS_ADDR) == 0) { 7884837Smckusic spcl = addrblock; 7894776Smckusic goto out; 7904700Smckusic } 7914610Smckusick } 7924776Smckusic out: 7934776Smckusic if (curblk > 0) { 7944776Smckusic (*f1)(buf, (curblk * TP_BSIZE) + size); 7954776Smckusic curblk = 0; 7964776Smckusic } 7974610Smckusick } 7984610Smckusick 7994610Smckusick /* 800*4843Smckusic * The next routines are called during file extraction to 801*4843Smckusic * put the data into the right form and place. 802*4843Smckusic */ 803*4843Smckusic #ifndef STANDALONE 804*4843Smckusic xtrfile(buf, size) 805*4843Smckusic char *buf; 806*4843Smckusic long size; 807*4843Smckusic { 808*4843Smckusic if (xwrite(ofile, buf, (int) size) == -1) { 809*4843Smckusic perror("extract write:"); 810*4843Smckusic done(1); 811*4843Smckusic } 812*4843Smckusic } 813*4843Smckusic 814*4843Smckusic skip(buf, size) 815*4843Smckusic char *buf; 816*4843Smckusic long size; 817*4843Smckusic { 818*4843Smckusic if (xseek(ofile, size, 1) == -1) { 819*4843Smckusic perror("extract seek:"); 820*4843Smckusic done(1); 821*4843Smckusic } 822*4843Smckusic } 823*4843Smckusic #endif 824*4843Smckusic 825*4843Smckusic 826*4843Smckusic rstrfile(buf, size) 827*4843Smckusic char *buf; 828*4843Smckusic long size; 829*4843Smckusic { 830*4843Smckusic u.u_base = buf; 831*4843Smckusic u.u_count = size; 832*4843Smckusic writei(cur_ip); 833*4843Smckusic if (u.u_error) { 834*4843Smckusic perror("restor write:"); 835*4843Smckusic done(1); 836*4843Smckusic } 837*4843Smckusic } 838*4843Smckusic 839*4843Smckusic rstrskip(buf, size) 840*4843Smckusic char *buf; 841*4843Smckusic long size; 842*4843Smckusic { 843*4843Smckusic u.u_offset += size; 844*4843Smckusic } 845*4843Smckusic 846*4843Smckusic null() {;} 847*4843Smckusic 848*4843Smckusic /* 8494776Smckusic * Do the tape i/o, dealing with volume changes 8504610Smckusick * etc.. 8514610Smckusick */ 8524610Smckusick readtape(b) 8534700Smckusic char *b; 8544610Smckusick { 8554776Smckusic register int i; 8564837Smckusic struct s_spcl tmpbuf; 8574610Smckusick 8584610Smckusick if (bct >= NTREC) { 8594610Smckusick for (i = 0; i < NTREC; i++) 8604776Smckusic ((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0; 8614610Smckusick bct = 0; 8624776Smckusic if ((i = read(mt, tbf, NTREC*TP_BSIZE)) < 0) { 8634700Smckusic perror("Tape read error"); 8644610Smckusick eflag++; 8654700Smckusic done(1); 8664610Smckusick } 8674610Smckusick if (i == 0) { 8684610Smckusick bct = NTREC + 1; 8694610Smckusick volno++; 8704610Smckusick loop: 8714610Smckusick flsht(); 8724610Smckusick close(mt); 8734700Smckusic fprintf(stderr, "Mount volume %d\n", volno); 8744610Smckusick while (getchar() != '\n') 8754610Smckusick ; 8764610Smckusick if ((mt = open(magtape, 0)) == -1) { 8774700Smckusic fprintf(stderr, "Cannot open tape!\n"); 8784610Smckusick goto loop; 8794610Smckusick } 8804610Smckusick if (readhdr(&tmpbuf) == 0) { 8814700Smckusic fprintf(stderr, "Not a dump tape.Try again\n"); 8824610Smckusick goto loop; 8834610Smckusick } 8844610Smckusick if (checkvol(&tmpbuf, volno) == 0) { 8854700Smckusic fprintf(stderr, "Wrong tape. Try again\n"); 8864610Smckusick goto loop; 8874610Smckusick } 8884610Smckusick readtape(b); 8894610Smckusick return; 8904610Smckusick } 8914610Smckusick } 8924776Smckusic copy(&tbf[(bct++*TP_BSIZE)], b, TP_BSIZE); 8934610Smckusick } 8944610Smckusick 8954610Smckusick flsht() 8964610Smckusick { 8974610Smckusick bct = NTREC+1; 8984610Smckusick } 8994610Smckusick 9004610Smckusick copy(f, t, s) 9014700Smckusic register char *f, *t; 9024610Smckusick { 9034776Smckusic register int i; 9044610Smckusick 9054610Smckusick i = s; 9064610Smckusick do 9074610Smckusick *t++ = *f++; 9084610Smckusick while (--i); 9094610Smckusick } 9104610Smckusick 911*4843Smckusic checkvol(b, t) 912*4843Smckusic struct s_spcl *b; 913*4843Smckusic int t; 9144610Smckusick { 915*4843Smckusic if (b->c_volume == t) 916*4843Smckusic return(1); 9174610Smckusick return(0); 9184610Smckusick } 9194610Smckusick 920*4843Smckusic readhdr(b) 921*4843Smckusic struct s_spcl *b; 9224610Smckusick { 923*4843Smckusic if (gethead(b) == 0) 9244610Smckusick return(0); 925*4843Smckusic if (checktype(b, TS_TAPE) == 0) 926*4843Smckusic return(0); 927*4843Smckusic return(1); 9284610Smckusick } 9294610Smckusick 9304610Smckusick /* 9314610Smckusick * read the tape into buf, then return whether or 9324610Smckusick * or not it is a header block. 9334610Smckusick */ 9344610Smckusick gethead(buf) 9354837Smckusic struct s_spcl *buf; 9364610Smckusick { 9374610Smckusick readtape((char *)buf); 9384837Smckusic if (buf->c_magic != MAGIC || checksum((int *)buf) == 0) 9394610Smckusick return(0); 9404610Smckusick return(1); 9414610Smckusick } 9424610Smckusick 9434610Smckusick /* 9444610Smckusick * return whether or not the buffer contains a header block 9454610Smckusick */ 9464610Smckusick ishead(buf) 9474837Smckusic struct s_spcl *buf; 9484610Smckusick { 9494837Smckusic if (buf->c_magic != MAGIC || checksum((int *)buf) == 0) 9504610Smckusick return(0); 9514610Smckusick return(1); 9524610Smckusick } 9534610Smckusick 9544610Smckusick checktype(b, t) 9554837Smckusic struct s_spcl *b; 9564700Smckusic int t; 9574610Smckusick { 9584837Smckusic return(b->c_type == t); 9594610Smckusick } 9604610Smckusick 9614610Smckusick 9624610Smckusick checksum(b) 9634700Smckusic int *b; 9644610Smckusick { 9654776Smckusic register int i, j; 9664610Smckusick 9674776Smckusic j = sizeof(union u_spcl) / sizeof(int); 9684610Smckusick i = 0; 9694610Smckusick do 9704610Smckusick i += *b++; 9714610Smckusick while (--j); 9724610Smckusick if (i != CHECKSUM) { 9734776Smckusic fprintf(stderr, "Checksum error %o, ino %u\n", i, ino); 9744610Smckusick return(0); 9754610Smckusick } 9764610Smckusick return(1); 9774610Smckusick } 9784610Smckusick 9794610Smckusick /* 9804700Smckusic * tell whether an inode is allocated 9814700Smckusic * this is drawn from ialloccg in sys/alloc.c 9824700Smckusic */ 9834700Smckusic iexist(dev, ino) 9844700Smckusic dev_t dev; 9854700Smckusic ino_t ino; 9864610Smckusick { 9874700Smckusic register struct fs *fs; 9884700Smckusic register struct cg *cgp; 9894700Smckusic register struct buf *bp; 9904700Smckusic int cg; 9914700Smckusic 9924700Smckusic fs = getfs(dev); 9934700Smckusic if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg) 9944700Smckusic return (0); 9954700Smckusic cg = itog(ino, fs); 9964700Smckusic bp = bread(dev, cgtod(cg, fs), BSIZE); 9974700Smckusic if (bp->b_flags & B_ERROR) 9984700Smckusic return(0); 9994700Smckusic cgp = bp->b_un.b_cg; 10004700Smckusic ino %= fs->fs_ipg; 10014700Smckusic if (isclr(cgp->cg_iused, ino)) { 10024700Smckusic brelse(bp); 10034700Smckusic return(0); 10044700Smckusic } 10054700Smckusic brelse(bp); 10064700Smckusic return (1); 10074610Smckusick } 10084610Smckusick 10094610Smckusick /* 10104610Smckusick * read a bit mask from the tape into m. 10114610Smckusick */ 10124610Smckusick readbits(m) 10134700Smckusic short *m; 10144610Smckusick { 10154776Smckusic register int i; 10164610Smckusick 10174610Smckusick i = spcl.c_count; 10184610Smckusick 10194610Smckusick while (i--) { 10204610Smckusick readtape((char *) m); 10214776Smckusic m += (TP_BSIZE/(MLEN/BITS)); 10224610Smckusick } 10234610Smckusick while (gethead(&spcl) == 0) 10244610Smckusick ; 10254610Smckusick } 10264610Smckusick 10274700Smckusic done(exitcode) 10284700Smckusic int exitcode; 10294610Smckusick { 10304610Smckusick #ifndef STANDALONE 10314610Smckusick unlink(dirfile); 10324610Smckusick #endif 10334700Smckusic if (mounted) 10344700Smckusic xumount(); 10354700Smckusic exit(exitcode); 10364610Smckusick } 10374610Smckusick 1038*4843Smckusic allocinotab(ino, seekpt) 10394837Smckusic ino_t ino; 1040*4843Smckusic daddr_t seekpt; 10414610Smckusick { 10424837Smckusic register struct inotab *itp; 10434776Smckusic 10444837Smckusic itp = (struct inotab *)calloc(1, sizeof(struct inotab)); 10454837Smckusic itp->t_next = inotab[INOHASH(ino)]; 10464837Smckusic inotab[INOHASH(ino)] = itp; 10474837Smckusic itp->t_ino = ino; 1048*4843Smckusic itp->t_seekpt = seekpt; 10494610Smckusick } 10504610Smckusick 1051*4843Smckusic allocxtr(ino, name, flags) 10524837Smckusic ino_t ino; 1053*4843Smckusic char *name; 1054*4843Smckusic char flags; 10554610Smckusick { 1056*4843Smckusic register struct xtrlist *xp, *pxp; 10574776Smckusic 1058*4843Smckusic xp = (struct xtrlist *)calloc(1, sizeof(struct xtrlist) + strlen(name)); 10594837Smckusic xp->x_next = xtrlist[INOHASH(ino)]; 10604837Smckusic xtrlist[INOHASH(ino)] = xp; 10614837Smckusic xp->x_ino = ino; 1062*4843Smckusic strcpy(xp->x_name, name); 10634837Smckusic xtrcnt++; 1064*4843Smckusic xp->x_flags = flags; 1065*4843Smckusic for (pxp = xp->x_next; pxp; pxp = pxp->x_next) 1066*4843Smckusic if (pxp->x_ino == ino && (pxp->x_flags & XLINKED) == 0) { 1067*4843Smckusic xp->x_flags |= XLINKED; 1068*4843Smckusic xp->x_linkedto = pxp; 1069*4843Smckusic xtrcnt--; 1070*4843Smckusic break; 1071*4843Smckusic } 1072*4843Smckusic if (xp->x_flags & XLINKED) 1073*4843Smckusic fprintf(stdout, "%s: linked to %s\n", xp->x_name, pxp->x_name); 1074*4843Smckusic else if (xp->x_flags & XISDIR) 1075*4843Smckusic fprintf(stdout, "%s: directory inode %u\n", xp->x_name, ino); 1076*4843Smckusic else 1077*4843Smckusic fprintf(stdout, "%s: inode %u\n", xp->x_name, ino); 10784610Smckusick } 10794610Smckusick 10804610Smckusick /* 10814610Smckusick * Check for access into each directory in the pathname of an extracted 10824610Smckusick * file and create such a directory if needed in preparation for moving 10834610Smckusick * the file to its proper home. 10844610Smckusick */ 10854610Smckusick checkdir(name) 10864700Smckusic register char *name; 10874610Smckusick { 10884610Smckusick register char *cp; 10894610Smckusick int i; 10904776Smckusic 10914610Smckusick for (cp = name; *cp; cp++) { 10924610Smckusick if (*cp == '/') { 10934610Smckusick *cp = '\0'; 10944700Smckusic if (xaccess(name, 01) < 0) { 10954610Smckusick register int pid, rp; 10964610Smckusick 10974700Smckusic xumount(); 10984610Smckusick if ((pid = fork()) == 0) { 10994700Smckusic execl("/bin/xmkdir", "xmkdir", name, 0); 11004700Smckusic execl("/usr/bin/xmkdir", "xmkdir", name, 0); 11014700Smckusic execl("./xmkdir", "xmkdir", name, 0); 11024700Smckusic fprintf(stderr, "xrestor: cannot find xmkdir!\n"); 11034610Smckusick done(0); 11044610Smckusick } 11054610Smckusick while ((rp = wait(&i)) >= 0 && rp != pid) 11064610Smckusick ; 11074700Smckusic xmount(envp); 11084610Smckusick } 11094610Smckusick *cp = '/'; 11104610Smckusick } 11114610Smckusick } 11124610Smckusick } 1113