File: | src/sbin/fsck_ffs/utilities.c |
Warning: | line 465, column 9 The left operand of '==' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: utilities.c,v 1.55 2023/03/08 04:43:06 guenther Exp $ */ | |||
2 | /* $NetBSD: utilities.c,v 1.18 1996/09/27 22:45:20 christos Exp $ */ | |||
3 | ||||
4 | /* | |||
5 | * Copyright (c) 1980, 1986, 1993 | |||
6 | * The Regents of the University of California. All rights reserved. | |||
7 | * | |||
8 | * Redistribution and use in source and binary forms, with or without | |||
9 | * modification, are permitted provided that the following conditions | |||
10 | * are met: | |||
11 | * 1. Redistributions of source code must retain the above copyright | |||
12 | * notice, this list of conditions and the following disclaimer. | |||
13 | * 2. Redistributions in binary form must reproduce the above copyright | |||
14 | * notice, this list of conditions and the following disclaimer in the | |||
15 | * documentation and/or other materials provided with the distribution. | |||
16 | * 3. Neither the name of the University nor the names of its contributors | |||
17 | * may be used to endorse or promote products derived from this software | |||
18 | * without specific prior written permission. | |||
19 | * | |||
20 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |||
21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |||
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
30 | * SUCH DAMAGE. | |||
31 | */ | |||
32 | ||||
33 | #include <sys/param.h> /* DEV_BSIZE isset setbit clrbit */ | |||
34 | #include <sys/time.h> | |||
35 | #include <sys/uio.h> | |||
36 | #include <ufs/ufs/dinode.h> | |||
37 | #include <ufs/ufs/dir.h> | |||
38 | #include <ufs/ffs/fs.h> | |||
39 | #include <signal.h> | |||
40 | #include <stdio.h> | |||
41 | #include <stdlib.h> | |||
42 | #include <string.h> | |||
43 | #include <ctype.h> | |||
44 | #include <unistd.h> | |||
45 | #include <limits.h> | |||
46 | #include <errno(*__errno()).h> | |||
47 | #include <fcntl.h> | |||
48 | #include <paths.h> | |||
49 | ||||
50 | #include "fsutil.h" | |||
51 | #include "fsck.h" | |||
52 | #include "extern.h" | |||
53 | ||||
54 | long diskreads, totalreads; /* Disk cache statistics */ | |||
55 | static struct bufarea cgblk; /* backup buffer for cylinder group blocks */ | |||
56 | ||||
57 | static void rwerror(char *, daddr_t); | |||
58 | ||||
59 | int | |||
60 | ftypeok(union dinode *dp) | |||
61 | { | |||
62 | switch (DIP(dp, di_mode)(((*sblk.b_un.b_fs).fs_magic == 0x011954) ? (dp)->dp1.di_mode : (dp)->dp2.di_mode) & IFMT0170000) { | |||
63 | case IFDIR0040000: | |||
64 | case IFREG0100000: | |||
65 | case IFBLK0060000: | |||
66 | case IFCHR0020000: | |||
67 | case IFLNK0120000: | |||
68 | case IFSOCK0140000: | |||
69 | case IFIFO0010000: | |||
70 | return (1); | |||
71 | default: | |||
72 | if (debug) | |||
73 | printf("bad file type 0%o\n", DIP(dp, di_mode)(((*sblk.b_un.b_fs).fs_magic == 0x011954) ? (dp)->dp1.di_mode : (dp)->dp2.di_mode)); | |||
74 | return (0); | |||
75 | } | |||
76 | } | |||
77 | ||||
78 | int | |||
79 | reply(char *question) | |||
80 | { | |||
81 | int persevere, c; | |||
82 | ||||
83 | if (preen) | |||
84 | pfatal("INTERNAL ERROR: GOT TO reply()"); | |||
85 | persevere = !strcmp(question, "CONTINUE"); | |||
86 | printf("\n"); | |||
87 | if (!persevere && (nflag || fswritefd < 0)) { | |||
88 | printf("%s? no\n\n", question); | |||
89 | resolved = 0; | |||
90 | return (0); | |||
91 | } | |||
92 | if (yflag || (persevere && nflag)) { | |||
93 | printf("%s? yes\n\n", question); | |||
94 | return (1); | |||
95 | } | |||
96 | ||||
97 | do { | |||
98 | printf("%s? [Fyn?] ", question); | |||
99 | (void) fflush(stdout(&__sF[1])); | |||
100 | c = getc(stdin)(!__isthreaded ? (--((&__sF[0]))->_r < 0 ? __srget( (&__sF[0])) : (int)(*((&__sF[0]))->_p++)) : (getc) ((&__sF[0]))); | |||
101 | if (c == 'F') { | |||
102 | yflag = 1; | |||
103 | return (1); | |||
104 | } | |||
105 | while (c != '\n' && getc(stdin)(!__isthreaded ? (--((&__sF[0]))->_r < 0 ? __srget( (&__sF[0])) : (int)(*((&__sF[0]))->_p++)) : (getc) ((&__sF[0]))) != '\n') { | |||
106 | if (feof(stdin)(!__isthreaded ? ((((&__sF[0]))->_flags & 0x0020) != 0) : (feof)((&__sF[0])))) { | |||
107 | resolved = 0; | |||
108 | return (0); | |||
109 | } | |||
110 | } | |||
111 | } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N'); | |||
112 | printf("\n"); | |||
113 | if (c == 'y' || c == 'Y') | |||
114 | return (1); | |||
115 | resolved = 0; | |||
116 | return (0); | |||
117 | } | |||
118 | ||||
119 | /* | |||
120 | * Look up state information for an inode. | |||
121 | */ | |||
122 | struct inostat * | |||
123 | inoinfo(ino_t inum) | |||
124 | { | |||
125 | static struct inostat unallocated = { USTATE01, 0, 0 }; | |||
126 | struct inostatlist *ilp; | |||
127 | int iloff; | |||
128 | ||||
129 | if (inum > maxino) | |||
130 | errexit("inoinfo: inumber %llu out of range", | |||
131 | (unsigned long long)inum); | |||
132 | ilp = &inostathead[inum / sblock(*sblk.b_un.b_fs).fs_ipg]; | |||
133 | iloff = inum % sblock(*sblk.b_un.b_fs).fs_ipg; | |||
134 | if (iloff >= ilp->il_numalloced) | |||
135 | return (&unallocated); | |||
136 | return (&ilp->il_stat[iloff]); | |||
137 | } | |||
138 | ||||
139 | /* | |||
140 | * Malloc buffers and set up cache. | |||
141 | */ | |||
142 | void | |||
143 | bufinit(void) | |||
144 | { | |||
145 | struct bufarea *bp; | |||
146 | long bufcnt, i; | |||
147 | char *bufp; | |||
148 | ||||
149 | pbp = pdirbp = NULL((void *)0); | |||
150 | bufp = malloc((unsigned int)sblock(*sblk.b_un.b_fs).fs_bsize); | |||
151 | if (bufp == 0) | |||
152 | errexit("cannot allocate buffer pool\n"); | |||
153 | cgblk.b_un.b_buf = bufp; | |||
154 | initbarea(&cgblk)(&cgblk)->b_dirty = 0; (&cgblk)->b_bno = -1; (& cgblk)->b_flags = 0;; | |||
155 | bufhead.b_next = bufhead.b_prev = &bufhead; | |||
156 | bufcnt = MAXBUFSPACE40*1024 / sblock(*sblk.b_un.b_fs).fs_bsize; | |||
157 | if (bufcnt < MINBUFS5) | |||
158 | bufcnt = MINBUFS5; | |||
159 | for (i = 0; i < bufcnt; i++) { | |||
160 | bp = malloc(sizeof(struct bufarea)); | |||
161 | bufp = malloc((unsigned int)sblock(*sblk.b_un.b_fs).fs_bsize); | |||
162 | if (bp == NULL((void *)0) || bufp == NULL((void *)0)) { | |||
163 | free(bp); | |||
164 | free(bufp); | |||
165 | if (i >= MINBUFS5) | |||
166 | break; | |||
167 | errexit("cannot allocate buffer pool\n"); | |||
168 | } | |||
169 | bp->b_un.b_buf = bufp; | |||
170 | bp->b_prev = &bufhead; | |||
171 | bp->b_next = bufhead.b_next; | |||
172 | bufhead.b_next->b_prev = bp; | |||
173 | bufhead.b_next = bp; | |||
174 | initbarea(bp)(bp)->b_dirty = 0; (bp)->b_bno = -1; (bp)->b_flags = 0;; | |||
175 | } | |||
176 | bufhead.b_size = i; /* save number of buffers */ | |||
177 | } | |||
178 | ||||
179 | /* | |||
180 | * Manage cylinder group buffers. | |||
181 | */ | |||
182 | static struct bufarea *cgbufs; /* header for cylinder group cache */ | |||
183 | static int flushtries; /* number of tries to reclaim memory */ | |||
184 | struct bufarea * | |||
185 | cglookup(u_int cg) | |||
186 | { | |||
187 | struct bufarea *cgbp; | |||
188 | struct cg *cgp; | |||
189 | ||||
190 | if (cgbufs == NULL((void *)0)) { | |||
191 | cgbufs = calloc(sblock(*sblk.b_un.b_fs).fs_ncg, sizeof(struct bufarea)); | |||
192 | if (cgbufs == NULL((void *)0)) | |||
193 | errexit("cannot allocate cylinder group buffers"); | |||
194 | } | |||
195 | cgbp = &cgbufs[cg]; | |||
196 | if (cgbp->b_un.b_cg != NULL((void *)0)) | |||
197 | return (cgbp); | |||
198 | cgp = NULL((void *)0); | |||
199 | if (flushtries == 0) | |||
200 | cgp = malloc((unsigned int)sblock(*sblk.b_un.b_fs).fs_cgsize); | |||
201 | if (cgp == NULL((void *)0)) { | |||
202 | getblk(&cgblk, cgtod(&sblock, cg)((((daddr_t)(&(*sblk.b_un.b_fs))->fs_fpg * (cg)) + (& (*sblk.b_un.b_fs))->fs_cgoffset * ((cg) & ~((&(*sblk .b_un.b_fs))->fs_cgmask))) + (&(*sblk.b_un.b_fs))-> fs_cblkno), sblock(*sblk.b_un.b_fs).fs_cgsize); | |||
203 | return (&cgblk); | |||
204 | } | |||
205 | cgbp->b_un.b_cg = cgp; | |||
206 | initbarea(cgbp)(cgbp)->b_dirty = 0; (cgbp)->b_bno = -1; (cgbp)->b_flags = 0;; | |||
207 | getblk(cgbp, cgtod(&sblock, cg)((((daddr_t)(&(*sblk.b_un.b_fs))->fs_fpg * (cg)) + (& (*sblk.b_un.b_fs))->fs_cgoffset * ((cg) & ~((&(*sblk .b_un.b_fs))->fs_cgmask))) + (&(*sblk.b_un.b_fs))-> fs_cblkno), sblock(*sblk.b_un.b_fs).fs_cgsize); | |||
208 | return (cgbp); | |||
209 | } | |||
210 | ||||
211 | ||||
212 | /* | |||
213 | * Manage a cache of directory blocks. | |||
214 | */ | |||
215 | struct bufarea * | |||
216 | getdatablk(daddr_t blkno, long size) | |||
217 | { | |||
218 | struct bufarea *bp; | |||
219 | ||||
220 | for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) | |||
221 | if (bp->b_bno == fsbtodb(&sblock, blkno)((blkno) << (&(*sblk.b_un.b_fs))->fs_fsbtodb)) | |||
222 | goto foundit; | |||
223 | for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) | |||
224 | if ((bp->b_flags & B_INUSE1) == 0) | |||
225 | break; | |||
226 | if (bp == &bufhead) | |||
227 | errexit("deadlocked buffer pool\n"); | |||
228 | getblk(bp, blkno, size); | |||
229 | /* FALLTHROUGH */ | |||
230 | foundit: | |||
231 | totalreads++; | |||
232 | bp->b_prev->b_next = bp->b_next; | |||
233 | bp->b_next->b_prev = bp->b_prev; | |||
234 | bp->b_prev = &bufhead; | |||
235 | bp->b_next = bufhead.b_next; | |||
236 | bufhead.b_next->b_prev = bp; | |||
237 | bufhead.b_next = bp; | |||
238 | bp->b_flags |= B_INUSE1; | |||
239 | return (bp); | |||
240 | } | |||
241 | ||||
242 | void | |||
243 | getblk(struct bufarea *bp, daddr_t blk, long size) | |||
244 | { | |||
245 | daddr_t dblk; | |||
246 | ||||
247 | dblk = fsbtodb(&sblock, blk)((blk) << (&(*sblk.b_un.b_fs))->fs_fsbtodb); | |||
248 | if (bp->b_bno != dblk) { | |||
249 | flush(fswritefd, bp); | |||
250 | diskreads++; | |||
251 | bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size); | |||
252 | bp->b_bno = dblk; | |||
253 | bp->b_size = size; | |||
254 | } | |||
255 | } | |||
256 | ||||
257 | void | |||
258 | flush(int fd, struct bufarea *bp) | |||
259 | { | |||
260 | int i, j; | |||
261 | ||||
262 | if (!bp->b_dirty) | |||
263 | return; | |||
264 | if (bp->b_errs != 0) | |||
265 | pfatal("WRITING %sZERO'ED BLOCK %lld TO DISK\n", | |||
266 | (bp->b_errs == bp->b_size / DEV_BSIZE(1 << 9)) ? "" : "PARTIALLY ", | |||
267 | (long long)bp->b_bno); | |||
268 | bp->b_dirty = 0; | |||
269 | bp->b_errs = 0; | |||
270 | bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); | |||
271 | if (bp != &sblk) | |||
272 | return; | |||
273 | for (i = 0, j = 0; i < sblock(*sblk.b_un.b_fs).fs_cssize; i += sblock(*sblk.b_un.b_fs).fs_bsize, j++) { | |||
274 | bwrite(fswritefd, (char *)sblock(*sblk.b_un.b_fs).fs_csp + i, | |||
275 | fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag)(((*sblk.b_un.b_fs).fs_csaddr + j * (*sblk.b_un.b_fs).fs_frag ) << (&(*sblk.b_un.b_fs))->fs_fsbtodb), | |||
276 | sblock(*sblk.b_un.b_fs).fs_cssize - i < sblock(*sblk.b_un.b_fs).fs_bsize ? | |||
277 | sblock(*sblk.b_un.b_fs).fs_cssize - i : sblock(*sblk.b_un.b_fs).fs_bsize); | |||
278 | } | |||
279 | } | |||
280 | ||||
281 | static void | |||
282 | rwerror(char *mesg, daddr_t blk) | |||
283 | { | |||
284 | ||||
285 | if (preen == 0) | |||
286 | printf("\n"); | |||
287 | pfatal("CANNOT %s: BLK %lld", mesg, (long long)blk); | |||
288 | if (reply("CONTINUE") == 0) | |||
289 | errexit("Program terminated\n"); | |||
290 | } | |||
291 | ||||
292 | void | |||
293 | ckfini(int markclean) | |||
294 | { | |||
295 | struct bufarea *bp, *nbp; | |||
296 | int cnt = 0; | |||
297 | sigset_t oset, nset; | |||
298 | int64_t sblockloc; | |||
299 | ||||
300 | sigemptyset(&nset); | |||
301 | sigaddset(&nset, SIGINT2); | |||
302 | sigprocmask(SIG_BLOCK1, &nset, &oset); | |||
303 | ||||
304 | if (fswritefd < 0) { | |||
305 | (void)close(fsreadfd); | |||
306 | fsreadfd = -1; | |||
307 | sigprocmask(SIG_SETMASK3, &oset, NULL((void *)0)); | |||
308 | return; | |||
309 | } | |||
310 | if (sblock(*sblk.b_un.b_fs).fs_magic == FS_UFS1_MAGIC0x011954) { | |||
311 | sblockloc = SBLOCK_UFS18192; | |||
312 | sblock(*sblk.b_un.b_fs).fs_ffs1_time = sblock(*sblk.b_un.b_fs).fs_time; | |||
313 | sblock(*sblk.b_un.b_fs).fs_ffs1_size = sblock(*sblk.b_un.b_fs).fs_size; | |||
314 | sblock(*sblk.b_un.b_fs).fs_ffs1_dsize = sblock(*sblk.b_un.b_fs).fs_dsize; | |||
315 | sblock(*sblk.b_un.b_fs).fs_ffs1_csaddr = sblock(*sblk.b_un.b_fs).fs_csaddr; | |||
316 | sblock(*sblk.b_un.b_fs).fs_ffs1_cstotal.cs_ndir = sblock(*sblk.b_un.b_fs).fs_cstotal.cs_ndir; | |||
317 | sblock(*sblk.b_un.b_fs).fs_ffs1_cstotal.cs_nbfree = sblock(*sblk.b_un.b_fs).fs_cstotal.cs_nbfree; | |||
318 | sblock(*sblk.b_un.b_fs).fs_ffs1_cstotal.cs_nifree = sblock(*sblk.b_un.b_fs).fs_cstotal.cs_nifree; | |||
319 | sblock(*sblk.b_un.b_fs).fs_ffs1_cstotal.cs_nffree = sblock(*sblk.b_un.b_fs).fs_cstotal.cs_nffree; | |||
320 | /* Force update on next mount */ | |||
321 | sblock(*sblk.b_un.b_fs).fs_ffs1_flags &= ~FS_FLAGS_UPDATED0x80; | |||
322 | } else | |||
323 | sblockloc = SBLOCK_UFS265536; | |||
324 | flush(fswritefd, &sblk); | |||
325 | if (havesb && sblk.b_bno != sblockloc / DEV_BSIZE(1 << 9) && !preen && | |||
326 | reply("UPDATE STANDARD SUPERBLOCK")) { | |||
327 | sblk.b_bno = sblockloc / DEV_BSIZE(1 << 9); | |||
328 | sbdirty()sblk.b_dirty = 1; | |||
329 | flush(fswritefd, &sblk); | |||
330 | } | |||
331 | flush(fswritefd, &cgblk); | |||
332 | free(cgblk.b_un.b_buf); | |||
333 | for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) { | |||
334 | cnt++; | |||
335 | flush(fswritefd, bp); | |||
336 | nbp = bp->b_prev; | |||
337 | free(bp->b_un.b_buf); | |||
338 | free(bp); | |||
339 | } | |||
340 | if (bufhead.b_size != cnt) | |||
341 | errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt); | |||
342 | if (cgbufs != NULL((void *)0)) { | |||
343 | for (cnt = 0; cnt < sblock(*sblk.b_un.b_fs).fs_ncg; cnt++) { | |||
344 | if (cgbufs[cnt].b_un.b_cg == NULL((void *)0)) | |||
345 | continue; | |||
346 | flush(fswritefd, &cgbufs[cnt]); | |||
347 | free(cgbufs[cnt].b_un.b_cg); | |||
348 | } | |||
349 | free(cgbufs); | |||
350 | } | |||
351 | pbp = pdirbp = NULL((void *)0); | |||
352 | if (markclean && (sblock(*sblk.b_un.b_fs).fs_clean & FS_ISCLEAN0x01) == 0) { | |||
353 | /* | |||
354 | * Mark the file system as clean, and sync the superblock. | |||
355 | */ | |||
356 | if (preen) | |||
357 | pwarn("MARKING FILE SYSTEM CLEAN\n"); | |||
358 | else if (!reply("MARK FILE SYSTEM CLEAN")) | |||
359 | markclean = 0; | |||
360 | if (markclean) { | |||
361 | sblock(*sblk.b_un.b_fs).fs_clean = FS_ISCLEAN0x01; | |||
362 | sbdirty()sblk.b_dirty = 1; | |||
363 | flush(fswritefd, &sblk); | |||
364 | } | |||
365 | } | |||
366 | if (debug) | |||
367 | printf("cache missed %ld of %ld (%d%%)\n", diskreads, | |||
368 | totalreads, (int)(diskreads * 100 / totalreads)); | |||
369 | (void)close(fsreadfd); | |||
370 | fsreadfd = -1; | |||
371 | (void)close(fswritefd); | |||
372 | fswritefd = -1; | |||
373 | sigprocmask(SIG_SETMASK3, &oset, NULL((void *)0)); | |||
374 | } | |||
375 | ||||
376 | int | |||
377 | bread(int fd, char *buf, daddr_t blk, long size) | |||
378 | { | |||
379 | char *cp; | |||
380 | int i, errs; | |||
381 | off_t offset; | |||
382 | ||||
383 | offset = blk; | |||
384 | offset *= DEV_BSIZE(1 << 9); | |||
385 | if (pread(fd, buf, size, offset) == size) | |||
386 | return (0); | |||
387 | rwerror("READ", blk); | |||
388 | errs = 0; | |||
389 | memset(buf, 0, (size_t)size); | |||
390 | printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); | |||
391 | for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { | |||
392 | if (pread(fd, cp, secsize, offset + i) != secsize) { | |||
393 | if (secsize != DEV_BSIZE(1 << 9)) | |||
394 | printf(" %lld (%lld),", | |||
395 | (long long)(offset + i) / secsize, | |||
396 | (long long)blk + i / DEV_BSIZE(1 << 9)); | |||
397 | else | |||
398 | printf(" %lld,", (long long)blk + | |||
399 | i / DEV_BSIZE(1 << 9)); | |||
400 | errs++; | |||
401 | } | |||
402 | } | |||
403 | printf("\n"); | |||
404 | return (errs); | |||
405 | } | |||
406 | ||||
407 | void | |||
408 | bwrite(int fd, char *buf, daddr_t blk, long size) | |||
409 | { | |||
410 | int i; | |||
411 | char *cp; | |||
412 | off_t offset; | |||
413 | ||||
414 | if (fd < 0) | |||
415 | return; | |||
416 | offset = blk; | |||
417 | offset *= DEV_BSIZE(1 << 9); | |||
418 | if (pwrite(fd, buf, size, offset) == size) { | |||
419 | fsmodified = 1; | |||
420 | return; | |||
421 | } | |||
422 | rwerror("WRITE", blk); | |||
423 | printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); | |||
424 | for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) | |||
425 | if (pwrite(fd, cp, secsize, offset + i) != secsize) { | |||
426 | if (secsize != DEV_BSIZE(1 << 9)) | |||
427 | printf(" %lld (%lld),", | |||
428 | (long long)(offset + i) / secsize, | |||
429 | (long long)blk + i / DEV_BSIZE(1 << 9)); | |||
430 | else | |||
431 | printf(" %lld,", (long long)blk + | |||
432 | i / DEV_BSIZE(1 << 9)); | |||
433 | } | |||
434 | printf("\n"); | |||
435 | return; | |||
436 | } | |||
437 | ||||
438 | /* | |||
439 | * allocate a data block with the specified number of fragments | |||
440 | */ | |||
441 | daddr_t | |||
442 | allocblk(int frags) | |||
443 | { | |||
444 | daddr_t i, baseblk; | |||
445 | int j, k, cg; | |||
446 | struct bufarea *cgbp; | |||
447 | struct cg *cgp; | |||
448 | ||||
449 | if (frags <= 0 || frags > sblock(*sblk.b_un.b_fs).fs_frag) | |||
| ||||
450 | return (0); | |||
451 | for (i = 0; i < maxfsblock - sblock(*sblk.b_un.b_fs).fs_frag; i += sblock(*sblk.b_un.b_fs).fs_frag) { | |||
452 | for (j = 0; j <= sblock(*sblk.b_un.b_fs).fs_frag - frags; j++) { | |||
453 | if (testbmap(i + j)((blockmap)[(i + j)>>3] & (1<<((i + j)&(8 -1))))) | |||
454 | continue; | |||
455 | for (k = 1; k < frags; k++) | |||
456 | if (testbmap(i + j + k)((blockmap)[(i + j + k)>>3] & (1<<((i + j + k )&(8 -1))))) | |||
457 | break; | |||
458 | if (k
| |||
459 | j += k; | |||
460 | continue; | |||
461 | } | |||
462 | cg = dtog(&sblock, i + j)((i + j) / (&(*sblk.b_un.b_fs))->fs_fpg); | |||
463 | cgbp = cglookup(cg); | |||
464 | cgp = cgbp->b_un.b_cg; | |||
465 | if (!cg_chkmagic(cgp)((cgp)->cg_magic == 0x090255 || ((struct ocg *)(cgp))-> cg_magic == 0x090255)) | |||
| ||||
466 | pfatal("CG %d: BAD MAGIC NUMBER\n", cg); | |||
467 | baseblk = dtogd(&sblock, i + j)((i + j) % (&(*sblk.b_un.b_fs))->fs_fpg); | |||
468 | ||||
469 | for (k = 0; k < frags; k++) { | |||
470 | setbmap(i + j + k)((blockmap)[(i + j + k)>>3] |= 1<<((i + j + k)& (8 -1))); | |||
471 | clrbit(cg_blksfree(cgp), baseblk + k)(((((cgp)->cg_magic != 0x090255) ? (((struct ocg *)(cgp))-> cg_free) : ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_freeoff ))))[(baseblk + k)>>3] &= ~(1<<((baseblk + k) &(8 -1)))); | |||
472 | } | |||
473 | n_blks += frags; | |||
474 | if (frags == sblock(*sblk.b_un.b_fs).fs_frag) | |||
475 | cgp->cg_cs.cs_nbfree--; | |||
476 | else | |||
477 | cgp->cg_cs.cs_nffree -= frags; | |||
478 | return (i + j); | |||
479 | } | |||
480 | } | |||
481 | return (0); | |||
482 | } | |||
483 | ||||
484 | /* | |||
485 | * Free a previously allocated block | |||
486 | */ | |||
487 | void | |||
488 | freeblk(daddr_t blkno, int frags) | |||
489 | { | |||
490 | struct inodesc idesc; | |||
491 | ||||
492 | idesc.id_blkno = blkno; | |||
493 | idesc.id_numfrags = frags; | |||
494 | (void)pass4check(&idesc); | |||
495 | } | |||
496 | ||||
497 | /* | |||
498 | * Find a pathname | |||
499 | */ | |||
500 | void | |||
501 | getpathname(char *namebuf, size_t namebuflen, ino_t curdir, ino_t ino) | |||
502 | { | |||
503 | int len; | |||
504 | char *cp; | |||
505 | struct inodesc idesc; | |||
506 | static int busy = 0; | |||
507 | ||||
508 | if (curdir == ino && ino == ROOTINO((ufsino_t)2)) { | |||
509 | (void)strlcpy(namebuf, "/", namebuflen); | |||
510 | return; | |||
511 | } | |||
512 | if (busy || | |||
513 | (GET_ISTATE(curdir)(inoinfo(curdir)->ino_state) != DSTATE03 && GET_ISTATE(curdir)(inoinfo(curdir)->ino_state) != DFOUND04)) { | |||
514 | (void)strlcpy(namebuf, "?", namebuflen); | |||
515 | return; | |||
516 | } | |||
517 | busy = 1; | |||
518 | memset(&idesc, 0, sizeof(struct inodesc)); | |||
519 | idesc.id_type = DATA1; | |||
520 | idesc.id_fix = IGNORE; | |||
521 | cp = &namebuf[PATH_MAX1024 - 1]; | |||
522 | *cp = '\0'; | |||
523 | if (curdir != ino) { | |||
524 | idesc.id_parent = curdir; | |||
525 | goto namelookup; | |||
526 | } | |||
527 | while (ino != ROOTINO((ufsino_t)2)) { | |||
528 | idesc.id_number = ino; | |||
529 | idesc.id_func = findino; | |||
530 | idesc.id_name = ".."; | |||
531 | if ((ckinode(ginode(ino), &idesc) & FOUND0x10) == 0) | |||
532 | break; | |||
533 | namelookup: | |||
534 | idesc.id_number = idesc.id_parent; | |||
535 | idesc.id_parent = ino; | |||
536 | idesc.id_func = findname; | |||
537 | idesc.id_name = namebuf; | |||
538 | if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND0x10) == 0) | |||
539 | break; | |||
540 | len = strlen(namebuf); | |||
541 | cp -= len; | |||
542 | memmove(cp, namebuf, (size_t)len); | |||
543 | *--cp = '/'; | |||
544 | if (cp < &namebuf[MAXNAMLEN255]) | |||
545 | break; | |||
546 | ino = idesc.id_number; | |||
547 | } | |||
548 | busy = 0; | |||
549 | if (ino != ROOTINO((ufsino_t)2)) | |||
550 | *--cp = '?'; | |||
551 | memmove(namebuf, cp, (size_t)(&namebuf[PATH_MAX1024] - cp)); | |||
552 | } | |||
553 | ||||
554 | void | |||
555 | catch(int signo) | |||
556 | { | |||
557 | ckfini(0); /* XXX signal race */ | |||
558 | _exit(12); | |||
559 | } | |||
560 | ||||
561 | /* | |||
562 | * When preening, allow a single quit to signal | |||
563 | * a special exit after filesystem checks complete | |||
564 | * so that reboot sequence may be interrupted. | |||
565 | */ | |||
566 | void | |||
567 | catchquit(int signo) | |||
568 | { | |||
569 | extern volatile sig_atomic_t returntosingle; | |||
570 | static const char message[] = | |||
571 | "returning to single-user after filesystem check\n"; | |||
572 | ||||
573 | write(STDOUT_FILENO1, message, sizeof(message)-1); | |||
574 | returntosingle = 1; | |||
575 | (void)signal(SIGQUIT3, SIG_DFL(void (*)(int))0); | |||
576 | } | |||
577 | ||||
578 | /* | |||
579 | * Ignore a single quit signal; wait and flush just in case. | |||
580 | * Used by child processes in preen. | |||
581 | */ | |||
582 | void | |||
583 | voidquit(int signo) | |||
584 | { | |||
585 | int save_errno = errno(*__errno()); | |||
586 | ||||
587 | sleep(1); | |||
588 | (void)signal(SIGQUIT3, SIG_IGN(void (*)(int))1); | |||
589 | (void)signal(SIGQUIT3, SIG_DFL(void (*)(int))0); | |||
590 | errno(*__errno()) = save_errno; | |||
591 | } | |||
592 | ||||
593 | /* | |||
594 | * determine whether an inode should be fixed. | |||
595 | */ | |||
596 | int | |||
597 | dofix(struct inodesc *idesc, char *msg) | |||
598 | { | |||
599 | switch (idesc->id_fix) { | |||
600 | ||||
601 | case DONTKNOW: | |||
602 | if (idesc->id_type == DATA1) | |||
603 | direrror(idesc->id_number, msg); | |||
604 | else | |||
605 | pwarn("%s", msg); | |||
606 | if (preen) { | |||
607 | printf(" (SALVAGED)\n"); | |||
608 | idesc->id_fix = FIX; | |||
609 | return (ALTERED0x08); | |||
610 | } | |||
611 | if (reply("SALVAGE") == 0) { | |||
612 | idesc->id_fix = NOFIX; | |||
613 | return (0); | |||
614 | } | |||
615 | idesc->id_fix = FIX; | |||
616 | return (ALTERED0x08); | |||
617 | ||||
618 | case FIX: | |||
619 | return (ALTERED0x08); | |||
620 | ||||
621 | case NOFIX: | |||
622 | case IGNORE: | |||
623 | return (0); | |||
624 | ||||
625 | default: | |||
626 | errexit("UNKNOWN INODESC FIX MODE %u\n", idesc->id_fix); | |||
627 | } | |||
628 | /* NOTREACHED */ | |||
629 | } | |||
630 | ||||
631 | int (* info_fn)(char *, size_t) = NULL((void *)0); | |||
632 | char *info_filesys = "?"; | |||
633 | ||||
634 | void | |||
635 | catchinfo(int signo) | |||
636 | { | |||
637 | static int info_fd; | |||
638 | int save_errno = errno(*__errno()); | |||
639 | struct iovec iov[4]; | |||
640 | char buf[1024]; | |||
641 | ||||
642 | if (signo == 0) { | |||
643 | info_fd = open(_PATH_TTY"/dev/tty", O_WRONLY0x0001); | |||
644 | signal(SIGINFO29, catchinfo); | |||
645 | } else if (info_fd > 0 && info_fn != NULL((void *)0) && info_fn(buf, sizeof buf)) { | |||
646 | iov[0].iov_base = info_filesys; | |||
647 | iov[0].iov_len = strlen(info_filesys); | |||
648 | iov[1].iov_base = ": "; | |||
649 | iov[1].iov_len = sizeof ": " - 1; | |||
650 | iov[2].iov_base = buf; | |||
651 | iov[2].iov_len = strlen(buf); | |||
652 | iov[3].iov_base = "\n"; | |||
653 | iov[3].iov_len = sizeof "\n" - 1; | |||
654 | ||||
655 | writev(info_fd, iov, 4); | |||
656 | } | |||
657 | errno(*__errno()) = save_errno; | |||
658 | } | |||
659 | /* | |||
660 | * Attempt to flush a cylinder group cache entry. | |||
661 | * Return whether the flush was successful. | |||
662 | */ | |||
663 | static int | |||
664 | flushentry(void) | |||
665 | { | |||
666 | struct bufarea *cgbp; | |||
667 | ||||
668 | if (flushtries == sblock(*sblk.b_un.b_fs).fs_ncg || cgbufs == NULL((void *)0)) | |||
669 | return (0); | |||
670 | cgbp = &cgbufs[flushtries++]; | |||
671 | if (cgbp->b_un.b_cg == NULL((void *)0)) | |||
672 | return (0); | |||
673 | flush(fswritefd, cgbp); | |||
674 | free(cgbp->b_un.b_buf); | |||
675 | cgbp->b_un.b_buf = NULL((void *)0); | |||
676 | return (1); | |||
677 | } | |||
678 | ||||
679 | /* | |||
680 | * Wrapper for malloc() that flushes the cylinder group cache to try | |||
681 | * to get space. | |||
682 | */ | |||
683 | void * | |||
684 | Malloc(size_t size) | |||
685 | { | |||
686 | void *retval; | |||
687 | ||||
688 | while ((retval = malloc(size)) == NULL((void *)0)) | |||
689 | if (flushentry() == 0) | |||
690 | break; | |||
691 | return (retval); | |||
692 | } | |||
693 | ||||
694 | /* | |||
695 | * Wrapper for calloc() that flushes the cylinder group cache to try | |||
696 | * to get space. | |||
697 | */ | |||
698 | void* | |||
699 | Calloc(size_t cnt, size_t size) | |||
700 | { | |||
701 | void *retval; | |||
702 | ||||
703 | while ((retval = calloc(cnt, size)) == NULL((void *)0)) | |||
704 | if (flushentry() == 0) | |||
705 | break; | |||
706 | return (retval); | |||
707 | } | |||
708 | ||||
709 | /* | |||
710 | * Wrapper for reallocarray() that flushes the cylinder group cache to try | |||
711 | * to get space. | |||
712 | */ | |||
713 | void* | |||
714 | Reallocarray(void *p, size_t cnt, size_t size) | |||
715 | { | |||
716 | void *retval; | |||
717 | ||||
718 | while ((retval = reallocarray(p, cnt, size)) == NULL((void *)0)) | |||
719 | if (flushentry() == 0) | |||
720 | break; | |||
721 | return (retval); | |||
722 | } |