Annotation of 43BSDReno/sbin/fsck/setup.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1980, 1986 The Regents of the University of California.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * Redistribution and use in source and binary forms are permitted provided
        !             6:  * that: (1) source distributions retain this entire copyright notice and
        !             7:  * comment, and (2) distributions including binaries display the following
        !             8:  * acknowledgement:  ``This product includes software developed by the
        !             9:  * University of California, Berkeley and its contributors'' in the
        !            10:  * documentation or other materials provided with the distribution and in
        !            11:  * all advertising materials mentioning features or use of this software.
        !            12:  * Neither the name of the University nor the names of its contributors may
        !            13:  * be used to endorse or promote products derived from this software without
        !            14:  * specific prior written permission.
        !            15:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
        !            16:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
        !            17:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
        !            18:  */
        !            19: 
        !            20: #ifndef lint
        !            21: static char sccsid[] = "@(#)setup.c    5.32 (Berkeley) 7/22/90";
        !            22: #endif /* not lint */
        !            23: 
        !            24: #define DKTYPENAMES
        !            25: #include <sys/param.h>
        !            26: #include <ufs/dinode.h>
        !            27: #include <ufs/fs.h>
        !            28: #include <sys/stat.h>
        !            29: #include <sys/ioctl.h>
        !            30: #include <sys/disklabel.h>
        !            31: #include <sys/file.h>
        !            32: #include <errno.h>
        !            33: #include <stdlib.h>
        !            34: #include <string.h>
        !            35: #include <ctype.h>
        !            36: #include "fsck.h"
        !            37: 
        !            38: struct bufarea asblk;
        !            39: #define altsblock (*asblk.b_un.b_fs)
        !            40: #define POWEROF2(num)  (((num) & ((num) - 1)) == 0)
        !            41: 
        !            42: /*
        !            43:  * The size of a cylinder group is calculated by CGSIZE. The maximum size
        !            44:  * is limited by the fact that cylinder groups are at most one block.
        !            45:  * Its size is derived from the size of the maps maintained in the 
        !            46:  * cylinder group and the (struct cg) size.
        !            47:  */
        !            48: #define CGSIZE(fs) \
        !            49:     /* base cg */      (sizeof(struct cg) + \
        !            50:     /* blktot size */  (fs)->fs_cpg * sizeof(long) + \
        !            51:     /* blks size */    (fs)->fs_cpg * (fs)->fs_nrpos * sizeof(short) + \
        !            52:     /* inode map */    howmany((fs)->fs_ipg, NBBY) + \
        !            53:     /* block map */    howmany((fs)->fs_cpg * (fs)->fs_spc / NSPF(fs), NBBY))
        !            54: 
        !            55: char   *index();
        !            56: struct disklabel *getdisklabel();
        !            57: 
        !            58: setup(dev)
        !            59:        char *dev;
        !            60: {
        !            61:        long cg, size, asked, i, j;
        !            62:        long bmapsize;
        !            63:        struct disklabel *lp;
        !            64:        struct stat statb;
        !            65:        struct fs proto;
        !            66: 
        !            67:        havesb = 0;
        !            68:        if (stat(dev, &statb) < 0) {
        !            69:                printf("Can't stat %s: %s\n", dev, strerror(errno));
        !            70:                return (0);
        !            71:        }
        !            72:        if ((statb.st_mode & S_IFMT) != S_IFCHR) {
        !            73:                pfatal("%s is not a character device", dev);
        !            74:                if (reply("CONTINUE") == 0)
        !            75:                        return (0);
        !            76:        }
        !            77:        if ((fsreadfd = open(dev, O_RDONLY)) < 0) {
        !            78:                printf("Can't open %s: %s\n", dev, strerror(errno));
        !            79:                return (0);
        !            80:        }
        !            81:        if (preen == 0)
        !            82:                printf("** %s", dev);
        !            83:        if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) {
        !            84:                fswritefd = -1;
        !            85:                if (preen)
        !            86:                        pfatal("NO WRITE ACCESS");
        !            87:                printf(" (NO WRITE)");
        !            88:        }
        !            89:        if (preen == 0)
        !            90:                printf("\n");
        !            91:        fsmodified = 0;
        !            92:        lfdir = 0;
        !            93:        initbarea(&sblk);
        !            94:        initbarea(&asblk);
        !            95:        sblk.b_un.b_buf = malloc(SBSIZE);
        !            96:        asblk.b_un.b_buf = malloc(SBSIZE);
        !            97:        if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL)
        !            98:                errexit("cannot allocate space for superblock\n");
        !            99:        if (lp = getdisklabel((char *)NULL, fsreadfd))
        !           100:                dev_bsize = secsize = lp->d_secsize;
        !           101:        else
        !           102:                dev_bsize = secsize = DEV_BSIZE;
        !           103:        /*
        !           104:         * Read in the superblock, looking for alternates if necessary
        !           105:         */
        !           106:        if (readsb(1) == 0) {
        !           107:                if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0)
        !           108:                        return(0);
        !           109:                if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
        !           110:                        return (0);
        !           111:                for (cg = 0; cg < proto.fs_ncg; cg++) {
        !           112:                        bflag = fsbtodb(&proto, cgsblock(&proto, cg));
        !           113:                        if (readsb(0) != 0)
        !           114:                                break;
        !           115:                }
        !           116:                if (cg >= proto.fs_ncg) {
        !           117:                        printf("%s %s\n%s %s\n%s %s\n",
        !           118:                                "SEARCH FOR ALTERNATE SUPER-BLOCK",
        !           119:                                "FAILED. YOU MUST USE THE",
        !           120:                                "-b OPTION TO FSCK TO SPECIFY THE",
        !           121:                                "LOCATION OF AN ALTERNATE",
        !           122:                                "SUPER-BLOCK TO SUPPLY NEEDED",
        !           123:                                "INFORMATION; SEE fsck(8).");
        !           124:                        return(0);
        !           125:                }
        !           126:                pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag);
        !           127:        }
        !           128:        maxfsblock = sblock.fs_size;
        !           129:        maxino = sblock.fs_ncg * sblock.fs_ipg;
        !           130:        /*
        !           131:         * Check and potentially fix certain fields in the super block.
        !           132:         */
        !           133:        if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) {
        !           134:                pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK");
        !           135:                if (reply("SET TO DEFAULT") == 1) {
        !           136:                        sblock.fs_optim = FS_OPTTIME;
        !           137:                        sbdirty();
        !           138:                }
        !           139:        }
        !           140:        if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) {
        !           141:                pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK",
        !           142:                        sblock.fs_minfree);
        !           143:                if (reply("SET TO DEFAULT") == 1) {
        !           144:                        sblock.fs_minfree = 10;
        !           145:                        sbdirty();
        !           146:                }
        !           147:        }
        !           148:        if (sblock.fs_interleave < 1 || 
        !           149:            sblock.fs_interleave > sblock.fs_nsect) {
        !           150:                pwarn("IMPOSSIBLE INTERLEAVE=%d IN SUPERBLOCK",
        !           151:                        sblock.fs_interleave);
        !           152:                sblock.fs_interleave = 1;
        !           153:                if (preen)
        !           154:                        printf(" (FIXED)\n");
        !           155:                if (preen || reply("SET TO DEFAULT") == 1) {
        !           156:                        sbdirty();
        !           157:                        dirty(&asblk);
        !           158:                }
        !           159:        }
        !           160:        if (sblock.fs_npsect < sblock.fs_nsect || 
        !           161:            sblock.fs_npsect > sblock.fs_nsect*2) {
        !           162:                pwarn("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK",
        !           163:                        sblock.fs_npsect);
        !           164:                sblock.fs_npsect = sblock.fs_nsect;
        !           165:                if (preen)
        !           166:                        printf(" (FIXED)\n");
        !           167:                if (preen || reply("SET TO DEFAULT") == 1) {
        !           168:                        sbdirty();
        !           169:                        dirty(&asblk);
        !           170:                }
        !           171:        }
        !           172:        if (cvtflag) {
        !           173:                if (sblock.fs_postblformat == FS_42POSTBLFMT) {
        !           174:                        /*
        !           175:                         * Requested to convert from old format to new format
        !           176:                         */
        !           177:                        if (preen)
        !           178:                                pwarn("CONVERTING TO NEW FILE SYSTEM FORMAT\n");
        !           179:                        else if (!reply("CONVERT TO NEW FILE SYSTEM FORMAT"))
        !           180:                                return(0);
        !           181:                        sblock.fs_postblformat = FS_DYNAMICPOSTBLFMT;
        !           182:                        sblock.fs_nrpos = 8;
        !           183:                        sblock.fs_postbloff =
        !           184:                            (char *)(&sblock.fs_opostbl[0][0]) -
        !           185:                            (char *)(&sblock.fs_link);
        !           186:                        sblock.fs_rotbloff = &sblock.fs_space[0] -
        !           187:                            (u_char *)(&sblock.fs_link);
        !           188:                        sblock.fs_cgsize =
        !           189:                                fragroundup(&sblock, CGSIZE(&sblock));
        !           190:                        /*
        !           191:                         * Planning now for future expansion.
        !           192:                         */
        !           193: #                      if (BYTE_ORDER == BIG_ENDIAN)
        !           194:                                sblock.fs_qbmask.val[0] = 0;
        !           195:                                sblock.fs_qbmask.val[1] = ~sblock.fs_bmask;
        !           196:                                sblock.fs_qfmask.val[0] = 0;
        !           197:                                sblock.fs_qfmask.val[1] = ~sblock.fs_fmask;
        !           198: #                      endif /* BIG_ENDIAN */
        !           199: #                      if (BYTE_ORDER == LITTLE_ENDIAN)
        !           200:                                sblock.fs_qbmask.val[0] = ~sblock.fs_bmask;
        !           201:                                sblock.fs_qbmask.val[1] = 0;
        !           202:                                sblock.fs_qfmask.val[0] = ~sblock.fs_fmask;
        !           203:                                sblock.fs_qfmask.val[1] = 0;
        !           204: #                      endif /* LITTLE_ENDIAN */
        !           205:                        sbdirty();
        !           206:                        dirty(&asblk);
        !           207:                } else if (sblock.fs_postblformat == FS_DYNAMICPOSTBLFMT) {
        !           208:                        /*
        !           209:                         * Requested to convert from new format to old format
        !           210:                         */
        !           211:                        if (sblock.fs_nrpos != 8 || sblock.fs_ipg > 2048 ||
        !           212:                            sblock.fs_cpg > 32 || sblock.fs_cpc > 16) {
        !           213:                                printf(
        !           214:                                "PARAMETERS OF CURRENT FILE SYSTEM DO NOT\n\t");
        !           215:                                errexit(
        !           216:                                "ALLOW CONVERSION TO OLD FILE SYSTEM FORMAT\n");
        !           217:                        }
        !           218:                        if (preen)
        !           219:                                pwarn("CONVERTING TO OLD FILE SYSTEM FORMAT\n");
        !           220:                        else if (!reply("CONVERT TO OLD FILE SYSTEM FORMAT"))
        !           221:                                return(0);
        !           222:                        sblock.fs_postblformat = FS_42POSTBLFMT;
        !           223:                        sblock.fs_cgsize = fragroundup(&sblock,
        !           224:                            sizeof(struct ocg) + howmany(sblock.fs_fpg, NBBY));
        !           225:                        sbdirty();
        !           226:                        dirty(&asblk);
        !           227:                } else {
        !           228:                        errexit("UNKNOWN FILE SYSTEM FORMAT\n");
        !           229:                }
        !           230:        }
        !           231:        if (asblk.b_dirty) {
        !           232:                bcopy((char *)&sblock, (char *)&altsblock,
        !           233:                        (size_t)sblock.fs_sbsize);
        !           234:                flush(fswritefd, &asblk);
        !           235:        }
        !           236:        /*
        !           237:         * read in the summary info.
        !           238:         */
        !           239:        asked = 0;
        !           240:        for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
        !           241:                size = sblock.fs_cssize - i < sblock.fs_bsize ?
        !           242:                    sblock.fs_cssize - i : sblock.fs_bsize;
        !           243:                sblock.fs_csp[j] = (struct csum *)calloc(1, (unsigned)size);
        !           244:                if (bread(fsreadfd, (char *)sblock.fs_csp[j],
        !           245:                    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
        !           246:                    size) != 0 && !asked) {
        !           247:                        pfatal("BAD SUMMARY INFORMATION");
        !           248:                        if (reply("CONTINUE") == 0)
        !           249:                                errexit("");
        !           250:                        asked++;
        !           251:                }
        !           252:        }
        !           253:        /*
        !           254:         * allocate and initialize the necessary maps
        !           255:         */
        !           256:        bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(short));
        !           257:        blockmap = calloc((unsigned)bmapsize, sizeof (char));
        !           258:        if (blockmap == NULL) {
        !           259:                printf("cannot alloc %u bytes for blockmap\n",
        !           260:                    (unsigned)bmapsize);
        !           261:                goto badsb;
        !           262:        }
        !           263:        statemap = calloc((unsigned)(maxino + 1), sizeof(char));
        !           264:        if (statemap == NULL) {
        !           265:                printf("cannot alloc %u bytes for statemap\n",
        !           266:                    (unsigned)(maxino + 1));
        !           267:                goto badsb;
        !           268:        }
        !           269:        lncntp = (short *)calloc((unsigned)(maxino + 1), sizeof(short));
        !           270:        if (lncntp == NULL) {
        !           271:                printf("cannot alloc %u bytes for lncntp\n", 
        !           272:                    (unsigned)(maxino + 1) * sizeof(short));
        !           273:                goto badsb;
        !           274:        }
        !           275:        numdirs = sblock.fs_cstotal.cs_ndir;
        !           276:        inplast = 0;
        !           277:        listmax = numdirs + 10;
        !           278:        inpsort = (struct inoinfo **)calloc((unsigned)listmax,
        !           279:            sizeof(struct inoinfo *));
        !           280:        inphead = (struct inoinfo **)calloc((unsigned)numdirs,
        !           281:            sizeof(struct inoinfo *));
        !           282:        if (inpsort == NULL || inphead == NULL) {
        !           283:                printf("cannot alloc %u bytes for inphead\n", 
        !           284:                    (unsigned)numdirs * sizeof(struct inoinfo *));
        !           285:                goto badsb;
        !           286:        }
        !           287:        bufinit();
        !           288:        return (1);
        !           289: 
        !           290: badsb:
        !           291:        ckfini();
        !           292:        return (0);
        !           293: }
        !           294: 
        !           295: /*
        !           296:  * Read in the super block and its summary info.
        !           297:  */
        !           298: readsb(listerr)
        !           299:        int listerr;
        !           300: {
        !           301:        daddr_t super = bflag ? bflag : SBOFF / dev_bsize;
        !           302: 
        !           303:        if (bread(fsreadfd, (char *)&sblock, super, (long)SBSIZE) != 0)
        !           304:                return (0);
        !           305:        sblk.b_bno = super;
        !           306:        sblk.b_size = SBSIZE;
        !           307:        /*
        !           308:         * run a few consistency checks of the super block
        !           309:         */
        !           310:        if (sblock.fs_magic != FS_MAGIC)
        !           311:                { badsb(listerr, "MAGIC NUMBER WRONG"); return (0); }
        !           312:        if (sblock.fs_ncg < 1)
        !           313:                { badsb(listerr, "NCG OUT OF RANGE"); return (0); }
        !           314:        if (sblock.fs_cpg < 1)
        !           315:                { badsb(listerr, "CPG OUT OF RANGE"); return (0); }
        !           316:        if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl ||
        !           317:            (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl)
        !           318:                { badsb(listerr, "NCYL LESS THAN NCG*CPG"); return (0); }
        !           319:        if (sblock.fs_sbsize > SBSIZE)
        !           320:                { badsb(listerr, "SIZE PREPOSTEROUSLY LARGE"); return (0); }
        !           321:        /*
        !           322:         * Compute block size that the filesystem is based on,
        !           323:         * according to fsbtodb, and adjust superblock block number
        !           324:         * so we can tell if this is an alternate later.
        !           325:         */
        !           326:        super *= dev_bsize;
        !           327:        dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
        !           328:        sblk.b_bno = super / dev_bsize;
        !           329:        /*
        !           330:         * Set all possible fields that could differ, then do check
        !           331:         * of whole super block against an alternate super block.
        !           332:         * When an alternate super-block is specified this check is skipped.
        !           333:         */
        !           334:        getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), sblock.fs_sbsize);
        !           335:        if (asblk.b_errs)
        !           336:                return (0);
        !           337:        if (bflag) {
        !           338:                havesb = 1;
        !           339:                return (1);
        !           340:        }
        !           341:        altsblock.fs_link = sblock.fs_link;
        !           342:        altsblock.fs_rlink = sblock.fs_rlink;
        !           343:        altsblock.fs_time = sblock.fs_time;
        !           344:        altsblock.fs_cstotal = sblock.fs_cstotal;
        !           345:        altsblock.fs_cgrotor = sblock.fs_cgrotor;
        !           346:        altsblock.fs_fmod = sblock.fs_fmod;
        !           347:        altsblock.fs_clean = sblock.fs_clean;
        !           348:        altsblock.fs_ronly = sblock.fs_ronly;
        !           349:        altsblock.fs_flags = sblock.fs_flags;
        !           350:        altsblock.fs_maxcontig = sblock.fs_maxcontig;
        !           351:        altsblock.fs_minfree = sblock.fs_minfree;
        !           352:        altsblock.fs_optim = sblock.fs_optim;
        !           353:        altsblock.fs_rotdelay = sblock.fs_rotdelay;
        !           354:        altsblock.fs_maxbpg = sblock.fs_maxbpg;
        !           355:        bcopy((char *)sblock.fs_csp, (char *)altsblock.fs_csp,
        !           356:                sizeof sblock.fs_csp);
        !           357:        bcopy((char *)sblock.fs_fsmnt, (char *)altsblock.fs_fsmnt,
        !           358:                sizeof sblock.fs_fsmnt);
        !           359:        bcopy((char *)sblock.fs_sparecon, (char *)altsblock.fs_sparecon,
        !           360:                sizeof sblock.fs_sparecon);
        !           361:        /*
        !           362:         * The following should not have to be copied.
        !           363:         */
        !           364:        altsblock.fs_fsbtodb = sblock.fs_fsbtodb;
        !           365:        altsblock.fs_interleave = sblock.fs_interleave;
        !           366:        altsblock.fs_npsect = sblock.fs_npsect;
        !           367:        altsblock.fs_nrpos = sblock.fs_nrpos;
        !           368:        if (bcmp((char *)&sblock, (char *)&altsblock, (int)sblock.fs_sbsize)) {
        !           369:                badsb(listerr,
        !           370:                "VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE");
        !           371:                return (0);
        !           372:        }
        !           373:        havesb = 1;
        !           374:        return (1);
        !           375: }
        !           376: 
        !           377: badsb(listerr, s)
        !           378:        int listerr;
        !           379:        char *s;
        !           380: {
        !           381: 
        !           382:        if (!listerr)
        !           383:                return;
        !           384:        if (preen)
        !           385:                printf("%s: ", devname);
        !           386:        pfatal("BAD SUPER BLOCK: %s\n", s);
        !           387: }
        !           388: 
        !           389: /*
        !           390:  * Calculate a prototype superblock based on information in the disk label.
        !           391:  * When done the cgsblock macro can be calculated and the fs_ncg field
        !           392:  * can be used. Do NOT attempt to use other macros without verifying that
        !           393:  * their needed information is available!
        !           394:  */
        !           395: calcsb(dev, devfd, fs)
        !           396:        char *dev;
        !           397:        int devfd;
        !           398:        register struct fs *fs;
        !           399: {
        !           400:        register struct disklabel *lp;
        !           401:        register struct partition *pp;
        !           402:        register char *cp;
        !           403:        int i;
        !           404: 
        !           405:        cp = index(dev, '\0') - 1;
        !           406:        if (cp == (char *)-1 || (*cp < 'a' || *cp > 'h') && !isdigit(*cp)) {
        !           407:                pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev);
        !           408:                return (0);
        !           409:        }
        !           410:        lp = getdisklabel(dev, devfd);
        !           411:        if (isdigit(*cp))
        !           412:                pp = &lp->d_partitions[0];
        !           413:        else
        !           414:                pp = &lp->d_partitions[*cp - 'a'];
        !           415:        if (pp->p_fstype != FS_BSDFFS) {
        !           416:                pfatal("%s: NOT LABELED AS A BSD FILE SYSTEM (%s)\n",
        !           417:                        dev, pp->p_fstype < FSMAXTYPES ?
        !           418:                        fstypenames[pp->p_fstype] : "unknown");
        !           419:                return (0);
        !           420:        }
        !           421:        bzero((char *)fs, sizeof(struct fs));
        !           422:        fs->fs_fsize = pp->p_fsize;
        !           423:        fs->fs_frag = pp->p_frag;
        !           424:        fs->fs_cpg = pp->p_cpg;
        !           425:        fs->fs_size = pp->p_size;
        !           426:        fs->fs_ntrak = lp->d_ntracks;
        !           427:        fs->fs_nsect = lp->d_nsectors;
        !           428:        fs->fs_spc = lp->d_secpercyl;
        !           429:        fs->fs_nspf = fs->fs_fsize / lp->d_secsize;
        !           430:        fs->fs_sblkno = roundup(
        !           431:                howmany(lp->d_bbsize + lp->d_sbsize, fs->fs_fsize),
        !           432:                fs->fs_frag);
        !           433:        fs->fs_cgmask = 0xffffffff;
        !           434:        for (i = fs->fs_ntrak; i > 1; i >>= 1)
        !           435:                fs->fs_cgmask <<= 1;
        !           436:        if (!POWEROF2(fs->fs_ntrak))
        !           437:                fs->fs_cgmask <<= 1;
        !           438:        fs->fs_cgoffset = roundup(
        !           439:                howmany(fs->fs_nsect, NSPF(fs)), fs->fs_frag);
        !           440:        fs->fs_fpg = (fs->fs_cpg * fs->fs_spc) / NSPF(fs);
        !           441:        fs->fs_ncg = howmany(fs->fs_size / fs->fs_spc, fs->fs_cpg);
        !           442:        for (fs->fs_fsbtodb = 0, i = NSPF(fs); i > 1; i >>= 1)
        !           443:                fs->fs_fsbtodb++;
        !           444:        dev_bsize = lp->d_secsize;
        !           445:        return (1);
        !           446: }
        !           447: 
        !           448: struct disklabel *
        !           449: getdisklabel(s, fd)
        !           450:        char *s;
        !           451:        int     fd;
        !           452: {
        !           453:        static struct disklabel lab;
        !           454: 
        !           455:        if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
        !           456:                if (s == NULL)
        !           457:                        return ((struct disklabel *)NULL);
        !           458:                pwarn("ioctl (GCINFO): %s\n", strerror(errno));
        !           459:                errexit("%s: can't read disk label\n", s);
        !           460:        }
        !           461:        return (&lab);
        !           462: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.