| File: | src/sbin/fsdb/../../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.54 2020/07/13 06:52:53 otto 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 | /*ARGSUSED*/ | |||
| 555 | void | |||
| 556 | catch(int signo) | |||
| 557 | { | |||
| 558 | ckfini(0); /* XXX signal race */ | |||
| 559 | _exit(12); | |||
| 560 | } | |||
| 561 | ||||
| 562 | /* | |||
| 563 | * When preening, allow a single quit to signal | |||
| 564 | * a special exit after filesystem checks complete | |||
| 565 | * so that reboot sequence may be interrupted. | |||
| 566 | */ | |||
| 567 | /*ARGSUSED*/ | |||
| 568 | void | |||
| 569 | catchquit(int signo) | |||
| 570 | { | |||
| 571 | extern volatile sig_atomic_t returntosingle; | |||
| 572 | static const char message[] = | |||
| 573 | "returning to single-user after filesystem check\n"; | |||
| 574 | ||||
| 575 | write(STDOUT_FILENO1, message, sizeof(message)-1); | |||
| 576 | returntosingle = 1; | |||
| 577 | (void)signal(SIGQUIT3, SIG_DFL(void (*)(int))0); | |||
| 578 | } | |||
| 579 | ||||
| 580 | /* | |||
| 581 | * Ignore a single quit signal; wait and flush just in case. | |||
| 582 | * Used by child processes in preen. | |||
| 583 | */ | |||
| 584 | /*ARGSUSED*/ | |||
| 585 | void | |||
| 586 | voidquit(int signo) | |||
| 587 | { | |||
| 588 | int save_errno = errno(*__errno()); | |||
| 589 | ||||
| 590 | sleep(1); | |||
| 591 | (void)signal(SIGQUIT3, SIG_IGN(void (*)(int))1); | |||
| 592 | (void)signal(SIGQUIT3, SIG_DFL(void (*)(int))0); | |||
| 593 | errno(*__errno()) = save_errno; | |||
| 594 | } | |||
| 595 | ||||
| 596 | /* | |||
| 597 | * determine whether an inode should be fixed. | |||
| 598 | */ | |||
| 599 | int | |||
| 600 | dofix(struct inodesc *idesc, char *msg) | |||
| 601 | { | |||
| 602 | switch (idesc->id_fix) { | |||
| 603 | ||||
| 604 | case DONTKNOW: | |||
| 605 | if (idesc->id_type == DATA1) | |||
| 606 | direrror(idesc->id_number, msg); | |||
| 607 | else | |||
| 608 | pwarn("%s", msg); | |||
| 609 | if (preen) { | |||
| 610 | printf(" (SALVAGED)\n"); | |||
| 611 | idesc->id_fix = FIX; | |||
| 612 | return (ALTERED0x08); | |||
| 613 | } | |||
| 614 | if (reply("SALVAGE") == 0) { | |||
| 615 | idesc->id_fix = NOFIX; | |||
| 616 | return (0); | |||
| 617 | } | |||
| 618 | idesc->id_fix = FIX; | |||
| 619 | return (ALTERED0x08); | |||
| 620 | ||||
| 621 | case FIX: | |||
| 622 | return (ALTERED0x08); | |||
| 623 | ||||
| 624 | case NOFIX: | |||
| 625 | case IGNORE: | |||
| 626 | return (0); | |||
| 627 | ||||
| 628 | default: | |||
| 629 | errexit("UNKNOWN INODESC FIX MODE %u\n", idesc->id_fix); | |||
| 630 | } | |||
| 631 | /* NOTREACHED */ | |||
| 632 | } | |||
| 633 | ||||
| 634 | int (* info_fn)(char *, size_t) = NULL((void *)0); | |||
| 635 | char *info_filesys = "?"; | |||
| 636 | ||||
| 637 | /*ARGSUSED*/ | |||
| 638 | void | |||
| 639 | catchinfo(int signo) | |||
| 640 | { | |||
| 641 | static int info_fd; | |||
| 642 | int save_errno = errno(*__errno()); | |||
| 643 | struct iovec iov[4]; | |||
| 644 | char buf[1024]; | |||
| 645 | ||||
| 646 | if (signo == 0) { | |||
| 647 | info_fd = open(_PATH_TTY"/dev/tty", O_WRONLY0x0001); | |||
| 648 | signal(SIGINFO29, catchinfo); | |||
| 649 | } else if (info_fd > 0 && info_fn != NULL((void *)0) && info_fn(buf, sizeof buf)) { | |||
| 650 | iov[0].iov_base = info_filesys; | |||
| 651 | iov[0].iov_len = strlen(info_filesys); | |||
| 652 | iov[1].iov_base = ": "; | |||
| 653 | iov[1].iov_len = sizeof ": " - 1; | |||
| 654 | iov[2].iov_base = buf; | |||
| 655 | iov[2].iov_len = strlen(buf); | |||
| 656 | iov[3].iov_base = "\n"; | |||
| 657 | iov[3].iov_len = sizeof "\n" - 1; | |||
| 658 | ||||
| 659 | writev(info_fd, iov, 4); | |||
| 660 | } | |||
| 661 | errno(*__errno()) = save_errno; | |||
| 662 | } | |||
| 663 | /* | |||
| 664 | * Attempt to flush a cylinder group cache entry. | |||
| 665 | * Return whether the flush was successful. | |||
| 666 | */ | |||
| 667 | static int | |||
| 668 | flushentry(void) | |||
| 669 | { | |||
| 670 | struct bufarea *cgbp; | |||
| 671 | ||||
| 672 | if (flushtries == sblock(*sblk.b_un.b_fs).fs_ncg || cgbufs == NULL((void *)0)) | |||
| 673 | return (0); | |||
| 674 | cgbp = &cgbufs[flushtries++]; | |||
| 675 | if (cgbp->b_un.b_cg == NULL((void *)0)) | |||
| 676 | return (0); | |||
| 677 | flush(fswritefd, cgbp); | |||
| 678 | free(cgbp->b_un.b_buf); | |||
| 679 | cgbp->b_un.b_buf = NULL((void *)0); | |||
| 680 | return (1); | |||
| 681 | } | |||
| 682 | ||||
| 683 | /* | |||
| 684 | * Wrapper for malloc() that flushes the cylinder group cache to try | |||
| 685 | * to get space. | |||
| 686 | */ | |||
| 687 | void * | |||
| 688 | Malloc(size_t size) | |||
| 689 | { | |||
| 690 | void *retval; | |||
| 691 | ||||
| 692 | while ((retval = malloc(size)) == NULL((void *)0)) | |||
| 693 | if (flushentry() == 0) | |||
| 694 | break; | |||
| 695 | return (retval); | |||
| 696 | } | |||
| 697 | ||||
| 698 | /* | |||
| 699 | * Wrapper for calloc() that flushes the cylinder group cache to try | |||
| 700 | * to get space. | |||
| 701 | */ | |||
| 702 | void* | |||
| 703 | Calloc(size_t cnt, size_t size) | |||
| 704 | { | |||
| 705 | void *retval; | |||
| 706 | ||||
| 707 | while ((retval = calloc(cnt, size)) == NULL((void *)0)) | |||
| 708 | if (flushentry() == 0) | |||
| 709 | break; | |||
| 710 | return (retval); | |||
| 711 | } | |||
| 712 | ||||
| 713 | /* | |||
| 714 | * Wrapper for reallocarray() that flushes the cylinder group cache to try | |||
| 715 | * to get space. | |||
| 716 | */ | |||
| 717 | void* | |||
| 718 | Reallocarray(void *p, size_t cnt, size_t size) | |||
| 719 | { | |||
| 720 | void *retval; | |||
| 721 | ||||
| 722 | while ((retval = reallocarray(p, cnt, size)) == NULL((void *)0)) | |||
| 723 | if (flushentry() == 0) | |||
| 724 | break; | |||
| 725 | return (retval); | |||
| 726 | } |