Home | History | Annotate | Line # | Download | only in fsck_lfs
setup.c revision 1.2
      1 /*	$Id: setup.c,v 1.2 1999/03/24 05:32:23 nathanw 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 				(unsigned long long)sblock.lfs_maxfilesize,
    314 				(unsigned long long)maxfilesize);
    315 			sblock.lfs_maxfilesize = maxfilesize;
    316 			if (preen)
    317 				printf(" (FIXED)\n");
    318 			if (preen || reply("FIX") == 1) {
    319 				sbdirty();
    320 				dirty(&asblk);
    321 			}
    322 		}
    323 		if (sblock.lfs_maxsymlinklen != MAXSYMLINKLEN) {
    324 			pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK",
    325 				sblock.lfs_maxsymlinklen);
    326 			sblock.lfs_maxsymlinklen = MAXSYMLINKLEN;
    327 			if (preen)
    328 				printf(" (FIXED)\n");
    329 			if (preen || reply("FIX") == 1) {
    330 				sbdirty();
    331 				dirty(&asblk);
    332 			}
    333 		}
    334 		newinofmt = 1;
    335 	/*
    336 	 * allocate and initialize the necessary maps
    337 	 */
    338 #ifndef VERBOSE_BLOCKMAP
    339 	bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t));
    340         blockmap = malloc((unsigned)bmapsize * sizeof (char));
    341         bzero(blockmap, bmapsize * sizeof(char));
    342 #else
    343 	bmapsize = maxfsblock*sizeof(ino_t);
    344         blockmap = (ino_t *)malloc(maxfsblock * sizeof (ino_t));
    345         bzero(blockmap, maxfsblock * sizeof(ino_t));
    346 #endif
    347 	if (blockmap == NULL) {
    348 		printf("cannot alloc %u bytes for blockmap\n",
    349 		    (unsigned)bmapsize);
    350 		goto badsblabel;
    351 	}
    352 	statemap = calloc((unsigned)(maxino + 1), sizeof(char));
    353 	if (statemap == NULL) {
    354 		printf("cannot alloc %u bytes for statemap\n",
    355 		    (unsigned)(maxino + 1));
    356 		goto badsblabel;
    357 	}
    358 	typemap = calloc((unsigned)(maxino + 1), sizeof(char));
    359 	if (typemap == NULL) {
    360 		printf("cannot alloc %u bytes for typemap\n",
    361 		    (unsigned)(maxino + 1));
    362 		goto badsblabel;
    363 	}
    364 	lncntp = (int16_t *)calloc((unsigned)(maxino + 1), sizeof(int16_t));
    365 	if (lncntp == NULL) {
    366 		printf("cannot alloc %lu bytes for lncntp\n",
    367 		    (unsigned long)(maxino + 1) * sizeof(int16_t));
    368 		goto badsblabel;
    369 	}
    370 	bufinit();
    371 	return (1);
    372 
    373 badsblabel:
    374 	ckfini(0);
    375 	return (0);
    376 }
    377 
    378 /*
    379  * Read in the LFS super block and its summary info.
    380  */
    381 static int
    382 readsb(listerr)
    383 	int listerr;
    384 {
    385 	daddr_t super = bflag ? bflag : LFS_LABELPAD / dev_bsize;
    386         u_int32_t checksum;
    387 
    388 	if (bread(fsreadfd, (char *)&sblock, super, (long)LFS_SBPAD) != 0)
    389 		return (0);
    390 
    391 	sblk.b_bno = super;
    392 	sblk.b_size = LFS_SBPAD;
    393 	/*
    394 	 * run a few consistency checks of the super block
    395 	 */
    396 	if (sblock.lfs_magic != LFS_MAGIC)
    397 		{ badsb(listerr, "MAGIC NUMBER WRONG"); return (0); }
    398 
    399         /* checksum */
    400         checksum = lfs_sb_cksum(&(sblock.lfs_dlfs));
    401         if(sblock.lfs_cksum != checksum)
    402         {
    403             printf("Superblock checksum (%lu) does not match computed checksum %lu\n",
    404                    (unsigned long)sblock.lfs_cksum, (unsigned long)checksum);
    405         }
    406 
    407 #if 0 /* XXX - replace these checks with appropriate LFS sanity checks */
    408 	if (sblock.lfs_ncg < 1)
    409 		{ badsb(listerr, "NCG OUT OF RANGE"); return (0); }
    410 	if (sblock.lfs_cpg < 1)
    411 		{ badsb(listerr, "CPG OUT OF RANGE"); return (0); }
    412 	if (sblock.lfs_ncg * sblock.lfs_cpg < sblock.lfs_ncyl ||
    413 	    (sblock.lfs_ncg - 1) * sblock.lfs_cpg >= sblock.lfs_ncyl)
    414 		{ badsb(listerr, "NCYL LESS THAN NCG*CPG"); return (0); }
    415 	if (sblock.lfs_sbsize > SBSIZE)
    416 		{ badsb(listerr, "SIZE PREPOSTEROUSLY LARGE"); return (0); }
    417 #endif
    418 	/*
    419 	 * Compute block size that the filesystem is based on,
    420 	 * according to fsbtodb, and adjust superblock block number
    421 	 * so we can tell if this is an alternate later.
    422 	 */
    423 	super *= dev_bsize;
    424 #if 0
    425 	dev_bsize = sblock.lfs_bsize / fsbtodb(&sblock, 1);
    426 #endif
    427 	sblk.b_bno = super / dev_bsize;
    428 	if (bflag) {
    429 		havesb = 1;
    430 		return (1);
    431 	}
    432 #if 0 /* XXX - for now skip the alt. superblock test as well */
    433 	/*
    434 	 * Set all possible fields that could differ, then do check
    435 	 * of whole super block against an alternate super block.
    436 	 * When an alternate super-block is specified this check is skipped.
    437 	 */
    438 	getblk(&asblk, cgsblock(&sblock, sblock.lfs_ncg - 1), sblock.lfs_sbsize);
    439 	if (asblk.b_errs)
    440 		return (0);
    441 	altsblock.lfs_firstfield = sblock.lfs_firstfield;
    442 	altsblock.lfs_fscktime = sblock.lfs_fscktime;
    443 	altsblock.lfs_time = sblock.lfs_time;
    444 	altsblock.lfs_cstotal = sblock.lfs_cstotal;
    445 	altsblock.lfs_cgrotor = sblock.lfs_cgrotor;
    446 	altsblock.lfs_fmod = sblock.lfs_fmod;
    447 	altsblock.lfs_clean = sblock.lfs_clean;
    448 	altsblock.lfs_ronly = sblock.lfs_ronly;
    449 	altsblock.lfs_flags = sblock.lfs_flags;
    450 	altsblock.lfs_maxcontig = sblock.lfs_maxcontig;
    451 	altsblock.lfs_minfree = sblock.lfs_minfree;
    452 	altsblock.lfs_optim = sblock.lfs_optim;
    453 	altsblock.lfs_rotdelay = sblock.lfs_rotdelay;
    454 	altsblock.lfs_maxbpg = sblock.lfs_maxbpg;
    455 	memcpy(altsblock.lfs_csp, sblock.lfs_csp,
    456 		sizeof sblock.lfs_csp);
    457 	altsblock.lfs_maxcluster = sblock.lfs_maxcluster;
    458 	memcpy(altsblock.lfs_fsmnt, sblock.lfs_fsmnt,
    459 		sizeof sblock.lfs_fsmnt);
    460 	memcpy(altsblock.lfs_sparecon, sblock.lfs_sparecon,
    461 		sizeof sblock.lfs_sparecon);
    462 	/*
    463 	 * The following should not have to be copied.
    464 	 */
    465 	altsblock.lfs_fsbtodb = sblock.lfs_fsbtodb;
    466 	altsblock.lfs_interleave = sblock.lfs_interleave;
    467 	altsblock.lfs_npsect = sblock.lfs_npsect;
    468 	altsblock.lfs_nrpos = sblock.lfs_nrpos;
    469 	altsblock.lfs_state = sblock.lfs_state;
    470 	altsblock.lfs_qbmask = sblock.lfs_qbmask;
    471 	altsblock.lfs_qfmask = sblock.lfs_qfmask;
    472 	altsblock.lfs_state = sblock.lfs_state;
    473 	altsblock.lfs_maxfilesize = sblock.lfs_maxfilesize;
    474 	if (memcmp(&sblock, &altsblock, (int)sblock.lfs_sbsize)) {
    475 		if (debug) {
    476 			long *nlp, *olp, *endlp;
    477 
    478 			printf("superblock mismatches\n");
    479 			nlp = (long *)&altsblock;
    480 			olp = (long *)&sblock;
    481 			endlp = olp + (sblock.lfs_sbsize / sizeof *olp);
    482 			for ( ; olp < endlp; olp++, nlp++) {
    483 				if (*olp == *nlp)
    484 					continue;
    485 				printf("offset %d, original %ld, alternate %ld\n",
    486 				    olp - (long *)&sblock, *olp, *nlp);
    487 			}
    488 		}
    489 		badsb(listerr,
    490 		"VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE");
    491 		return (0);
    492 	}
    493 #endif
    494 	havesb = 1;
    495 	return (1);
    496 }
    497 
    498 void
    499 badsb(listerr, s)
    500 	int listerr;
    501 	char *s;
    502 {
    503 
    504 	if (!listerr)
    505 		return;
    506 	if (preen)
    507 		printf("%s: ", cdevname());
    508 	pfatal("BAD SUPER BLOCK: %s\n", s);
    509 }
    510 
    511 /*
    512  * Calculate a prototype superblock based on information in the disk label.
    513  * When done the cgsblock macro can be calculated and the fs_ncg field
    514  * can be used. Do NOT attempt to use other macros without verifying that
    515  * their needed information is available!
    516  */
    517 int
    518 calcsb(dev, devfd, fs)
    519 	const char *dev;
    520 	int devfd;
    521 	register struct lfs *fs;
    522 {
    523 	register struct disklabel *lp;
    524 	register struct partition *pp;
    525 	register char *cp;
    526 	int i;
    527 
    528 	cp = strchr(dev, '\0') - 1;
    529 	if ((cp == (char *)-1 || (*cp < 'a' || *cp > 'h')) && !isdigit(*cp)) {
    530 		pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev);
    531 		return (0);
    532 	}
    533 	lp = getdisklabel(dev, devfd);
    534 	if (isdigit(*cp))
    535 		pp = &lp->d_partitions[0];
    536 	else
    537 		pp = &lp->d_partitions[*cp - 'a'];
    538 	if (pp->p_fstype != FS_BSDLFS) {
    539 		pfatal("%s: NOT LABELED AS AN LFS FILE SYSTEM (%s)\n",
    540 			dev, pp->p_fstype < FSMAXTYPES ?
    541 			fstypenames[pp->p_fstype] : "unknown");
    542 		return (0);
    543 	}
    544 	memset(fs, 0, sizeof(struct lfs));
    545 	fs->lfs_fsize = pp->p_fsize;
    546 	fs->lfs_frag = pp->p_frag;
    547 	fs->lfs_size = pp->p_size;
    548 	fs->lfs_nspf = fs->lfs_fsize / lp->d_secsize;
    549 	dev_bsize = lp->d_secsize;
    550 	for (fs->lfs_fsbtodb = 0, i = fs->lfs_nspf; i > 1; i >>= 1)
    551 		fs->lfs_fsbtodb++;
    552 	return (1);
    553 }
    554 
    555 static struct disklabel *
    556 getdisklabel(s, fd)
    557 	const char *s;
    558 	int	fd;
    559 {
    560 	static struct disklabel lab;
    561 
    562 	if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
    563 		if (s == NULL)
    564 			return ((struct disklabel *)NULL);
    565 		pwarn("ioctl (GCINFO): %s\n", strerror(errno));
    566 		errexit("%s: can't read disk label\n", s);
    567 	}
    568 	return (&lab);
    569 }
    570