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