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