setup.c revision 1.30 1 /* $NetBSD: setup.c,v 1.30 1997/09/16 16:45:33 lukem 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 #include <sys/cdefs.h>
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)setup.c 8.10 (Berkeley) 5/9/95";
40 #else
41 __RCSID("$NetBSD: setup.c,v 1.30 1997/09/16 16:45:33 lukem Exp $");
42 #endif
43 #endif /* not lint */
44
45 #define DKTYPENAMES
46 #include <sys/param.h>
47 #include <sys/time.h>
48 #include <sys/stat.h>
49 #include <sys/ioctl.h>
50 #include <sys/disklabel.h>
51 #include <sys/file.h>
52
53 #include <ufs/ufs/dinode.h>
54 #include <ufs/ffs/fs.h>
55
56 #include <ctype.h>
57 #include <err.h>
58 #include <errno.h>
59 #include <string.h>
60
61 #include "fsck.h"
62 #include "extern.h"
63 #include "fsutil.h"
64
65 struct bufarea asblk;
66 #define altsblock (*asblk.b_un.b_fs)
67 #define POWEROF2(num) (((num) & ((num) - 1)) == 0)
68
69 static void badsb __P((int, char *));
70 static int calcsb __P((char *, int, struct fs *));
71 static struct disklabel *getdisklabel __P((char *, int));
72 static int readsb __P((int));
73
74 /*
75 * Read in a superblock finding an alternate if necessary.
76 * Return 1 if successful, 0 if unsuccessful, -1 if filesystem
77 * is already clean (preen mode only).
78 */
79 int
80 setup(dev)
81 char *dev;
82 {
83 long cg, size, asked, i, j;
84 long bmapsize;
85 struct disklabel *lp;
86 off_t sizepb;
87 struct stat statb;
88 struct fs proto;
89 int doskipclean;
90 u_int64_t maxfilesize;
91
92 havesb = 0;
93 fswritefd = -1;
94 doskipclean = skipclean;
95 if (stat(dev, &statb) < 0) {
96 printf("Can't stat %s: %s\n", dev, strerror(errno));
97 return (0);
98 }
99 if (!S_ISCHR(statb.st_mode)) {
100 pfatal("%s is not a character device", dev);
101 if (reply("CONTINUE") == 0)
102 return (0);
103 }
104 if ((fsreadfd = open(dev, O_RDONLY)) < 0) {
105 printf("Can't open %s: %s\n", dev, strerror(errno));
106 return (0);
107 }
108 if (preen == 0)
109 printf("** %s", dev);
110 if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) {
111 fswritefd = -1;
112 if (preen)
113 pfatal("NO WRITE ACCESS");
114 printf(" (NO WRITE)");
115 }
116 if (preen == 0)
117 printf("\n");
118 fsmodified = 0;
119 lfdir = 0;
120 initbarea(&sblk);
121 initbarea(&asblk);
122 sblk.b_un.b_buf = malloc(SBSIZE);
123 asblk.b_un.b_buf = malloc(SBSIZE);
124 if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL)
125 errx(EEXIT, "cannot allocate space for superblock");
126 if ((lp = getdisklabel(NULL, fsreadfd)) != NULL)
127 dev_bsize = secsize = lp->d_secsize;
128 else
129 dev_bsize = secsize = DEV_BSIZE;
130 /*
131 * Read in the superblock, looking for alternates if necessary
132 */
133 if (readsb(1) == 0) {
134 skipclean = 0;
135 if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0)
136 return(0);
137 if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
138 return (0);
139 for (cg = 0; cg < proto.fs_ncg; cg++) {
140 bflag = fsbtodb(&proto, cgsblock(&proto, cg));
141 if (readsb(0) != 0)
142 break;
143 }
144 if (cg >= proto.fs_ncg) {
145 printf("%s %s\n%s %s\n%s %s\n",
146 "SEARCH FOR ALTERNATE SUPER-BLOCK",
147 "FAILED. YOU MUST USE THE",
148 "-b OPTION TO FSCK_FFS TO SPECIFY THE",
149 "LOCATION OF AN ALTERNATE",
150 "SUPER-BLOCK TO SUPPLY NEEDED",
151 "INFORMATION; SEE fsck_ffs(8).");
152 return(0);
153 }
154 doskipclean = 0;
155 pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag);
156 }
157 if (debug)
158 printf("clean = %d\n", sblock.fs_clean);
159 if (sblock.fs_clean & FS_ISCLEAN) {
160 if (doskipclean) {
161 pwarn("%sile system is clean; not checking\n",
162 preen ? "f" : "** F");
163 return (-1);
164 }
165 if (!preen)
166 pwarn("** File system is already clean\n");
167 }
168 maxfsblock = sblock.fs_size;
169 maxino = sblock.fs_ncg * sblock.fs_ipg;
170 sizepb = sblock.fs_bsize;
171 maxfilesize = sblock.fs_bsize * NDADDR - 1;
172 for (i = 0; i < NIADDR; i++) {
173 sizepb *= NINDIR(&sblock);
174 maxfilesize += sizepb;
175 }
176 /*
177 * Check and potentially fix certain fields in the super block.
178 */
179 if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) {
180 pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK");
181 if (reply("SET TO DEFAULT") == 1) {
182 sblock.fs_optim = FS_OPTTIME;
183 sbdirty();
184 }
185 }
186 if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) {
187 pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK",
188 sblock.fs_minfree);
189 if (reply("SET TO DEFAULT") == 1) {
190 sblock.fs_minfree = 10;
191 sbdirty();
192 }
193 }
194 if (sblock.fs_interleave < 1 ||
195 sblock.fs_interleave > sblock.fs_nsect) {
196 pwarn("IMPOSSIBLE INTERLEAVE=%d IN SUPERBLOCK",
197 sblock.fs_interleave);
198 sblock.fs_interleave = 1;
199 if (preen)
200 printf(" (FIXED)\n");
201 if (preen || reply("SET TO DEFAULT") == 1) {
202 sbdirty();
203 dirty(&asblk);
204 }
205 }
206 if (sblock.fs_npsect < sblock.fs_nsect ||
207 sblock.fs_npsect > sblock.fs_nsect*2) {
208 pwarn("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK",
209 sblock.fs_npsect);
210 sblock.fs_npsect = sblock.fs_nsect;
211 if (preen)
212 printf(" (FIXED)\n");
213 if (preen || reply("SET TO DEFAULT") == 1) {
214 sbdirty();
215 dirty(&asblk);
216 }
217 }
218 if (sblock.fs_bmask != ~(sblock.fs_bsize - 1)) {
219 pwarn("INCORRECT BMASK=0x%x IN SUPERBLOCK",
220 sblock.fs_bmask);
221 sblock.fs_bmask = ~(sblock.fs_bsize - 1);
222 if (preen)
223 printf(" (FIXED)\n");
224 if (preen || reply("FIX") == 1) {
225 sbdirty();
226 dirty(&asblk);
227 }
228 }
229 if (sblock.fs_fmask != ~(sblock.fs_fsize - 1)) {
230 pwarn("INCORRECT FMASK=0x%x IN SUPERBLOCK",
231 sblock.fs_fmask);
232 sblock.fs_fmask = ~(sblock.fs_fsize - 1);
233 if (preen)
234 printf(" (FIXED)\n");
235 if (preen || reply("FIX") == 1) {
236 sbdirty();
237 dirty(&asblk);
238 }
239 }
240 if (sblock.fs_inodefmt >= FS_44INODEFMT) {
241 if (sblock.fs_maxfilesize != maxfilesize) {
242 pwarn("INCORRECT MAXFILESIZE=%qd IN SUPERBLOCK",
243 (unsigned long long)sblock.fs_maxfilesize);
244 sblock.fs_maxfilesize = maxfilesize;
245 if (preen)
246 printf(" (FIXED)\n");
247 if (preen || reply("FIX") == 1) {
248 sbdirty();
249 dirty(&asblk);
250 }
251 }
252 if (sblock.fs_maxsymlinklen != MAXSYMLINKLEN) {
253 pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK",
254 sblock.fs_maxsymlinklen);
255 sblock.fs_maxsymlinklen = MAXSYMLINKLEN;
256 if (preen)
257 printf(" (FIXED)\n");
258 if (preen || reply("FIX") == 1) {
259 sbdirty();
260 dirty(&asblk);
261 }
262 }
263 if (sblock.fs_qbmask != ~sblock.fs_bmask) {
264 pwarn("INCORRECT QBMASK=%qx IN SUPERBLOCK",
265 (unsigned long long)sblock.fs_qbmask);
266 sblock.fs_qbmask = ~sblock.fs_bmask;
267 if (preen)
268 printf(" (FIXED)\n");
269 if (preen || reply("FIX") == 1) {
270 sbdirty();
271 dirty(&asblk);
272 }
273 }
274 if (sblock.fs_qfmask != ~sblock.fs_fmask) {
275 pwarn("INCORRECT QFMASK=%qx IN SUPERBLOCK",
276 (unsigned long long)sblock.fs_qfmask);
277 sblock.fs_qfmask = ~sblock.fs_fmask;
278 if (preen)
279 printf(" (FIXED)\n");
280 if (preen || reply("FIX") == 1) {
281 sbdirty();
282 dirty(&asblk);
283 }
284 }
285 newinofmt = 1;
286 } else {
287 sblock.fs_qbmask = ~sblock.fs_bmask;
288 sblock.fs_qfmask = ~sblock.fs_fmask;
289 newinofmt = 0;
290 }
291 /*
292 * Convert to new inode format.
293 */
294 if (cvtlevel >= 2 && sblock.fs_inodefmt < FS_44INODEFMT) {
295 if (preen)
296 pwarn("CONVERTING TO NEW INODE FORMAT\n");
297 else if (!reply("CONVERT TO NEW INODE FORMAT"))
298 return(0);
299 doinglevel2++;
300 sblock.fs_inodefmt = FS_44INODEFMT;
301 sblock.fs_maxfilesize = maxfilesize;
302 sblock.fs_maxsymlinklen = MAXSYMLINKLEN;
303 sblock.fs_qbmask = ~sblock.fs_bmask;
304 sblock.fs_qfmask = ~sblock.fs_fmask;
305 sbdirty();
306 dirty(&asblk);
307 }
308 /*
309 * Convert to new cylinder group format.
310 */
311 if (cvtlevel >= 1 && sblock.fs_postblformat == FS_42POSTBLFMT) {
312 if (preen)
313 pwarn("CONVERTING TO NEW CYLINDER GROUP FORMAT\n");
314 else if (!reply("CONVERT TO NEW CYLINDER GROUP FORMAT"))
315 return(0);
316 doinglevel1++;
317 sblock.fs_postblformat = FS_DYNAMICPOSTBLFMT;
318 sblock.fs_nrpos = 8;
319 sblock.fs_postbloff =
320 (char *)(&sblock.fs_opostbl[0][0]) -
321 (char *)(&sblock.fs_firstfield);
322 sblock.fs_rotbloff = &sblock.fs_space[0] -
323 (u_char *)(&sblock.fs_firstfield);
324 sblock.fs_cgsize =
325 fragroundup(&sblock, CGSIZE(&sblock));
326 sbdirty();
327 dirty(&asblk);
328 }
329 if (asblk.b_dirty && !bflag) {
330 memmove(&altsblock, &sblock, (size_t)sblock.fs_sbsize);
331 flush(fswritefd, &asblk);
332 }
333 /*
334 * read in the summary info.
335 */
336 asked = 0;
337 for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
338 size = sblock.fs_cssize - i < sblock.fs_bsize ?
339 sblock.fs_cssize - i : sblock.fs_bsize;
340 sblock.fs_csp[j] = (struct csum *)calloc(1, (unsigned)size);
341 if (bread(fsreadfd, (char *)sblock.fs_csp[j],
342 fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
343 size) != 0 && !asked) {
344 pfatal("BAD SUMMARY INFORMATION");
345 if (reply("CONTINUE") == 0)
346 exit(EEXIT);
347 asked++;
348 }
349 }
350 /*
351 * allocate and initialize the necessary maps
352 */
353 bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t));
354 blockmap = calloc((unsigned)bmapsize, sizeof (char));
355 if (blockmap == NULL) {
356 printf("cannot alloc %u bytes for blockmap\n",
357 (unsigned)bmapsize);
358 goto badsblabel;
359 }
360 statemap = calloc((unsigned)(maxino + 1), sizeof(char));
361 if (statemap == NULL) {
362 printf("cannot alloc %u bytes for statemap\n",
363 (unsigned)(maxino + 1));
364 goto badsblabel;
365 }
366 typemap = calloc((unsigned)(maxino + 1), sizeof(char));
367 if (typemap == NULL) {
368 printf("cannot alloc %u bytes for typemap\n",
369 (unsigned)(maxino + 1));
370 goto badsblabel;
371 }
372 lncntp = (int16_t *)calloc((unsigned)(maxino + 1), sizeof(int16_t));
373 if (lncntp == NULL) {
374 printf("cannot alloc %u bytes for lncntp\n",
375 (unsigned)((maxino + 1) * sizeof(int16_t)));
376 goto badsblabel;
377 }
378 numdirs = sblock.fs_cstotal.cs_ndir;
379 inplast = 0;
380 listmax = numdirs + 10;
381 inpsort = (struct inoinfo **)calloc((unsigned)listmax,
382 sizeof(struct inoinfo *));
383 inphead = (struct inoinfo **)calloc((unsigned)numdirs,
384 sizeof(struct inoinfo *));
385 if (inpsort == NULL || inphead == NULL) {
386 printf("cannot alloc %u bytes for inphead\n",
387 (unsigned)(numdirs * sizeof(struct inoinfo *)));
388 goto badsblabel;
389 }
390 bufinit();
391 return (1);
392
393 badsblabel:
394 ckfini(0);
395 return (0);
396 }
397
398 /*
399 * Read in the super block and its summary info.
400 */
401 static int
402 readsb(listerr)
403 int listerr;
404 {
405 ufs_daddr_t super = bflag ? bflag : SBOFF / dev_bsize;
406
407 if (bread(fsreadfd, (char *)&sblock, super, (long)SBSIZE) != 0)
408 return (0);
409 sblk.b_bno = super;
410 sblk.b_size = SBSIZE;
411 /*
412 * run a few consistency checks of the super block
413 */
414 if (sblock.fs_magic != FS_MAGIC)
415 { badsb(listerr, "MAGIC NUMBER WRONG"); return (0); }
416 if (sblock.fs_ncg < 1)
417 { badsb(listerr, "NCG OUT OF RANGE"); return (0); }
418 if (sblock.fs_cpg < 1)
419 { badsb(listerr, "CPG OUT OF RANGE"); return (0); }
420 if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl ||
421 (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl)
422 { badsb(listerr, "NCYL LESS THAN NCG*CPG"); return (0); }
423 if (sblock.fs_sbsize > SBSIZE)
424 { badsb(listerr, "SIZE PREPOSTEROUSLY LARGE"); return (0); }
425 /*
426 * Compute block size that the filesystem is based on,
427 * according to fsbtodb, and adjust superblock block number
428 * so we can tell if this is an alternate later.
429 */
430 super *= dev_bsize;
431 dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
432 sblk.b_bno = super / dev_bsize;
433 if (bflag) {
434 havesb = 1;
435 return (1);
436 }
437 /*
438 * Set all possible fields that could differ, then do check
439 * of whole super block against an alternate super block.
440 * When an alternate super-block is specified this check is skipped.
441 */
442 getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), sblock.fs_sbsize);
443 if (asblk.b_errs)
444 return (0);
445 altsblock.fs_firstfield = sblock.fs_firstfield;
446 altsblock.fs_fscktime = sblock.fs_fscktime;
447 altsblock.fs_unused_1 = sblock.fs_unused_1;
448 altsblock.fs_time = sblock.fs_time;
449 altsblock.fs_cstotal = sblock.fs_cstotal;
450 altsblock.fs_cgrotor = sblock.fs_cgrotor;
451 altsblock.fs_fmod = sblock.fs_fmod;
452 altsblock.fs_clean = sblock.fs_clean;
453 altsblock.fs_ronly = sblock.fs_ronly;
454 altsblock.fs_flags = sblock.fs_flags;
455 altsblock.fs_maxcontig = sblock.fs_maxcontig;
456 altsblock.fs_minfree = sblock.fs_minfree;
457 altsblock.fs_optim = sblock.fs_optim;
458 altsblock.fs_rotdelay = sblock.fs_rotdelay;
459 altsblock.fs_maxbpg = sblock.fs_maxbpg;
460 memmove(altsblock.fs_csp, sblock.fs_csp, sizeof sblock.fs_csp);
461 altsblock.fs_maxcluster = sblock.fs_maxcluster;
462 memmove(altsblock.fs_fsmnt, sblock.fs_fsmnt, sizeof sblock.fs_fsmnt);
463 memmove(altsblock.fs_sparecon,
464 sblock.fs_sparecon, sizeof sblock.fs_sparecon);
465 /*
466 * The following should not have to be copied.
467 */
468 altsblock.fs_fsbtodb = sblock.fs_fsbtodb;
469 altsblock.fs_interleave = sblock.fs_interleave;
470 altsblock.fs_npsect = sblock.fs_npsect;
471 altsblock.fs_nrpos = sblock.fs_nrpos;
472 altsblock.fs_state = sblock.fs_state;
473 altsblock.fs_qbmask = sblock.fs_qbmask;
474 altsblock.fs_qfmask = sblock.fs_qfmask;
475 altsblock.fs_state = sblock.fs_state;
476 altsblock.fs_maxfilesize = sblock.fs_maxfilesize;
477 if (memcmp(&sblock, &altsblock, (int)sblock.fs_sbsize)) {
478 if (debug) {
479 long *nlp, *olp, *endlp;
480
481 printf("superblock mismatches\n");
482 nlp = (long *)&altsblock;
483 olp = (long *)&sblock;
484 endlp = olp + (sblock.fs_sbsize / sizeof *olp);
485 for ( ; olp < endlp; olp++, nlp++) {
486 if (*olp == *nlp)
487 continue;
488 printf("offset %ld, original %ld, alternate %ld\n",
489 (long)(olp - (long *)&sblock), *olp, *nlp);
490 }
491 }
492 badsb(listerr,
493 "VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE");
494 return (0);
495 }
496 havesb = 1;
497 return (1);
498 }
499
500 static void
501 badsb(listerr, s)
502 int listerr;
503 char *s;
504 {
505
506 if (!listerr)
507 return;
508 if (preen)
509 printf("%s: ", cdevname());
510 pfatal("BAD SUPER BLOCK: %s\n", s);
511 }
512
513 /*
514 * Calculate a prototype superblock based on information in the disk label.
515 * When done the cgsblock macro can be calculated and the fs_ncg field
516 * can be used. Do NOT attempt to use other macros without verifying that
517 * their needed information is available!
518 */
519 static int
520 calcsb(dev, devfd, fs)
521 char *dev;
522 int devfd;
523 struct fs *fs;
524 {
525 struct disklabel *lp;
526 struct partition *pp;
527 char *cp;
528 int i;
529
530 cp = strchr(dev, '\0') - 1;
531 if ((cp == (char *)-1 || (*cp < 'a' || *cp > 'h')) && !isdigit(*cp)) {
532 pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev);
533 return (0);
534 }
535 lp = getdisklabel(dev, devfd);
536 if (isdigit(*cp))
537 pp = &lp->d_partitions[0];
538 else
539 pp = &lp->d_partitions[*cp - 'a'];
540 if (pp->p_fstype != FS_BSDFFS) {
541 pfatal("%s: NOT LABELED AS A BSD FILE SYSTEM (%s)\n",
542 dev, pp->p_fstype < FSMAXTYPES ?
543 fstypenames[pp->p_fstype] : "unknown");
544 return (0);
545 }
546 memset(fs, 0, sizeof(struct fs));
547 fs->fs_fsize = pp->p_fsize;
548 fs->fs_frag = pp->p_frag;
549 fs->fs_cpg = pp->p_cpg;
550 fs->fs_size = pp->p_size;
551 fs->fs_ntrak = lp->d_ntracks;
552 fs->fs_nsect = lp->d_nsectors;
553 fs->fs_spc = lp->d_secpercyl;
554 fs->fs_nspf = fs->fs_fsize / lp->d_secsize;
555 fs->fs_sblkno = roundup(
556 howmany(lp->d_bbsize + lp->d_sbsize, fs->fs_fsize),
557 fs->fs_frag);
558 fs->fs_cgmask = 0xffffffff;
559 for (i = fs->fs_ntrak; i > 1; i >>= 1)
560 fs->fs_cgmask <<= 1;
561 if (!POWEROF2(fs->fs_ntrak))
562 fs->fs_cgmask <<= 1;
563 fs->fs_cgoffset = roundup(
564 howmany(fs->fs_nsect, NSPF(fs)), fs->fs_frag);
565 fs->fs_fpg = (fs->fs_cpg * fs->fs_spc) / NSPF(fs);
566 fs->fs_ncg = howmany(fs->fs_size / fs->fs_spc, fs->fs_cpg);
567 for (fs->fs_fsbtodb = 0, i = NSPF(fs); i > 1; i >>= 1)
568 fs->fs_fsbtodb++;
569 dev_bsize = lp->d_secsize;
570 return (1);
571 }
572
573 static struct disklabel *
574 getdisklabel(s, fd)
575 char *s;
576 int fd;
577 {
578 static struct disklabel lab;
579
580 if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
581 if (s == NULL)
582 return ((struct disklabel *)NULL);
583 pwarn("ioctl (GCINFO): %s\n", strerror(errno));
584 errx(EEXIT, "%s: can't read disk label", s);
585 }
586 return (&lab);
587 }
588