Commit | Line | Data |
---|---|---|
76797561 DF |
1 | /* |
2 | * Copyright (c) 1980 Regents of the University of California. | |
3 | * All rights reserved. The Berkeley software License Agreement | |
4 | * specifies the terms and conditions for redistribution. | |
5 | */ | |
6 | ||
eb93b62a | 7 | #ifndef lint |
6eb81197 | 8 | static char sccsid[] = "@(#)setup.c 5.7 (Berkeley) %G%"; |
76797561 | 9 | #endif not lint |
eb93b62a | 10 | |
c7aed003 | 11 | #define DKTYPENAMES |
eb93b62a KM |
12 | #include <sys/param.h> |
13 | #include <sys/inode.h> | |
14 | #include <sys/fs.h> | |
15 | #include <sys/stat.h> | |
c7aed003 KM |
16 | #include <sys/ioctl.h> |
17 | #include <sys/disklabel.h> | |
18 | #include <sys/file.h> | |
19 | #include <ctype.h> | |
eb93b62a KM |
20 | #include "fsck.h" |
21 | ||
c7aed003 KM |
22 | #define POWEROF2(num) (((num) & ((num) - 1)) == 0) |
23 | ||
eb93b62a | 24 | char *calloc(); |
c7aed003 | 25 | char *index(); |
eb93b62a KM |
26 | |
27 | setup(dev) | |
28 | char *dev; | |
29 | { | |
30 | dev_t rootdev; | |
c7aed003 | 31 | long cg, ncg, size, i, j; |
eb93b62a | 32 | struct stat statb; |
c7aed003 | 33 | struct fs proto; |
eb93b62a KM |
34 | |
35 | if (stat("/", &statb) < 0) | |
36 | errexit("Can't stat root\n"); | |
37 | rootdev = statb.st_dev; | |
38 | if (stat(dev, &statb) < 0) { | |
7718c0e6 | 39 | printf("Can't stat %s\n", dev); |
eb93b62a KM |
40 | return (0); |
41 | } | |
42 | rawflg = 0; | |
43 | if ((statb.st_mode & S_IFMT) == S_IFBLK) | |
44 | ; | |
45 | else if ((statb.st_mode & S_IFMT) == S_IFCHR) | |
46 | rawflg++; | |
47 | else { | |
48 | if (reply("file is not a block or character device; OK") == 0) | |
49 | return (0); | |
50 | } | |
51 | if (rootdev == statb.st_rdev) | |
52 | hotroot++; | |
c7aed003 | 53 | if ((dfile.rfdes = open(dev, O_RDONLY)) < 0) { |
7718c0e6 | 54 | printf("Can't open %s\n", dev); |
eb93b62a KM |
55 | return (0); |
56 | } | |
57 | if (preen == 0) | |
58 | printf("** %s", dev); | |
c7aed003 | 59 | if (nflag || (dfile.wfdes = open(dev, O_WRONLY)) < 0) { |
eb93b62a KM |
60 | dfile.wfdes = -1; |
61 | if (preen) | |
62 | pfatal("NO WRITE ACCESS"); | |
63 | printf(" (NO WRITE)"); | |
64 | } | |
65 | if (preen == 0) | |
66 | printf("\n"); | |
eb93b62a | 67 | dfile.mod = 0; |
eb93b62a | 68 | lfdir = 0; |
eb93b62a KM |
69 | initbarea(&sblk); |
70 | initbarea(&fileblk); | |
71 | initbarea(&inoblk); | |
72 | initbarea(&cgblk); | |
eb93b62a | 73 | /* |
c7aed003 | 74 | * Read in the superblock, looking for alternates if necessary |
eb93b62a | 75 | */ |
c7aed003 KM |
76 | if (readsb(1) == 0) { |
77 | if (bflag || calcsb(dev, dfile.rfdes, &proto) == 0 || preen) | |
78 | return(0); | |
79 | if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0) | |
80 | return (0); | |
81 | for (cg = 0; cg < proto.fs_ncg; cg++) { | |
82 | bflag = fsbtodb(&proto, cgsblock(&proto, cg)); | |
83 | if (readsb(0) != 0) | |
84 | break; | |
85 | } | |
86 | if (cg >= proto.fs_ncg) { | |
87 | printf("%s %s\n%s %s\n%s %s\n", | |
88 | "SEARCH FOR ALTERNATE SUPER-BLOCK", | |
89 | "FAILED. YOU MUST USE THE", | |
90 | "-b OPTION TO FSCK TO SPECIFY THE", | |
91 | "LOCATION OF AN ALTERNATE", | |
92 | "SUPER-BLOCK TO SUPPLY NEEDED", | |
93 | "INFORMATION; SEE fsck(8)."); | |
94 | return(0); | |
95 | } | |
96 | pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag); | |
97 | } | |
98 | fmax = sblock.fs_size; | |
99 | imax = sblock.fs_ncg * sblock.fs_ipg; | |
d9f38d60 KM |
100 | /* |
101 | * Check and potentially fix certain fields in the super block. | |
102 | */ | |
103 | if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) { | |
104 | pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK"); | |
105 | if (reply("SET TO DEFAULT") == 1) { | |
106 | sblock.fs_optim = FS_OPTTIME; | |
107 | sbdirty(); | |
108 | } | |
109 | } | |
110 | if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) { | |
111 | pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", | |
112 | sblock.fs_minfree); | |
113 | if (reply("SET TO DEFAULT") == 1) { | |
114 | sblock.fs_minfree = 10; | |
115 | sbdirty(); | |
116 | } | |
117 | } | |
d4af1a46 KM |
118 | if (sblock.fs_interleave < 1) { |
119 | pfatal("IMPOSSIBLE INTERLEAVE=%d IN SUPERBLOCK", | |
120 | sblock.fs_interleave); | |
121 | if (reply("SET TO DEFAULT") == 1) { | |
122 | sblock.fs_interleave = 1; | |
123 | sbdirty(); | |
124 | } | |
125 | } | |
126 | if (sblock.fs_npsect < sblock.fs_nsect) { | |
127 | pfatal("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK", | |
128 | sblock.fs_npsect); | |
129 | if (reply("SET TO DEFAULT") == 1) { | |
130 | sblock.fs_npsect = sblock.fs_nsect; | |
131 | sbdirty(); | |
132 | } | |
133 | } | |
eb93b62a KM |
134 | /* |
135 | * read in the summary info. | |
136 | */ | |
137 | for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { | |
138 | size = sblock.fs_cssize - i < sblock.fs_bsize ? | |
139 | sblock.fs_cssize - i : sblock.fs_bsize; | |
140 | sblock.fs_csp[j] = (struct csum *)calloc(1, (unsigned)size); | |
141 | if (bread(&dfile, (char *)sblock.fs_csp[j], | |
142 | fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), | |
49505034 | 143 | size) != 0) |
eb93b62a KM |
144 | return (0); |
145 | } | |
146 | /* | |
147 | * allocate and initialize the necessary maps | |
148 | */ | |
149 | bmapsz = roundup(howmany(fmax, NBBY), sizeof(short)); | |
150 | blockmap = calloc((unsigned)bmapsz, sizeof (char)); | |
151 | if (blockmap == NULL) { | |
152 | printf("cannot alloc %d bytes for blockmap\n", bmapsz); | |
153 | goto badsb; | |
154 | } | |
eb93b62a KM |
155 | statemap = calloc((unsigned)(imax + 1), sizeof(char)); |
156 | if (statemap == NULL) { | |
157 | printf("cannot alloc %d bytes for statemap\n", imax + 1); | |
158 | goto badsb; | |
159 | } | |
160 | lncntp = (short *)calloc((unsigned)(imax + 1), sizeof(short)); | |
161 | if (lncntp == NULL) { | |
162 | printf("cannot alloc %d bytes for lncntp\n", | |
163 | (imax + 1) * sizeof(short)); | |
164 | goto badsb; | |
165 | } | |
eb93b62a KM |
166 | |
167 | return (1); | |
168 | ||
169 | badsb: | |
170 | ckfini(); | |
171 | return (0); | |
c7aed003 KM |
172 | } |
173 | ||
174 | /* | |
175 | * Read in the super block and its summary info. | |
176 | */ | |
177 | readsb(listerr) | |
178 | int listerr; | |
179 | { | |
180 | BUFAREA asblk; | |
181 | # define altsblock asblk.b_un.b_fs | |
182 | daddr_t super = bflag ? bflag : SBLOCK; | |
183 | ||
184 | initbarea(&asblk); | |
6eb81197 | 185 | dev_bsize = DEV_BSIZE; |
c7aed003 KM |
186 | if (bread(&dfile, (char *)&sblock, super, (long)SBSIZE) != 0) |
187 | return (0); | |
188 | sblk.b_bno = super; | |
189 | sblk.b_size = SBSIZE; | |
190 | /* | |
191 | * run a few consistency checks of the super block | |
192 | */ | |
193 | if (sblock.fs_magic != FS_MAGIC) | |
194 | { badsb(listerr, "MAGIC NUMBER WRONG"); return (0); } | |
195 | if (sblock.fs_ncg < 1) | |
196 | { badsb(listerr, "NCG OUT OF RANGE"); return (0); } | |
197 | if (sblock.fs_cpg < 1 || sblock.fs_cpg > MAXCPG) | |
198 | { badsb(listerr, "CPG OUT OF RANGE"); return (0); } | |
199 | if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl || | |
200 | (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) | |
201 | { badsb(listerr, "NCYL LESS THAN NCG*CPG"); return (0); } | |
202 | if (sblock.fs_sbsize > SBSIZE) | |
203 | { badsb(listerr, "SIZE PREPOSTEROUSLY LARGE"); return (0); } | |
204 | /* | |
205 | * Set all possible fields that could differ, then do check | |
206 | * of whole super block against an alternate super block. | |
207 | * When an alternate super-block is specified this check is skipped. | |
208 | */ | |
6eb81197 KM |
209 | dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); |
210 | sblk.b_bno = sblk.b_bno * DEV_BSIZE / dev_bsize; | |
c7aed003 KM |
211 | if (bflag) |
212 | return (1); | |
213 | getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), sblock.fs_sbsize); | |
214 | if (asblk.b_errs != NULL) | |
215 | return (0); | |
216 | altsblock.fs_link = sblock.fs_link; | |
217 | altsblock.fs_rlink = sblock.fs_rlink; | |
218 | altsblock.fs_time = sblock.fs_time; | |
219 | altsblock.fs_cstotal = sblock.fs_cstotal; | |
220 | altsblock.fs_cgrotor = sblock.fs_cgrotor; | |
221 | altsblock.fs_fmod = sblock.fs_fmod; | |
222 | altsblock.fs_clean = sblock.fs_clean; | |
223 | altsblock.fs_ronly = sblock.fs_ronly; | |
224 | altsblock.fs_flags = sblock.fs_flags; | |
225 | altsblock.fs_maxcontig = sblock.fs_maxcontig; | |
226 | altsblock.fs_minfree = sblock.fs_minfree; | |
227 | altsblock.fs_optim = sblock.fs_optim; | |
228 | altsblock.fs_rotdelay = sblock.fs_rotdelay; | |
229 | altsblock.fs_maxbpg = sblock.fs_maxbpg; | |
938edf28 KM |
230 | altsblock.fs_npsect = sblock.fs_npsect; |
231 | altsblock.fs_interleave = sblock.fs_interleave; | |
c7aed003 KM |
232 | bcopy((char *)sblock.fs_csp, (char *)altsblock.fs_csp, |
233 | sizeof sblock.fs_csp); | |
234 | bcopy((char *)sblock.fs_fsmnt, (char *)altsblock.fs_fsmnt, | |
235 | sizeof sblock.fs_fsmnt); | |
236 | if (bcmp((char *)&sblock, (char *)&altsblock, (int)sblock.fs_sbsize)) | |
237 | { badsb(listerr, "TRASHED VALUES IN SUPER BLOCK"); return (0); } | |
238 | return (1); | |
eb93b62a KM |
239 | # undef altsblock |
240 | } | |
241 | ||
c7aed003 KM |
242 | badsb(listerr, s) |
243 | int listerr; | |
eb93b62a KM |
244 | char *s; |
245 | { | |
246 | ||
c7aed003 KM |
247 | if (!listerr) |
248 | return; | |
eb93b62a KM |
249 | if (preen) |
250 | printf("%s: ", devname); | |
c7aed003 KM |
251 | pfatal("BAD SUPER BLOCK: %s\n", s); |
252 | } | |
253 | ||
254 | /* | |
255 | * Calculate a prototype superblock based on information in the disk label. | |
256 | * When done the cgsblock macro can be calculated and the fs_ncg field | |
257 | * can be used. Do NOT attempt to use other macros without verifying that | |
258 | * their needed information is available! | |
259 | */ | |
260 | calcsb(dev, devfd, fs) | |
261 | char *dev; | |
262 | int devfd; | |
263 | register struct fs *fs; | |
264 | { | |
265 | register struct disklabel *lp; | |
266 | register struct partition *pp; | |
267 | register char *cp; | |
268 | struct disklabel *getdisklabel(); | |
269 | int i; | |
270 | ||
271 | cp = index(dev, '\0') - 1; | |
272 | if (cp == (char *)-1 || (*cp < 'a' || *cp > 'h') && !isdigit(*cp)) { | |
273 | pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev); | |
274 | return (0); | |
275 | } | |
276 | lp = getdisklabel(dev, devfd); | |
277 | if (isdigit(*cp)) | |
278 | pp = &lp->d_partitions[0]; | |
279 | else | |
280 | pp = &lp->d_partitions[*cp - 'a']; | |
281 | if (pp->p_fstype != FS_BSDFFS) { | |
282 | pfatal("%s: NOT FORMATTED AS A BSD FILE SYSTEM (%s)\n", | |
283 | dev, pp->p_fstype < FSMAXTYPES ? | |
284 | fstypenames[pp->p_fstype] : "unknown"); | |
285 | return (0); | |
286 | } | |
287 | bzero(fs, sizeof(struct fs)); | |
288 | fs->fs_fsize = pp->p_fsize; | |
289 | fs->fs_frag = pp->p_frag; | |
290 | fs->fs_cpg = pp->p_cpg; | |
291 | fs->fs_size = pp->p_size; | |
292 | fs->fs_ntrak = lp->d_ntracks; | |
293 | fs->fs_nsect = lp->d_nsectors; | |
294 | fs->fs_spc = lp->d_secpercyl; | |
295 | fs->fs_nspf = fs->fs_fsize / lp->d_secsize; | |
296 | fs->fs_sblkno = roundup( | |
297 | howmany(lp->d_bbsize + lp->d_sbsize, fs->fs_fsize), | |
298 | fs->fs_frag); | |
299 | fs->fs_cgmask = 0xffffffff; | |
300 | for (i = fs->fs_ntrak; i > 1; i >>= 1) | |
301 | fs->fs_cgmask <<= 1; | |
302 | if (!POWEROF2(fs->fs_ntrak)) | |
303 | fs->fs_cgmask <<= 1; | |
304 | fs->fs_cgoffset = roundup( | |
305 | howmany(fs->fs_nsect, NSPF(fs)), fs->fs_frag); | |
306 | fs->fs_fpg = (fs->fs_cpg * fs->fs_spc) / NSPF(fs); | |
307 | fs->fs_ncg = howmany(fs->fs_size / fs->fs_spc, fs->fs_cpg); | |
308 | for (fs->fs_fsbtodb = 0, i = NSPF(fs); i > 1; i >>= 1) | |
309 | fs->fs_fsbtodb++; | |
310 | return (1); | |
311 | } | |
312 | ||
313 | #ifdef byioctl | |
314 | struct disklabel * | |
315 | getdisklabel(s, fd) | |
316 | char *s; | |
317 | int fd; | |
318 | { | |
319 | static struct disklabel lab; | |
320 | ||
321 | if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) { | |
322 | perror("ioctl (GDINFO)"); | |
323 | fatal("%s: can't read disk label", s); | |
324 | } | |
325 | return (&lab); | |
326 | } | |
327 | #else byioctl | |
328 | char specname[64]; | |
329 | char boot[BBSIZE]; | |
330 | ||
331 | struct disklabel * | |
332 | getdisklabel(s, fd) | |
333 | char *s; | |
334 | int fd; | |
335 | { | |
336 | char *cp; | |
337 | u_long magic = htonl(DISKMAGIC); | |
338 | register struct disklabel *lp; | |
339 | int cfd; | |
340 | ||
341 | /* | |
342 | * Make name for 'c' partition. | |
343 | */ | |
344 | strcpy(specname, s); | |
345 | cp = specname + strlen(specname) - 1; | |
346 | if (!isdigit(*cp)) | |
347 | *cp = 'c'; | |
348 | cfd = open(specname, O_RDONLY); | |
349 | if (cfd < 0) { | |
350 | perror(specname); | |
351 | exit(2); | |
352 | } | |
353 | ||
354 | if (read(cfd, boot, BBSIZE) < BBSIZE) { | |
355 | perror(specname); | |
356 | exit(2); | |
357 | } | |
358 | close(cfd); | |
359 | for (lp = (struct disklabel *)(boot + LABELOFFSET); | |
360 | lp <= (struct disklabel *)(boot + BBSIZE - | |
361 | sizeof(struct disklabel)); | |
362 | lp = (struct disklabel *)((char *)lp + 128)) | |
363 | if (lp->d_magic == magic && lp->d_magic2 == magic) | |
364 | break; | |
365 | if (lp > (struct disklabel *)(boot + BBSIZE - | |
366 | sizeof(struct disklabel)) || | |
367 | lp->d_magic != magic || lp->d_magic2 != magic || | |
368 | dkcksum(lp) != 0) { | |
369 | printf("Bad pack magic number %s\n", | |
370 | "(label is damaged, or pack is unlabeled)"); | |
371 | exit(1); | |
372 | } | |
373 | #if ENDIAN != BIG | |
374 | swablabel(lp); | |
375 | #endif | |
376 | return (lp); | |
eb93b62a | 377 | } |
c7aed003 | 378 | #endif byioctl |