Home | History | Annotate | Line # | Download | only in fsck_lfs
setup.c revision 1.1
      1 /*	$Id: setup.c,v 1.1 1999/03/18 02:02:19 perseant Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1980, 1986, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by the University of
     18  *	California, Berkeley and its contributors.
     19  * 4. Neither the name of the University nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 /* #define DKTYPENAMES */
     37 #define FSTYPENAMES
     38 #include <sys/param.h>
     39 #include <sys/time.h>
     40 #include <sys/stat.h>
     41 #include <sys/ioctl.h>
     42 #include <sys/disklabel.h>
     43 #include <sys/file.h>
     44 
     45 #include <ufs/ufs/dinode.h>
     46 #include <sys/mount.h> /* XXX ufs/lfs/lfs.h should include this for us */
     47 #include <ufs/lfs/lfs.h>
     48 #include <ufs/lfs/lfs_extern.h>
     49 
     50 #include <ctype.h>
     51 #include <err.h>
     52 #include <errno.h>
     53 #include <stdio.h>
     54 #include <stdlib.h>
     55 #include <string.h>
     56 
     57 #include "fsck.h"
     58 #include "extern.h"
     59 #include "fsutil.h"
     60 
     61 struct bufarea asblk;
     62 extern struct dinode **din_table;
     63 extern SEGUSE *seg_table;
     64 #define altsblock (*asblk.b_un.b_fs)
     65 #define POWEROF2(num)	(((num) & ((num) - 1)) == 0)
     66 
     67 void badsb __P((int, char *));
     68 int calcsb __P((const char *, int, struct lfs *));
     69 static struct disklabel *getdisklabel __P((const char *, int));
     70 static int readsb __P((int));
     71 int lfs_maxino(void);
     72 
     73 #ifdef DKTYPENAMES
     74 int useless __P((void));
     75 
     76 int
     77 useless(void)
     78 {
     79 	char **foo = (char **)dktypenames;
     80 	char **bar = (char **)fscknames;
     81 
     82 	return foo-bar;
     83 }
     84 #endif
     85 
     86 int
     87 setup(dev)
     88 	const char *dev;
     89 {
     90 	long bmapsize;
     91 	struct disklabel *lp;
     92 #if 0
     93 	long i;
     94 	off_t sizepb;
     95 #endif
     96 	struct stat statb;
     97 	struct lfs proto;
     98 	int doskipclean;
     99 	u_int64_t maxfilesize;
    100         struct lfs *sb0;
    101 
    102 	havesb = 0;
    103 	fswritefd = -1;
    104 	doskipclean = skipclean;
    105 	if (stat(dev, &statb) < 0) {
    106 		printf("Can't stat %s: %s\n", dev, strerror(errno));
    107 		return (0);
    108 	}
    109 	if (!S_ISCHR(statb.st_mode)) {
    110 		pfatal("%s is not a character device", dev);
    111 		if (reply("CONTINUE") == 0)
    112 			return (0);
    113 	}
    114 	if ((fsreadfd = open(dev, O_RDONLY)) < 0) {
    115 		printf("Can't open %s: %s\n", dev, strerror(errno));
    116 		return (0);
    117 	}
    118 	if (preen == 0)
    119 		printf("** %s", dev);
    120 	if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) {
    121 		fswritefd = -1;
    122 		if (preen)
    123 			pfatal("NO WRITE ACCESS");
    124 		printf(" (NO WRITE)");
    125 	}
    126 	if (preen == 0)
    127 		printf("\n");
    128 	fsmodified = 0;
    129 	lfdir = 0;
    130 	initbarea(&sblk);
    131 	initbarea(&asblk);
    132 	sblk.b_un.b_buf = malloc(LFS_SBPAD);
    133 	asblk.b_un.b_buf = malloc(LFS_SBPAD);
    134 	if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL)
    135 		errexit("cannot allocate space for superblock\n");
    136 	if ((lp = getdisklabel((char *)NULL, fsreadfd)) != NULL)
    137 		dev_bsize = secsize = lp->d_secsize;
    138 	else
    139 		dev_bsize = secsize = DEV_BSIZE;
    140 
    141 	/*
    142 	 * Read in the superblock, looking for alternates if necessary
    143 	 */
    144 	if (readsb(1) == 0) {
    145 		if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0)
    146 			return(0);
    147 		if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
    148 			return (0);
    149 #if 0 /* XXX find the LFS way to do this */
    150 		for (cg = 0; cg < proto.lfs_ncg; cg++) {
    151 			bflag = fsbtodb(&proto, cgsblock(&proto, cg));
    152 			if (readsb(0) != 0)
    153 				break;
    154 		}
    155 		if (cg >= proto.lfs_ncg) {
    156 			printf("%s %s\n%s %s\n%s %s\n",
    157 				"SEARCH FOR ALTERNATE SUPER-BLOCK",
    158 				"FAILED. YOU MUST USE THE",
    159 				"-b OPTION TO FSCK_FFS TO SPECIFY THE",
    160 				"LOCATION OF AN ALTERNATE",
    161 				"SUPER-BLOCK TO SUPPLY NEEDED",
    162 				"INFORMATION; SEE fsck_ffs(8).");
    163 			return(0);
    164 		}
    165 #else
    166 		pwarn("XXX Can't look for alternate superblocks yet\n");
    167 		return(0);
    168 #endif
    169 		doskipclean = 0;
    170 		pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag);
    171 	}
    172 	if(bflag==0) {
    173 		/*
    174 		 * Even if that superblock read in properly, it may not
    175 		 * be guaranteed to point to a complete checkpoint.
    176 		 * Read in the second superblock too, and take whichever
    177 		 * of the two is *less* recent. --ks
    178 		 */
    179 		sb0 = malloc(sizeof(*sb0));
    180 		memcpy(sb0,&sblock,sizeof(*sb0));
    181 			bflag = sblock.lfs_sboffs[1];
    182 			if(readsb(1)==0) {
    183 				pwarn("COULDN'T READ ALT SUPERBLOCK AT BLK %d",bflag);
    184 				if (reply("ASSUME PRIMARY SUPERBLOCK IS GOOD") == 0) {
    185 					return (0);
    186 				} else { /* use primary as good */
    187 					memcpy(&sblock,sb0,sizeof(*sb0)); /* XXX cheating? */
    188 				}
    189 			} else {
    190 				if(debug)
    191 					pwarn("sb0 %d, sb1 %d\n",sb0->lfs_tstamp,sblock.lfs_tstamp);
    192 				if(sblock.lfs_tstamp >= sb0->lfs_tstamp) {
    193 					memcpy(&sblock,sb0,sizeof(*sb0)); /* XXX cheating? */
    194 				} else {
    195 					pwarn("Using alt superblock, disk addr 0x%x\n",
    196 					      bflag);
    197 				}
    198 			}
    199 		free(sb0);
    200 	}
    201 	if(debug) {
    202         	printf("dev_bsize = %lu\n",dev_bsize);
    203                 printf("lfs_bsize = %lu\n",(unsigned long)sblock.lfs_bsize);
    204                 printf("lfs_fsize = %lu\n",(unsigned long)sblock.lfs_fsize);
    205                 printf("lfs_frag  = %lu\n",(unsigned long)sblock.lfs_frag);
    206                 printf("INOPB(fs) = %lu\n",(unsigned long)INOPB(&sblock));
    207         	/* printf("fsbtodb(fs,1) = %lu\n",fsbtodb(&sblock,1)); */
    208 	}
    209 #if 0 /* FFS-specific fs-clean check */
    210 	if (debug)
    211 		printf("clean = %d\n", sblock.lfs_clean);
    212 	if (sblock.lfs_clean & FS_ISCLEAN) {
    213 		if (doskipclean) {
    214 			pwarn("%sile system is clean; not checking\n",
    215 			    preen ? "f" : "** F");
    216 			return (-1);
    217 		}
    218 		if (!preen)
    219 			pwarn("** File system is already clean\n");
    220 	}
    221 	maxino = sblock.lfs_ncg * sblock.lfs_ipg;
    222 #else
    223 #if 0
    224         /* XXX - count the number of inodes here */
    225         maxino = sblock.lfs_nfiles+2;
    226 #else
    227         initbarea(&iblk);
    228         iblk.b_un.b_buf = malloc(sblock.lfs_bsize);
    229         if(bread(fsreadfd, (char *)iblk.b_un.b_buf,
    230                  sblock.lfs_idaddr,
    231                  (long)sblock.lfs_bsize) != 0)
    232         {
    233             printf("Couldn't read disk block %d\n",sblock.lfs_idaddr);
    234             exit(1);
    235         }
    236         maxino = lfs_maxino();
    237 #endif
    238 	if (debug)
    239         	printf("maxino=%d\n",maxino);
    240         din_table = (struct dinode **)malloc(maxino*sizeof(*din_table));
    241         memset(din_table,0,maxino*sizeof(*din_table));
    242         seg_table = (SEGUSE *)malloc(sblock.lfs_nseg * sizeof(SEGUSE));
    243         memset(seg_table,0,sblock.lfs_nseg * sizeof(SEGUSE));
    244 #endif
    245 	maxfsblock = sblock.lfs_size * (sblock.lfs_bsize / dev_bsize);
    246 #if 0
    247 	sizepb = sblock.lfs_bsize;
    248 	maxfilesize = sblock.lfs_bsize * NDADDR - 1;
    249 	for (i = 0; i < NIADDR; i++) {
    250 		sizepb *= NINDIR(&sblock);
    251 		maxfilesize += sizepb;
    252 	}
    253         maxfilesize++; /* XXX */
    254 #else /* LFS way */
    255 {
    256 u_quad_t maxtable[] = {
    257         /*    1 */ -1,
    258         /*    2 */ -1,
    259         /*    4 */ -1,
    260         /*    8 */ -1,
    261         /*   16 */ -1,
    262         /*   32 */ -1,
    263         /*   64 */ -1,
    264         /*  128 */ -1,
    265         /*  256 */ -1,
    266         /*  512 */ NDADDR + 128 + 128 * 128 + 128 * 128 * 128,
    267         /* 1024 */ NDADDR + 256 + 256 * 256 + 256 * 256 * 256,
    268         /* 2048 */ NDADDR + 512 + 512 * 512 + 512 * 512 * 512,
    269         /* 4096 */ NDADDR + 1024 + 1024 * 1024 + 1024 * 1024 * 1024,
    270         /* 8192 */ 1 << 31,
    271         /* 16 K */ 1 << 31,
    272         /* 32 K */ 1 << 31,
    273 };
    274 	maxfilesize = maxtable[sblock.lfs_bshift] << sblock.lfs_bshift;
    275 }
    276 #endif
    277 	if ((sblock.lfs_minfree < 0 || sblock.lfs_minfree > 99)) {
    278 		pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK",
    279 			sblock.lfs_minfree);
    280 		if (reply("SET TO DEFAULT") == 1) {
    281 			sblock.lfs_minfree = 10;
    282 			sbdirty();
    283 		}
    284 	}
    285         /* XXX used to be ~(sblock.lfs_bsize - 1) */
    286 	if (sblock.lfs_bmask != sblock.lfs_bsize - 1) {
    287 		pwarn("INCORRECT BMASK=%x IN SUPERBLOCK (should be %x)",
    288 			(unsigned int)sblock.lfs_bmask,
    289 			(unsigned int)sblock.lfs_bsize - 1);
    290 		sblock.lfs_bmask = sblock.lfs_bsize - 1;
    291 		if (preen)
    292 			printf(" (FIXED)\n");
    293 		if (preen || reply("FIX") == 1) {
    294 			sbdirty();
    295 			dirty(&asblk);
    296 		}
    297 	}
    298 #if 0 /* FFS-specific checks */
    299 	if (sblock.lfs_fmask != ~(sblock.lfs_fsize - 1)) {
    300 		pwarn("INCORRECT FMASK=%x IN SUPERBLOCK",
    301 			sblock.lfs_fmask);
    302 		sblock.lfs_fmask = ~(sblock.lfs_fsize - 1);
    303 		if (preen)
    304 			printf(" (FIXED)\n");
    305 		if (preen || reply("FIX") == 1) {
    306 			sbdirty();
    307 			dirty(&asblk);
    308 		}
    309 	}
    310 #endif
    311 		if (sblock.lfs_maxfilesize != maxfilesize) {
    312 			pwarn("INCORRECT MAXFILESIZE=%qu IN SUPERBLOCK (should be %qu)",
    313 				sblock.lfs_maxfilesize, maxfilesize);
    314 			sblock.lfs_maxfilesize = maxfilesize;
    315 			if (preen)
    316 				printf(" (FIXED)\n");
    317 			if (preen || reply("FIX") == 1) {
    318 				sbdirty();
    319 				dirty(&asblk);
    320 			}
    321 		}
    322 		if (sblock.lfs_maxsymlinklen != MAXSYMLINKLEN) {
    323 			pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK",
    324 				sblock.lfs_maxsymlinklen);
    325 			sblock.lfs_maxsymlinklen = MAXSYMLINKLEN;
    326 			if (preen)
    327 				printf(" (FIXED)\n");
    328 			if (preen || reply("FIX") == 1) {
    329 				sbdirty();
    330 				dirty(&asblk);
    331 			}
    332 		}
    333 		newinofmt = 1;
    334 	/*
    335 	 * allocate and initialize the necessary maps
    336 	 */
    337 #ifndef VERBOSE_BLOCKMAP
    338 	bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t));
    339         blockmap = malloc((unsigned)bmapsize * sizeof (char));
    340         bzero(blockmap, bmapsize * sizeof(char));
    341 #else
    342 	bmapsize = maxfsblock*sizeof(ino_t);
    343         blockmap = (ino_t *)malloc(maxfsblock * sizeof (ino_t));
    344         bzero(blockmap, maxfsblock * sizeof(ino_t));
    345 #endif
    346 	if (blockmap == NULL) {
    347 		printf("cannot alloc %u bytes for blockmap\n",
    348 		    (unsigned)bmapsize);
    349 		goto badsblabel;
    350 	}
    351 	statemap = calloc((unsigned)(maxino + 1), sizeof(char));
    352 	if (statemap == NULL) {
    353 		printf("cannot alloc %u bytes for statemap\n",
    354 		    (unsigned)(maxino + 1));
    355 		goto badsblabel;
    356 	}
    357 	typemap = calloc((unsigned)(maxino + 1), sizeof(char));
    358 	if (typemap == NULL) {
    359 		printf("cannot alloc %u bytes for typemap\n",
    360 		    (unsigned)(maxino + 1));
    361 		goto badsblabel;
    362 	}
    363 	lncntp = (int16_t *)calloc((unsigned)(maxino + 1), sizeof(int16_t));
    364 	if (lncntp == NULL) {
    365 		printf("cannot alloc %u bytes for lncntp\n",
    366 		    (unsigned)(maxino + 1) * sizeof(int16_t));
    367 		goto badsblabel;
    368 	}
    369 	bufinit();
    370 	return (1);
    371 
    372 badsblabel:
    373 	ckfini(0);
    374 	return (0);
    375 }
    376 
    377 /*
    378  * Read in the LFS super block and its summary info.
    379  */
    380 static int
    381 readsb(listerr)
    382 	int listerr;
    383 {
    384 	daddr_t super = bflag ? bflag : LFS_LABELPAD / dev_bsize;
    385         u_int32_t checksum;
    386 
    387 	if (bread(fsreadfd, (char *)&sblock, super, (long)LFS_SBPAD) != 0)
    388 		return (0);
    389 
    390 	sblk.b_bno = super;
    391 	sblk.b_size = LFS_SBPAD;
    392 	/*
    393 	 * run a few consistency checks of the super block
    394 	 */
    395 	if (sblock.lfs_magic != LFS_MAGIC)
    396 		{ badsb(listerr, "MAGIC NUMBER WRONG"); return (0); }
    397 
    398         /* checksum */
    399         checksum = lfs_sb_cksum(&(sblock.lfs_dlfs));
    400         if(sblock.lfs_cksum != checksum)
    401         {
    402             printf("Superblock checksum (%lu) does not match computed checksum %lu\n",
    403                    (unsigned long)sblock.lfs_cksum, (unsigned long)checksum);
    404         }
    405 
    406 #if 0 /* XXX - replace these checks with appropriate LFS sanity checks */
    407 	if (sblock.lfs_ncg < 1)
    408 		{ badsb(listerr, "NCG OUT OF RANGE"); return (0); }
    409 	if (sblock.lfs_cpg < 1)
    410 		{ badsb(listerr, "CPG OUT OF RANGE"); return (0); }
    411 	if (sblock.lfs_ncg * sblock.lfs_cpg < sblock.lfs_ncyl ||
    412 	    (sblock.lfs_ncg - 1) * sblock.lfs_cpg >= sblock.lfs_ncyl)
    413 		{ badsb(listerr, "NCYL LESS THAN NCG*CPG"); return (0); }
    414 	if (sblock.lfs_sbsize > SBSIZE)
    415 		{ badsb(listerr, "SIZE PREPOSTEROUSLY LARGE"); return (0); }
    416 #endif
    417 	/*
    418 	 * Compute block size that the filesystem is based on,
    419 	 * according to fsbtodb, and adjust superblock block number
    420 	 * so we can tell if this is an alternate later.
    421 	 */
    422 	super *= dev_bsize;
    423 #if 0
    424 	dev_bsize = sblock.lfs_bsize / fsbtodb(&sblock, 1);
    425 #endif
    426 	sblk.b_bno = super / dev_bsize;
    427 	if (bflag) {
    428 		havesb = 1;
    429 		return (1);
    430 	}
    431 #if 0 /* XXX - for now skip the alt. superblock test as well */
    432 	/*
    433 	 * Set all possible fields that could differ, then do check
    434 	 * of whole super block against an alternate super block.
    435 	 * When an alternate super-block is specified this check is skipped.
    436 	 */
    437 	getblk(&asblk, cgsblock(&sblock, sblock.lfs_ncg - 1), sblock.lfs_sbsize);
    438 	if (asblk.b_errs)
    439 		return (0);
    440 	altsblock.lfs_firstfield = sblock.lfs_firstfield;
    441 	altsblock.lfs_fscktime = sblock.lfs_fscktime;
    442 	altsblock.lfs_time = sblock.lfs_time;
    443 	altsblock.lfs_cstotal = sblock.lfs_cstotal;
    444 	altsblock.lfs_cgrotor = sblock.lfs_cgrotor;
    445 	altsblock.lfs_fmod = sblock.lfs_fmod;
    446 	altsblock.lfs_clean = sblock.lfs_clean;
    447 	altsblock.lfs_ronly = sblock.lfs_ronly;
    448 	altsblock.lfs_flags = sblock.lfs_flags;
    449 	altsblock.lfs_maxcontig = sblock.lfs_maxcontig;
    450 	altsblock.lfs_minfree = sblock.lfs_minfree;
    451 	altsblock.lfs_optim = sblock.lfs_optim;
    452 	altsblock.lfs_rotdelay = sblock.lfs_rotdelay;
    453 	altsblock.lfs_maxbpg = sblock.lfs_maxbpg;
    454 	memcpy(altsblock.lfs_csp, sblock.lfs_csp,
    455 		sizeof sblock.lfs_csp);
    456 	altsblock.lfs_maxcluster = sblock.lfs_maxcluster;
    457 	memcpy(altsblock.lfs_fsmnt, sblock.lfs_fsmnt,
    458 		sizeof sblock.lfs_fsmnt);
    459 	memcpy(altsblock.lfs_sparecon, sblock.lfs_sparecon,
    460 		sizeof sblock.lfs_sparecon);
    461 	/*
    462 	 * The following should not have to be copied.
    463 	 */
    464 	altsblock.lfs_fsbtodb = sblock.lfs_fsbtodb;
    465 	altsblock.lfs_interleave = sblock.lfs_interleave;
    466 	altsblock.lfs_npsect = sblock.lfs_npsect;
    467 	altsblock.lfs_nrpos = sblock.lfs_nrpos;
    468 	altsblock.lfs_state = sblock.lfs_state;
    469 	altsblock.lfs_qbmask = sblock.lfs_qbmask;
    470 	altsblock.lfs_qfmask = sblock.lfs_qfmask;
    471 	altsblock.lfs_state = sblock.lfs_state;
    472 	altsblock.lfs_maxfilesize = sblock.lfs_maxfilesize;
    473 	if (memcmp(&sblock, &altsblock, (int)sblock.lfs_sbsize)) {
    474 		if (debug) {
    475 			long *nlp, *olp, *endlp;
    476 
    477 			printf("superblock mismatches\n");
    478 			nlp = (long *)&altsblock;
    479 			olp = (long *)&sblock;
    480 			endlp = olp + (sblock.lfs_sbsize / sizeof *olp);
    481 			for ( ; olp < endlp; olp++, nlp++) {
    482 				if (*olp == *nlp)
    483 					continue;
    484 				printf("offset %d, original %ld, alternate %ld\n",
    485 				    olp - (long *)&sblock, *olp, *nlp);
    486 			}
    487 		}
    488 		badsb(listerr,
    489 		"VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE");
    490 		return (0);
    491 	}
    492 #endif
    493 	havesb = 1;
    494 	return (1);
    495 }
    496 
    497 void
    498 badsb(listerr, s)
    499 	int listerr;
    500 	char *s;
    501 {
    502 
    503 	if (!listerr)
    504 		return;
    505 	if (preen)
    506 		printf("%s: ", cdevname());
    507 	pfatal("BAD SUPER BLOCK: %s\n", s);
    508 }
    509 
    510 /*
    511  * Calculate a prototype superblock based on information in the disk label.
    512  * When done the cgsblock macro can be calculated and the fs_ncg field
    513  * can be used. Do NOT attempt to use other macros without verifying that
    514  * their needed information is available!
    515  */
    516 int
    517 calcsb(dev, devfd, fs)
    518 	const char *dev;
    519 	int devfd;
    520 	register struct lfs *fs;
    521 {
    522 	register struct disklabel *lp;
    523 	register struct partition *pp;
    524 	register char *cp;
    525 	int i;
    526 
    527 	cp = strchr(dev, '\0') - 1;
    528 	if ((cp == (char *)-1 || (*cp < 'a' || *cp > 'h')) && !isdigit(*cp)) {
    529 		pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev);
    530 		return (0);
    531 	}
    532 	lp = getdisklabel(dev, devfd);
    533 	if (isdigit(*cp))
    534 		pp = &lp->d_partitions[0];
    535 	else
    536 		pp = &lp->d_partitions[*cp - 'a'];
    537 	if (pp->p_fstype != FS_BSDLFS) {
    538 		pfatal("%s: NOT LABELED AS AN LFS FILE SYSTEM (%s)\n",
    539 			dev, pp->p_fstype < FSMAXTYPES ?
    540 			fstypenames[pp->p_fstype] : "unknown");
    541 		return (0);
    542 	}
    543 	memset(fs, 0, sizeof(struct lfs));
    544 	fs->lfs_fsize = pp->p_fsize;
    545 	fs->lfs_frag = pp->p_frag;
    546 	fs->lfs_size = pp->p_size;
    547 	fs->lfs_nspf = fs->lfs_fsize / lp->d_secsize;
    548 	dev_bsize = lp->d_secsize;
    549 	for (fs->lfs_fsbtodb = 0, i = fs->lfs_nspf; i > 1; i >>= 1)
    550 		fs->lfs_fsbtodb++;
    551 	return (1);
    552 }
    553 
    554 static struct disklabel *
    555 getdisklabel(s, fd)
    556 	const char *s;
    557 	int	fd;
    558 {
    559 	static struct disklabel lab;
    560 
    561 	if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
    562 		if (s == NULL)
    563 			return ((struct disklabel *)NULL);
    564 		pwarn("ioctl (GCINFO): %s\n", strerror(errno));
    565 		errexit("%s: can't read disk label\n", s);
    566 	}
    567 	return (&lab);
    568 }
    569