Commit | Line | Data |
---|---|---|
76797561 | 1 | /* |
21e5ab9a KB |
2 | * Copyright (c) 1980, 1986, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
fe32782c | 4 | * |
70ab3c27 | 5 | * %sccs.include.redist.c% |
76797561 DF |
6 | */ |
7 | ||
eb93b62a | 8 | #ifndef lint |
6c3d0366 | 9 | static char sccsid[] = "@(#)setup.c 8.4 (Berkeley) %G%"; |
fe32782c | 10 | #endif /* not lint */ |
eb93b62a | 11 | |
c7aed003 | 12 | #define DKTYPENAMES |
eb93b62a | 13 | #include <sys/param.h> |
b82067db | 14 | #include <sys/time.h> |
558b3a30 KB |
15 | #include <ufs/ufs/dinode.h> |
16 | #include <ufs/ffs/fs.h> | |
eb93b62a | 17 | #include <sys/stat.h> |
c7aed003 KM |
18 | #include <sys/ioctl.h> |
19 | #include <sys/disklabel.h> | |
20 | #include <sys/file.h> | |
d72e970b KM |
21 | #include <errno.h> |
22 | #include <stdlib.h> | |
23 | #include <string.h> | |
c7aed003 | 24 | #include <ctype.h> |
eb93b62a KM |
25 | #include "fsck.h" |
26 | ||
569ec282 | 27 | struct bufarea asblk; |
adc5a10c | 28 | #define altsblock (*asblk.b_un.b_fs) |
c7aed003 KM |
29 | #define POWEROF2(num) (((num) & ((num) - 1)) == 0) |
30 | ||
d35d4c2b | 31 | struct disklabel *getdisklabel(); |
eb93b62a KM |
32 | |
33 | setup(dev) | |
34 | char *dev; | |
35 | { | |
569ec282 KM |
36 | long cg, size, asked, i, j; |
37 | long bmapsize; | |
d35d4c2b | 38 | struct disklabel *lp; |
53a26cfb | 39 | off_t sizepb; |
eb93b62a | 40 | struct stat statb; |
c7aed003 | 41 | struct fs proto; |
eb93b62a | 42 | |
55f8bbd7 | 43 | havesb = 0; |
6ec186b9 | 44 | fswritefd = -1; |
eb93b62a | 45 | if (stat(dev, &statb) < 0) { |
d72e970b | 46 | printf("Can't stat %s: %s\n", dev, strerror(errno)); |
eb93b62a KM |
47 | return (0); |
48 | } | |
9324cdb0 KM |
49 | if ((statb.st_mode & S_IFMT) != S_IFCHR) { |
50 | pfatal("%s is not a character device", dev); | |
51 | if (reply("CONTINUE") == 0) | |
52 | return (0); | |
53 | } | |
569ec282 | 54 | if ((fsreadfd = open(dev, O_RDONLY)) < 0) { |
d72e970b | 55 | printf("Can't open %s: %s\n", dev, strerror(errno)); |
eb93b62a KM |
56 | return (0); |
57 | } | |
58 | if (preen == 0) | |
59 | printf("** %s", dev); | |
569ec282 KM |
60 | if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) { |
61 | fswritefd = -1; | |
eb93b62a KM |
62 | if (preen) |
63 | pfatal("NO WRITE ACCESS"); | |
64 | printf(" (NO WRITE)"); | |
65 | } | |
66 | if (preen == 0) | |
67 | printf("\n"); | |
569ec282 | 68 | fsmodified = 0; |
eb93b62a | 69 | lfdir = 0; |
eb93b62a | 70 | initbarea(&sblk); |
7beeecfc | 71 | initbarea(&asblk); |
d35d4c2b KM |
72 | sblk.b_un.b_buf = malloc(SBSIZE); |
73 | asblk.b_un.b_buf = malloc(SBSIZE); | |
74 | if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL) | |
adc5a10c | 75 | errexit("cannot allocate space for superblock\n"); |
569ec282 | 76 | if (lp = getdisklabel((char *)NULL, fsreadfd)) |
55f8bbd7 | 77 | dev_bsize = secsize = lp->d_secsize; |
7beeecfc KM |
78 | else |
79 | dev_bsize = secsize = DEV_BSIZE; | |
eb93b62a | 80 | /* |
c7aed003 | 81 | * Read in the superblock, looking for alternates if necessary |
eb93b62a | 82 | */ |
c7aed003 | 83 | if (readsb(1) == 0) { |
569ec282 | 84 | if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0) |
c7aed003 KM |
85 | return(0); |
86 | if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0) | |
87 | return (0); | |
88 | for (cg = 0; cg < proto.fs_ncg; cg++) { | |
89 | bflag = fsbtodb(&proto, cgsblock(&proto, cg)); | |
90 | if (readsb(0) != 0) | |
91 | break; | |
92 | } | |
93 | if (cg >= proto.fs_ncg) { | |
94 | printf("%s %s\n%s %s\n%s %s\n", | |
95 | "SEARCH FOR ALTERNATE SUPER-BLOCK", | |
96 | "FAILED. YOU MUST USE THE", | |
97 | "-b OPTION TO FSCK TO SPECIFY THE", | |
98 | "LOCATION OF AN ALTERNATE", | |
99 | "SUPER-BLOCK TO SUPPLY NEEDED", | |
100 | "INFORMATION; SEE fsck(8)."); | |
101 | return(0); | |
102 | } | |
103 | pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag); | |
104 | } | |
569ec282 KM |
105 | maxfsblock = sblock.fs_size; |
106 | maxino = sblock.fs_ncg * sblock.fs_ipg; | |
d9f38d60 KM |
107 | /* |
108 | * Check and potentially fix certain fields in the super block. | |
109 | */ | |
110 | if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) { | |
111 | pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK"); | |
112 | if (reply("SET TO DEFAULT") == 1) { | |
113 | sblock.fs_optim = FS_OPTTIME; | |
114 | sbdirty(); | |
115 | } | |
116 | } | |
117 | if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) { | |
118 | pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", | |
119 | sblock.fs_minfree); | |
120 | if (reply("SET TO DEFAULT") == 1) { | |
121 | sblock.fs_minfree = 10; | |
122 | sbdirty(); | |
123 | } | |
124 | } | |
5f4c807d KM |
125 | if (sblock.fs_interleave < 1 || |
126 | sblock.fs_interleave > sblock.fs_nsect) { | |
d4af1a46 | 127 | sblock.fs_interleave); |
43171015 | 128 | sblock.fs_interleave = 1; |
d4af1a46 | 129 | sbdirty(); |
7beeecfc KM |
130 | dirty(&asblk); |
131 | } | |
d4af1a46 | 132 | } |
5f4c807d KM |
133 | if (sblock.fs_npsect < sblock.fs_nsect || |
134 | sblock.fs_npsect > sblock.fs_nsect*2) { | |
d4af1a46 | 135 | sblock.fs_npsect); |
43171015 | 136 | sblock.fs_npsect = sblock.fs_nsect; |
d4af1a46 | 137 | sbdirty(); |
7beeecfc KM |
138 | dirty(&asblk); |
139 | } | |
140 | } | |
249863dc | 141 | if (sblock.fs_inodefmt >= FS_44INODEFMT) { |
3f80f884 | 142 | newinofmt = 1; |
249863dc KM |
143 | } else { |
144 | sblock.fs_qbmask = ~sblock.fs_bmask; | |
145 | sblock.fs_qfmask = ~sblock.fs_fmask; | |
3f80f884 | 146 | newinofmt = 0; |
249863dc KM |
147 | } |
148 | /* | |
149 | * Convert to new inode format. | |
150 | */ | |
151 | if (cvtlevel >= 2 && sblock.fs_inodefmt < FS_44INODEFMT) { | |
152 | if (preen) | |
153 | pwarn("CONVERTING TO NEW INODE FORMAT\n"); | |
154 | else if (!reply("CONVERT TO NEW INODE FORMAT")) | |
155 | return(0); | |
156 | doinglevel2++; | |
157 | sblock.fs_inodefmt = FS_44INODEFMT; | |
53a26cfb KM |
158 | sizepb = sblock.fs_bsize; |
159 | sblock.fs_maxfilesize = sblock.fs_bsize * NDADDR - 1; | |
160 | for (i = 0; i < NIADDR; i++) { | |
161 | sizepb *= NINDIR(&sblock); | |
162 | sblock.fs_maxfilesize += sizepb; | |
163 | } | |
249863dc | 164 | sblock.fs_maxsymlinklen = MAXSYMLINKLEN; |
53a26cfb KM |
165 | sblock.fs_qbmask = ~sblock.fs_bmask; |
166 | sblock.fs_qfmask = ~sblock.fs_fmask; | |
249863dc KM |
167 | sbdirty(); |
168 | dirty(&asblk); | |
53a26cfb | 169 | } |
249863dc KM |
170 | /* |
171 | * Convert to new cylinder group format. | |
172 | */ | |
173 | if (cvtlevel >= 1 && sblock.fs_postblformat == FS_42POSTBLFMT) { | |
174 | if (preen) | |
175 | pwarn("CONVERTING TO NEW CYLINDER GROUP FORMAT\n"); | |
176 | else if (!reply("CONVERT TO NEW CYLINDER GROUP FORMAT")) | |
177 | return(0); | |
178 | doinglevel1++; | |
179 | sblock.fs_postblformat = FS_DYNAMICPOSTBLFMT; | |
180 | sblock.fs_nrpos = 8; | |
181 | sblock.fs_postbloff = | |
182 | (char *)(&sblock.fs_opostbl[0][0]) - | |
6c3d0366 | 183 | (char *)(&sblock.fs_firstfield); |
249863dc | 184 | sblock.fs_rotbloff = &sblock.fs_space[0] - |
6c3d0366 | 185 | (u_char *)(&sblock.fs_firstfield); |
249863dc KM |
186 | sblock.fs_cgsize = |
187 | fragroundup(&sblock, CGSIZE(&sblock)); | |
188 | sbdirty(); | |
189 | dirty(&asblk); | |
7beeecfc KM |
190 | } |
191 | if (asblk.b_dirty) { | |
569ec282 | 192 | bcopy((char *)&sblock, (char *)&altsblock, |
d72e970b | 193 | (size_t)sblock.fs_sbsize); |
569ec282 | 194 | flush(fswritefd, &asblk); |
d4af1a46 | 195 | } |
eb93b62a KM |
196 | /* |
197 | * read in the summary info. | |
198 | */ | |
05d069d3 | 199 | asked = 0; |
eb93b62a KM |
200 | for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { |
201 | size = sblock.fs_cssize - i < sblock.fs_bsize ? | |
202 | sblock.fs_cssize - i : sblock.fs_bsize; | |
203 | sblock.fs_csp[j] = (struct csum *)calloc(1, (unsigned)size); | |
569ec282 | 204 | if (bread(fsreadfd, (char *)sblock.fs_csp[j], |
eb93b62a | 205 | fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), |
05d069d3 KM |
206 | size) != 0 && !asked) { |
207 | pfatal("BAD SUMMARY INFORMATION"); | |
208 | if (reply("CONTINUE") == 0) | |
209 | errexit(""); | |
210 | asked++; | |
211 | } | |
eb93b62a KM |
212 | } |
213 | /* | |
214 | * allocate and initialize the necessary maps | |
215 | */ | |
569ec282 KM |
216 | bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(short)); |
217 | blockmap = calloc((unsigned)bmapsize, sizeof (char)); | |
eb93b62a | 218 | if (blockmap == NULL) { |
d72e970b KM |
219 | printf("cannot alloc %u bytes for blockmap\n", |
220 | (unsigned)bmapsize); | |
eb93b62a KM |
221 | goto badsb; |
222 | } | |
569ec282 | 223 | statemap = calloc((unsigned)(maxino + 1), sizeof(char)); |
eb93b62a | 224 | if (statemap == NULL) { |
d72e970b KM |
225 | printf("cannot alloc %u bytes for statemap\n", |
226 | (unsigned)(maxino + 1)); | |
eb93b62a KM |
227 | goto badsb; |
228 | } | |
249863dc KM |
229 | typemap = calloc((unsigned)(maxino + 1), sizeof(char)); |
230 | if (typemap == NULL) { | |
231 | printf("cannot alloc %u bytes for typemap\n", | |
232 | (unsigned)(maxino + 1)); | |
233 | goto badsb; | |
234 | } | |
569ec282 | 235 | lncntp = (short *)calloc((unsigned)(maxino + 1), sizeof(short)); |
eb93b62a | 236 | if (lncntp == NULL) { |
d72e970b KM |
237 | printf("cannot alloc %u bytes for lncntp\n", |
238 | (unsigned)(maxino + 1) * sizeof(short)); | |
eb93b62a KM |
239 | goto badsb; |
240 | } | |
a5880917 | 241 | numdirs = sblock.fs_cstotal.cs_ndir; |
a955a370 | 242 | inplast = 0; |
a5880917 KM |
243 | listmax = numdirs + 10; |
244 | inpsort = (struct inoinfo **)calloc((unsigned)listmax, | |
245 | sizeof(struct inoinfo *)); | |
246 | inphead = (struct inoinfo **)calloc((unsigned)numdirs, | |
247 | sizeof(struct inoinfo *)); | |
248 | if (inpsort == NULL || inphead == NULL) { | |
d72e970b KM |
249 | printf("cannot alloc %u bytes for inphead\n", |
250 | (unsigned)numdirs * sizeof(struct inoinfo *)); | |
a5880917 KM |
251 | goto badsb; |
252 | } | |
adc5a10c | 253 | bufinit(); |
eb93b62a KM |
254 | return (1); |
255 | ||
256 | badsb: | |
257 | ckfini(); | |
258 | return (0); | |
c7aed003 KM |
259 | } |
260 | ||
261 | /* | |
262 | * Read in the super block and its summary info. | |
263 | */ | |
264 | readsb(listerr) | |
265 | int listerr; | |
266 | { | |
55f8bbd7 | 267 | daddr_t super = bflag ? bflag : SBOFF / dev_bsize; |
c7aed003 | 268 | |
569ec282 | 269 | if (bread(fsreadfd, (char *)&sblock, super, (long)SBSIZE) != 0) |
c7aed003 KM |
270 | return (0); |
271 | sblk.b_bno = super; | |
272 | sblk.b_size = SBSIZE; | |
273 | /* | |
274 | * run a few consistency checks of the super block | |
275 | */ | |
276 | if (sblock.fs_magic != FS_MAGIC) | |
277 | { badsb(listerr, "MAGIC NUMBER WRONG"); return (0); } | |
278 | if (sblock.fs_ncg < 1) | |
279 | { badsb(listerr, "NCG OUT OF RANGE"); return (0); } | |
7beeecfc | 280 | if (sblock.fs_cpg < 1) |
c7aed003 KM |
281 | { badsb(listerr, "CPG OUT OF RANGE"); return (0); } |
282 | if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl || | |
283 | (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) | |
284 | { badsb(listerr, "NCYL LESS THAN NCG*CPG"); return (0); } | |
285 | if (sblock.fs_sbsize > SBSIZE) | |
286 | { badsb(listerr, "SIZE PREPOSTEROUSLY LARGE"); return (0); } | |
55f8bbd7 MK |
287 | /* |
288 | * Compute block size that the filesystem is based on, | |
289 | * according to fsbtodb, and adjust superblock block number | |
290 | * so we can tell if this is an alternate later. | |
291 | */ | |
55f8bbd7 MK |
292 | super *= dev_bsize; |
293 | dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); | |
294 | sblk.b_bno = super / dev_bsize; | |
0af8a0aa KM |
295 | if (bflag) { |
296 | havesb = 1; | |
297 | return (1); | |
298 | } | |
c7aed003 KM |
299 | /* |
300 | * Set all possible fields that could differ, then do check | |
301 | * of whole super block against an alternate super block. | |
302 | * When an alternate super-block is specified this check is skipped. | |
303 | */ | |
7beeecfc | 304 | getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), sblock.fs_sbsize); |
d35d4c2b | 305 | if (asblk.b_errs) |
7beeecfc | 306 | return (0); |
c7aed003 KM |
307 | altsblock.fs_time = sblock.fs_time; |
308 | altsblock.fs_cstotal = sblock.fs_cstotal; | |
309 | altsblock.fs_cgrotor = sblock.fs_cgrotor; | |
310 | altsblock.fs_fmod = sblock.fs_fmod; | |
311 | altsblock.fs_clean = sblock.fs_clean; | |
312 | altsblock.fs_ronly = sblock.fs_ronly; | |
313 | altsblock.fs_flags = sblock.fs_flags; | |
314 | altsblock.fs_maxcontig = sblock.fs_maxcontig; | |
315 | altsblock.fs_minfree = sblock.fs_minfree; | |
316 | altsblock.fs_optim = sblock.fs_optim; | |
317 | altsblock.fs_rotdelay = sblock.fs_rotdelay; | |
318 | altsblock.fs_maxbpg = sblock.fs_maxbpg; | |
319 | bcopy((char *)sblock.fs_csp, (char *)altsblock.fs_csp, | |
320 | sizeof sblock.fs_csp); | |
321 | bcopy((char *)sblock.fs_fsmnt, (char *)altsblock.fs_fsmnt, | |
322 | sizeof sblock.fs_fsmnt); | |
cfbff64d MK |
323 | bcopy((char *)sblock.fs_sparecon, (char *)altsblock.fs_sparecon, |
324 | sizeof sblock.fs_sparecon); | |
7beeecfc KM |
325 | /* |
326 | * The following should not have to be copied. | |
327 | */ | |
328 | altsblock.fs_fsbtodb = sblock.fs_fsbtodb; | |
329 | altsblock.fs_interleave = sblock.fs_interleave; | |
330 | altsblock.fs_npsect = sblock.fs_npsect; | |
331 | altsblock.fs_nrpos = sblock.fs_nrpos; | |
6cea9ab1 | 332 | altsblock.fs_state = sblock.fs_state; |
ad132be1 KM |
333 | altsblock.fs_qbmask = sblock.fs_qbmask; |
334 | altsblock.fs_qfmask = sblock.fs_qfmask; | |
335 | altsblock.fs_state = sblock.fs_state; | |
336 | altsblock.fs_maxfilesize = sblock.fs_maxfilesize; | |
cfbff64d MK |
337 | if (bcmp((char *)&sblock, (char *)&altsblock, (int)sblock.fs_sbsize)) { |
338 | badsb(listerr, | |
339 | "VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE"); | |
340 | return (0); | |
341 | } | |
55f8bbd7 | 342 | havesb = 1; |
c7aed003 | 343 | return (1); |
eb93b62a KM |
344 | } |
345 | ||
c7aed003 KM |
346 | badsb(listerr, s) |
347 | int listerr; | |
eb93b62a KM |
348 | char *s; |
349 | { | |
350 | ||
c7aed003 KM |
351 | if (!listerr) |
352 | return; | |
eb93b62a | 353 | if (preen) |
8b45fecd | 354 | printf("%s: ", cdevname); |
c7aed003 KM |
355 | pfatal("BAD SUPER BLOCK: %s\n", s); |
356 | } | |
357 | ||
358 | /* | |
359 | * Calculate a prototype superblock based on information in the disk label. | |
360 | * When done the cgsblock macro can be calculated and the fs_ncg field | |
361 | * can be used. Do NOT attempt to use other macros without verifying that | |
362 | * their needed information is available! | |
363 | */ | |
364 | calcsb(dev, devfd, fs) | |
365 | char *dev; | |
366 | int devfd; | |
367 | register struct fs *fs; | |
368 | { | |
369 | register struct disklabel *lp; | |
370 | register struct partition *pp; | |
371 | register char *cp; | |
c7aed003 KM |
372 | int i; |
373 | ||
374 | cp = index(dev, '\0') - 1; | |
375 | if (cp == (char *)-1 || (*cp < 'a' || *cp > 'h') && !isdigit(*cp)) { | |
376 | pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev); | |
377 | return (0); | |
378 | } | |
379 | lp = getdisklabel(dev, devfd); | |
380 | if (isdigit(*cp)) | |
381 | pp = &lp->d_partitions[0]; | |
382 | else | |
383 | pp = &lp->d_partitions[*cp - 'a']; | |
384 | if (pp->p_fstype != FS_BSDFFS) { | |
55f8bbd7 | 385 | pfatal("%s: NOT LABELED AS A BSD FILE SYSTEM (%s)\n", |
c7aed003 KM |
386 | dev, pp->p_fstype < FSMAXTYPES ? |
387 | fstypenames[pp->p_fstype] : "unknown"); | |
388 | return (0); | |
389 | } | |
569ec282 | 390 | bzero((char *)fs, sizeof(struct fs)); |
c7aed003 KM |
391 | fs->fs_fsize = pp->p_fsize; |
392 | fs->fs_frag = pp->p_frag; | |
393 | fs->fs_cpg = pp->p_cpg; | |
394 | fs->fs_size = pp->p_size; | |
395 | fs->fs_ntrak = lp->d_ntracks; | |
396 | fs->fs_nsect = lp->d_nsectors; | |
397 | fs->fs_spc = lp->d_secpercyl; | |
398 | fs->fs_nspf = fs->fs_fsize / lp->d_secsize; | |
399 | fs->fs_sblkno = roundup( | |
400 | howmany(lp->d_bbsize + lp->d_sbsize, fs->fs_fsize), | |
401 | fs->fs_frag); | |
402 | fs->fs_cgmask = 0xffffffff; | |
403 | for (i = fs->fs_ntrak; i > 1; i >>= 1) | |
404 | fs->fs_cgmask <<= 1; | |
405 | if (!POWEROF2(fs->fs_ntrak)) | |
406 | fs->fs_cgmask <<= 1; | |
407 | fs->fs_cgoffset = roundup( | |
408 | howmany(fs->fs_nsect, NSPF(fs)), fs->fs_frag); | |
409 | fs->fs_fpg = (fs->fs_cpg * fs->fs_spc) / NSPF(fs); | |
410 | fs->fs_ncg = howmany(fs->fs_size / fs->fs_spc, fs->fs_cpg); | |
411 | for (fs->fs_fsbtodb = 0, i = NSPF(fs); i > 1; i >>= 1) | |
412 | fs->fs_fsbtodb++; | |
55f8bbd7 | 413 | dev_bsize = lp->d_secsize; |
c7aed003 KM |
414 | return (1); |
415 | } | |
416 | ||
c7aed003 KM |
417 | struct disklabel * |
418 | getdisklabel(s, fd) | |
419 | char *s; | |
420 | int fd; | |
421 | { | |
422 | static struct disklabel lab; | |
423 | ||
424 | if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) { | |
919c85da MK |
425 | if (s == NULL) |
426 | return ((struct disklabel *)NULL); | |
d72e970b | 427 | pwarn("ioctl (GCINFO): %s\n", strerror(errno)); |
1a85539e | 428 | errexit("%s: can't read disk label\n", s); |
c7aed003 KM |
429 | } |
430 | return (&lab); | |
431 | } |