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 | ||
5d9906c0 | 7 | #ifndef lint |
55f8bbd7 | 8 | static char sccsid[] = "@(#)utilities.c 5.10 (Berkeley) %G%"; |
76797561 | 9 | #endif not lint |
5d9906c0 KM |
10 | |
11 | #include <stdio.h> | |
12 | #include <ctype.h> | |
13 | #include <sys/param.h> | |
14 | #include <sys/inode.h> | |
15 | #include <sys/fs.h> | |
3ad2f081 | 16 | #include <sys/dir.h> |
5d9906c0 KM |
17 | #include "fsck.h" |
18 | ||
19 | long lseek(); | |
20 | ||
21 | ftypeok(dp) | |
22 | DINODE *dp; | |
23 | { | |
24 | switch (dp->di_mode & IFMT) { | |
25 | ||
26 | case IFDIR: | |
27 | case IFREG: | |
28 | case IFBLK: | |
29 | case IFCHR: | |
30 | case IFLNK: | |
31 | case IFSOCK: | |
32 | return (1); | |
33 | ||
34 | default: | |
35 | if (debug) | |
36 | printf("bad file type 0%o\n", dp->di_mode); | |
37 | return (0); | |
38 | } | |
39 | } | |
40 | ||
41 | reply(s) | |
42 | char *s; | |
43 | { | |
44 | char line[80]; | |
919c85da | 45 | int cont = (strcmp(s, "CONTINUE") == 0); |
5d9906c0 KM |
46 | |
47 | if (preen) | |
48 | pfatal("INTERNAL ERROR: GOT TO reply()"); | |
5d9906c0 | 49 | printf("\n%s? ", s); |
919c85da | 50 | if (!cont && (nflag || dfile.wfdes < 0)) { |
5d9906c0 KM |
51 | printf(" no\n\n"); |
52 | return (0); | |
53 | } | |
919c85da | 54 | if (yflag || (cont && nflag)) { |
5d9906c0 KM |
55 | printf(" yes\n\n"); |
56 | return (1); | |
57 | } | |
58 | if (getline(stdin, line, sizeof(line)) == EOF) | |
59 | errexit("\n"); | |
60 | printf("\n"); | |
61 | if (line[0] == 'y' || line[0] == 'Y') | |
62 | return (1); | |
63 | else | |
64 | return (0); | |
65 | } | |
66 | ||
67 | getline(fp, loc, maxlen) | |
68 | FILE *fp; | |
69 | char *loc; | |
70 | { | |
71 | register n; | |
72 | register char *p, *lastloc; | |
73 | ||
74 | p = loc; | |
75 | lastloc = &p[maxlen-1]; | |
76 | while ((n = getc(fp)) != '\n') { | |
77 | if (n == EOF) | |
78 | return (EOF); | |
79 | if (!isspace(n) && p < lastloc) | |
80 | *p++ = n; | |
81 | } | |
82 | *p = 0; | |
83 | return (p - loc); | |
84 | } | |
85 | ||
86 | BUFAREA * | |
87 | getblk(bp, blk, size) | |
88 | register BUFAREA *bp; | |
89 | daddr_t blk; | |
90 | long size; | |
91 | { | |
92 | register struct filecntl *fcp; | |
93 | daddr_t dblk; | |
94 | ||
95 | fcp = &dfile; | |
96 | dblk = fsbtodb(&sblock, blk); | |
97 | if (bp->b_bno == dblk) | |
98 | return (bp); | |
99 | flush(fcp, bp); | |
49505034 KM |
100 | bp->b_errs = bread(fcp, bp->b_un.b_buf, dblk, size); |
101 | bp->b_bno = dblk; | |
102 | bp->b_size = size; | |
103 | return (bp); | |
5d9906c0 KM |
104 | } |
105 | ||
106 | flush(fcp, bp) | |
107 | struct filecntl *fcp; | |
108 | register BUFAREA *bp; | |
109 | { | |
7718c0e6 | 110 | register int i, j; |
5d9906c0 | 111 | |
7718c0e6 KM |
112 | if (!bp->b_dirty) |
113 | return; | |
49505034 | 114 | if (bp->b_errs != 0) |
919c85da MK |
115 | pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n", |
116 | (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", | |
117 | bp->b_bno); | |
5d9906c0 | 118 | bp->b_dirty = 0; |
49505034 | 119 | bp->b_errs = 0; |
cee9cbac | 120 | bwrite(fcp, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); |
7718c0e6 KM |
121 | if (bp != &sblk) |
122 | return; | |
123 | for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { | |
cee9cbac | 124 | bwrite(&dfile, (char *)sblock.fs_csp[j], |
7718c0e6 KM |
125 | fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), |
126 | sblock.fs_cssize - i < sblock.fs_bsize ? | |
127 | sblock.fs_cssize - i : sblock.fs_bsize); | |
128 | } | |
5d9906c0 KM |
129 | } |
130 | ||
131 | rwerr(s, blk) | |
132 | char *s; | |
133 | daddr_t blk; | |
134 | { | |
135 | ||
136 | if (preen == 0) | |
137 | printf("\n"); | |
138 | pfatal("CANNOT %s: BLK %ld", s, blk); | |
139 | if (reply("CONTINUE") == 0) | |
140 | errexit("Program terminated\n"); | |
141 | } | |
142 | ||
143 | ckfini() | |
144 | { | |
145 | ||
146 | flush(&dfile, &fileblk); | |
147 | flush(&dfile, &sblk); | |
55f8bbd7 | 148 | if (havesb && sblk.b_bno != SBOFF / dev_bsize && |
6eb81197 | 149 | !preen && reply("UPDATE STANDARD SUPERBLOCK")) { |
bc5c7748 | 150 | sblk.b_bno = SBOFF / dev_bsize; |
5d9906c0 KM |
151 | sbdirty(); |
152 | flush(&dfile, &sblk); | |
153 | } | |
154 | flush(&dfile, &inoblk); | |
111a311a | 155 | flush(&dfile, &cgblk); |
5d9906c0 KM |
156 | (void)close(dfile.rfdes); |
157 | (void)close(dfile.wfdes); | |
158 | } | |
159 | ||
160 | bread(fcp, buf, blk, size) | |
161 | register struct filecntl *fcp; | |
162 | char *buf; | |
163 | daddr_t blk; | |
164 | long size; | |
165 | { | |
49505034 KM |
166 | char *cp; |
167 | int i, errs; | |
168 | ||
a037e18f | 169 | if (lseek(fcp->rfdes, blk * dev_bsize, 0) < 0) |
5d9906c0 KM |
170 | rwerr("SEEK", blk); |
171 | else if (read(fcp->rfdes, buf, (int)size) == size) | |
49505034 | 172 | return (0); |
5d9906c0 | 173 | rwerr("READ", blk); |
a037e18f | 174 | if (lseek(fcp->rfdes, blk * dev_bsize, 0) < 0) |
49505034 KM |
175 | rwerr("SEEK", blk); |
176 | errs = 0; | |
48a56825 | 177 | bzero(buf, size); |
919c85da MK |
178 | printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); |
179 | for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { | |
180 | if (read(fcp->rfdes, cp, secsize) < 0) { | |
181 | lseek(fcp->rfdes, blk * dev_bsize + i + secsize, 0); | |
55f8bbd7 | 182 | if (secsize != dev_bsize && dev_bsize != 1) |
919c85da MK |
183 | printf(" %d (%d),", |
184 | (blk * dev_bsize + i) / secsize, | |
185 | blk + i / dev_bsize); | |
186 | else | |
187 | printf(" %d,", blk + i / dev_bsize); | |
49505034 KM |
188 | errs++; |
189 | } | |
190 | } | |
cee9cbac | 191 | printf("\n"); |
49505034 | 192 | return (errs); |
5d9906c0 KM |
193 | } |
194 | ||
195 | bwrite(fcp, buf, blk, size) | |
196 | register struct filecntl *fcp; | |
197 | char *buf; | |
198 | daddr_t blk; | |
199 | long size; | |
200 | { | |
cee9cbac KM |
201 | int i; |
202 | char *cp; | |
5d9906c0 KM |
203 | |
204 | if (fcp->wfdes < 0) | |
cee9cbac | 205 | return; |
a037e18f | 206 | if (lseek(fcp->wfdes, blk * dev_bsize, 0) < 0) |
5d9906c0 KM |
207 | rwerr("SEEK", blk); |
208 | else if (write(fcp->wfdes, buf, (int)size) == size) { | |
209 | fcp->mod = 1; | |
cee9cbac | 210 | return; |
5d9906c0 KM |
211 | } |
212 | rwerr("WRITE", blk); | |
a037e18f | 213 | if (lseek(fcp->wfdes, blk * dev_bsize, 0) < 0) |
cee9cbac | 214 | rwerr("SEEK", blk); |
919c85da | 215 | printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); |
6eb81197 KM |
216 | for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) |
217 | if (write(fcp->wfdes, cp, dev_bsize) < 0) { | |
a037e18f | 218 | lseek(fcp->rfdes, blk * dev_bsize + i + dev_bsize, 0); |
6eb81197 | 219 | printf(" %d,", blk + i / dev_bsize); |
6d8dba44 | 220 | } |
cee9cbac KM |
221 | printf("\n"); |
222 | return; | |
5d9906c0 KM |
223 | } |
224 | ||
3e2a23ca KM |
225 | /* |
226 | * allocate a data block with the specified number of fragments | |
227 | */ | |
228 | allocblk(frags) | |
229 | int frags; | |
230 | { | |
231 | register int i, j, k; | |
232 | ||
233 | if (frags <= 0 || frags > sblock.fs_frag) | |
234 | return (0); | |
235 | for (i = 0; i < fmax - sblock.fs_frag; i += sblock.fs_frag) { | |
236 | for (j = 0; j <= sblock.fs_frag - frags; j++) { | |
237 | if (getbmap(i + j)) | |
238 | continue; | |
239 | for (k = 1; k < frags; k++) | |
240 | if (getbmap(i + j + k)) | |
241 | break; | |
242 | if (k < frags) { | |
243 | j += k; | |
244 | continue; | |
245 | } | |
246 | for (k = 0; k < frags; k++) | |
247 | setbmap(i + j + k); | |
248 | n_blks += frags; | |
249 | return (i + j); | |
250 | } | |
251 | } | |
252 | return (0); | |
253 | } | |
254 | ||
255 | /* | |
256 | * Free a previously allocated block | |
257 | */ | |
258 | freeblk(blkno, frags) | |
259 | daddr_t blkno; | |
260 | int frags; | |
261 | { | |
262 | struct inodesc idesc; | |
263 | ||
264 | idesc.id_blkno = blkno; | |
265 | idesc.id_numfrags = frags; | |
266 | pass4check(&idesc); | |
267 | } | |
268 | ||
3ad2f081 KM |
269 | /* |
270 | * Find a pathname | |
271 | */ | |
272 | getpathname(namebuf, curdir, ino) | |
273 | char *namebuf; | |
274 | ino_t curdir, ino; | |
275 | { | |
276 | int len; | |
277 | register char *cp; | |
278 | struct inodesc idesc; | |
279 | extern int findname(); | |
280 | ||
281 | if (statemap[ino] != DSTATE && statemap[ino] != DFOUND) { | |
282 | strcpy(namebuf, "?"); | |
283 | return; | |
284 | } | |
285 | bzero(&idesc, sizeof(struct inodesc)); | |
286 | idesc.id_type = DATA; | |
287 | cp = &namebuf[BUFSIZ - 1]; | |
315f1422 | 288 | *cp = '\0'; |
3ad2f081 KM |
289 | if (curdir != ino) { |
290 | idesc.id_parent = curdir; | |
291 | goto namelookup; | |
292 | } | |
293 | while (ino != ROOTINO) { | |
294 | idesc.id_number = ino; | |
295 | idesc.id_func = findino; | |
296 | idesc.id_name = ".."; | |
315f1422 | 297 | if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) |
3ad2f081 KM |
298 | break; |
299 | namelookup: | |
300 | idesc.id_number = idesc.id_parent; | |
301 | idesc.id_parent = ino; | |
302 | idesc.id_func = findname; | |
303 | idesc.id_name = namebuf; | |
315f1422 | 304 | if ((ckinode(ginode(idesc.id_number), &idesc) & FOUND) == 0) |
3ad2f081 KM |
305 | break; |
306 | len = strlen(namebuf); | |
307 | cp -= len; | |
308 | if (cp < &namebuf[MAXNAMLEN]) | |
309 | break; | |
310 | bcopy(namebuf, cp, len); | |
311 | *--cp = '/'; | |
312 | ino = idesc.id_number; | |
313 | } | |
314 | if (ino != ROOTINO) { | |
315 | strcpy(namebuf, "?"); | |
316 | return; | |
317 | } | |
318 | bcopy(cp, namebuf, &namebuf[BUFSIZ] - cp); | |
319 | } | |
320 | ||
5d9906c0 KM |
321 | catch() |
322 | { | |
323 | ||
324 | ckfini(); | |
325 | exit(12); | |
326 | } | |
327 | ||
3cfe4689 MK |
328 | /* |
329 | * When preening, allow a single quit to signal | |
330 | * a special exit after filesystem checks complete | |
331 | * so that reboot sequence may be interrupted. | |
332 | */ | |
333 | catchquit() | |
334 | { | |
335 | extern returntosingle; | |
336 | ||
337 | printf("returning to single-user after filesystem check\n"); | |
338 | returntosingle = 1; | |
339 | (void)signal(SIGQUIT, SIG_DFL); | |
340 | } | |
341 | ||
342 | /* | |
343 | * Ignore a single quit signal; wait and flush just in case. | |
344 | * Used by child processes in preen. | |
345 | */ | |
346 | voidquit() | |
347 | { | |
348 | ||
349 | sleep(1); | |
350 | (void)signal(SIGQUIT, SIG_IGN); | |
351 | (void)signal(SIGQUIT, SIG_DFL); | |
352 | } | |
353 | ||
5d9906c0 KM |
354 | /* |
355 | * determine whether an inode should be fixed. | |
356 | */ | |
7718c0e6 | 357 | dofix(idesc, msg) |
5d9906c0 | 358 | register struct inodesc *idesc; |
7718c0e6 | 359 | char *msg; |
5d9906c0 KM |
360 | { |
361 | ||
362 | switch (idesc->id_fix) { | |
363 | ||
364 | case DONTKNOW: | |
7718c0e6 KM |
365 | if (idesc->id_type == DATA) |
366 | direrr(idesc->id_number, msg); | |
367 | else | |
368 | pwarn(msg); | |
369 | if (preen) { | |
370 | printf(" (SALVAGED)\n"); | |
371 | idesc->id_fix = FIX; | |
372 | return (ALTERED); | |
373 | } | |
5d9906c0 KM |
374 | if (reply("SALVAGE") == 0) { |
375 | idesc->id_fix = NOFIX; | |
376 | return (0); | |
377 | } | |
378 | idesc->id_fix = FIX; | |
379 | return (ALTERED); | |
380 | ||
381 | case FIX: | |
382 | return (ALTERED); | |
383 | ||
384 | case NOFIX: | |
385 | return (0); | |
386 | ||
387 | default: | |
388 | errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix); | |
389 | } | |
390 | /* NOTREACHED */ | |
391 | } | |
392 | ||
5d9906c0 KM |
393 | /* VARARGS1 */ |
394 | errexit(s1, s2, s3, s4) | |
395 | char *s1; | |
396 | { | |
7718c0e6 | 397 | printf(s1, s2, s3, s4); |
5d9906c0 KM |
398 | exit(8); |
399 | } | |
400 | ||
401 | /* | |
402 | * An inconsistency occured which shouldn't during normal operations. | |
403 | * Die if preening, otherwise just printf. | |
404 | */ | |
405 | /* VARARGS1 */ | |
406 | pfatal(s, a1, a2, a3) | |
407 | char *s; | |
408 | { | |
409 | ||
410 | if (preen) { | |
411 | printf("%s: ", devname); | |
412 | printf(s, a1, a2, a3); | |
413 | printf("\n"); | |
7718c0e6 KM |
414 | printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", |
415 | devname); | |
416 | exit(8); | |
5d9906c0 KM |
417 | } |
418 | printf(s, a1, a2, a3); | |
419 | } | |
420 | ||
5d9906c0 KM |
421 | /* |
422 | * Pwarn is like printf when not preening, | |
423 | * or a warning (preceded by filename) when preening. | |
424 | */ | |
425 | /* VARARGS1 */ | |
426 | pwarn(s, a1, a2, a3, a4, a5, a6) | |
427 | char *s; | |
428 | { | |
429 | ||
430 | if (preen) | |
431 | printf("%s: ", devname); | |
432 | printf(s, a1, a2, a3, a4, a5, a6); | |
433 | } | |
434 | ||
435 | #ifndef lint | |
436 | /* | |
437 | * Stub for routines from kernel. | |
438 | */ | |
439 | panic(s) | |
440 | char *s; | |
441 | { | |
442 | ||
7718c0e6 KM |
443 | pfatal("INTERNAL INCONSISTENCY:"); |
444 | errexit(s); | |
5d9906c0 KM |
445 | } |
446 | #endif |