1 /* $OpenBSD: utilities.c,v 1.39 2011/04/24 07:07:03 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> 34 #include <sys/time.h> 35 #include <sys/types.h> 36 #include <sys/uio.h> 37 #include <ufs/ufs/dinode.h> 38 #include <ufs/ufs/dir.h> 39 #include <ufs/ffs/fs.h> 40 #include <signal.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <ctype.h> 45 #include <unistd.h> 46 #include <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 56 static void rwerror(char *, daddr64_t); 57 58 int 59 ftypeok(union dinode *dp) 60 { 61 switch (DIP(dp, di_mode) & IFMT) { 62 case IFDIR: 63 case IFREG: 64 case IFBLK: 65 case IFCHR: 66 case IFLNK: 67 case IFSOCK: 68 case IFIFO: 69 return (1); 70 default: 71 if (debug) 72 printf("bad file type 0%o\n", DIP(dp, di_mode)); 73 return (0); 74 } 75 } 76 77 int 78 reply(char *question) 79 { 80 int persevere, c; 81 82 if (preen) 83 pfatal("INTERNAL ERROR: GOT TO reply()"); 84 persevere = !strcmp(question, "CONTINUE"); 85 printf("\n"); 86 if (!persevere && (nflag || fswritefd < 0)) { 87 printf("%s? no\n\n", question); 88 resolved = 0; 89 return (0); 90 } 91 if (yflag || (persevere && nflag)) { 92 printf("%s? yes\n\n", question); 93 return (1); 94 } 95 96 do { 97 printf("%s? [Fyn?] ", question); 98 (void) fflush(stdout); 99 c = getc(stdin); 100 if (c == 'F') { 101 yflag = 1; 102 return (1); 103 } 104 while (c != '\n' && getc(stdin) != '\n') { 105 if (feof(stdin)) { 106 resolved = 0; 107 return (0); 108 } 109 } 110 } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N'); 111 printf("\n"); 112 if (c == 'y' || c == 'Y') 113 return (1); 114 resolved = 0; 115 return (0); 116 } 117 118 /* 119 * Look up state information for an inode. 120 */ 121 struct inostat * 122 inoinfo(ino_t inum) 123 { 124 static struct inostat unallocated = { USTATE, 0, 0 }; 125 struct inostatlist *ilp; 126 int iloff; 127 128 if (inum > maxino) 129 errexit("inoinfo: inumber %d out of range", inum); 130 ilp = &inostathead[inum / sblock.fs_ipg]; 131 iloff = inum % sblock.fs_ipg; 132 if (iloff >= ilp->il_numalloced) 133 return (&unallocated); 134 return (&ilp->il_stat[iloff]); 135 } 136 137 /* 138 * Malloc buffers and set up cache. 139 */ 140 void 141 bufinit(void) 142 { 143 struct bufarea *bp; 144 long bufcnt, i; 145 char *bufp; 146 147 pbp = pdirbp = NULL; 148 bufp = malloc((unsigned int)sblock.fs_bsize); 149 if (bufp == 0) 150 errexit("cannot allocate buffer pool\n"); 151 cgblk.b_un.b_buf = bufp; 152 initbarea(&cgblk); 153 bufhead.b_next = bufhead.b_prev = &bufhead; 154 bufcnt = MAXBUFSPACE / sblock.fs_bsize; 155 if (bufcnt < MINBUFS) 156 bufcnt = MINBUFS; 157 for (i = 0; i < bufcnt; i++) { 158 bp = malloc(sizeof(struct bufarea)); 159 bufp = malloc((unsigned int)sblock.fs_bsize); 160 if (bp == NULL || bufp == NULL) { 161 free(bp); 162 free(bufp); 163 if (i >= MINBUFS) 164 break; 165 errexit("cannot allocate buffer pool\n"); 166 } 167 bp->b_un.b_buf = bufp; 168 bp->b_prev = &bufhead; 169 bp->b_next = bufhead.b_next; 170 bufhead.b_next->b_prev = bp; 171 bufhead.b_next = bp; 172 initbarea(bp); 173 } 174 bufhead.b_size = i; /* save number of buffers */ 175 } 176 177 /* 178 * Manage a cache of directory blocks. 179 */ 180 struct bufarea * 181 getdatablk(daddr64_t blkno, long size) 182 { 183 struct bufarea *bp; 184 185 for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) 186 if (bp->b_bno == fsbtodb(&sblock, blkno)) 187 goto foundit; 188 for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) 189 if ((bp->b_flags & B_INUSE) == 0) 190 break; 191 if (bp == &bufhead) 192 errexit("deadlocked buffer pool\n"); 193 getblk(bp, blkno, size); 194 /* FALLTHROUGH */ 195 foundit: 196 totalreads++; 197 bp->b_prev->b_next = bp->b_next; 198 bp->b_next->b_prev = bp->b_prev; 199 bp->b_prev = &bufhead; 200 bp->b_next = bufhead.b_next; 201 bufhead.b_next->b_prev = bp; 202 bufhead.b_next = bp; 203 bp->b_flags |= B_INUSE; 204 return (bp); 205 } 206 207 void 208 getblk(struct bufarea *bp, daddr64_t blk, long size) 209 { 210 daddr64_t dblk; 211 212 dblk = fsbtodb(&sblock, blk); 213 if (bp->b_bno != dblk) { 214 flush(fswritefd, bp); 215 diskreads++; 216 bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size); 217 bp->b_bno = dblk; 218 bp->b_size = size; 219 } 220 } 221 222 void 223 flush(int fd, struct bufarea *bp) 224 { 225 int i, j; 226 227 if (!bp->b_dirty) 228 return; 229 if (bp->b_errs != 0) 230 pfatal("WRITING %sZERO'ED BLOCK %lld TO DISK\n", 231 (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", 232 bp->b_bno); 233 bp->b_dirty = 0; 234 bp->b_errs = 0; 235 bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); 236 if (bp != &sblk) 237 return; 238 for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 239 bwrite(fswritefd, (char *)sblock.fs_csp + i, 240 fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 241 sblock.fs_cssize - i < sblock.fs_bsize ? 242 sblock.fs_cssize - i : sblock.fs_bsize); 243 } 244 } 245 246 static void 247 rwerror(char *mesg, daddr64_t blk) 248 { 249 250 if (preen == 0) 251 printf("\n"); 252 pfatal("CANNOT %s: BLK %lld", mesg, blk); 253 if (reply("CONTINUE") == 0) 254 errexit("Program terminated\n"); 255 } 256 257 void 258 ckfini(int markclean) 259 { 260 struct bufarea *bp, *nbp; 261 int cnt = 0; 262 sigset_t oset, nset; 263 int64_t sblockloc; 264 265 sigemptyset(&nset); 266 sigaddset(&nset, SIGINT); 267 sigprocmask(SIG_BLOCK, &nset, &oset); 268 269 if (fswritefd < 0) { 270 (void)close(fsreadfd); 271 fsreadfd = -1; 272 sigprocmask(SIG_SETMASK, &oset, NULL); 273 return; 274 } 275 if (sblock.fs_magic == FS_UFS1_MAGIC) { 276 sblockloc = SBLOCK_UFS1; 277 sblock.fs_ffs1_time = sblock.fs_time; 278 sblock.fs_ffs1_size = sblock.fs_size; 279 sblock.fs_ffs1_dsize = sblock.fs_dsize; 280 sblock.fs_ffs1_csaddr = sblock.fs_csaddr; 281 sblock.fs_ffs1_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir; 282 sblock.fs_ffs1_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree; 283 sblock.fs_ffs1_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree; 284 sblock.fs_ffs1_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree; 285 /* Force update on next mount */ 286 sblock.fs_ffs1_flags &= ~FS_FLAGS_UPDATED; 287 } else 288 sblockloc = SBLOCK_UFS2; 289 flush(fswritefd, &sblk); 290 if (havesb && sblk.b_bno != sblockloc / dev_bsize && !preen && 291 reply("UPDATE STANDARD SUPERBLOCK")) { 292 sblk.b_bno = sblockloc / dev_bsize; 293 sbdirty(); 294 flush(fswritefd, &sblk); 295 } 296 flush(fswritefd, &cgblk); 297 free(cgblk.b_un.b_buf); 298 for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) { 299 cnt++; 300 flush(fswritefd, bp); 301 nbp = bp->b_prev; 302 free(bp->b_un.b_buf); 303 free(bp); 304 } 305 if (bufhead.b_size != cnt) 306 errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt); 307 pbp = pdirbp = NULL; 308 if (markclean && (sblock.fs_clean & FS_ISCLEAN) == 0) { 309 /* 310 * Mark the file system as clean, and sync the superblock. 311 */ 312 if (preen) 313 pwarn("MARKING FILE SYSTEM CLEAN\n"); 314 else if (!reply("MARK FILE SYSTEM CLEAN")) 315 markclean = 0; 316 if (markclean) { 317 sblock.fs_clean = FS_ISCLEAN; 318 sbdirty(); 319 flush(fswritefd, &sblk); 320 } 321 } 322 if (debug) 323 printf("cache missed %ld of %ld (%d%%)\n", diskreads, 324 totalreads, (int)(diskreads * 100 / totalreads)); 325 (void)close(fsreadfd); 326 fsreadfd = -1; 327 (void)close(fswritefd); 328 fswritefd = -1; 329 sigprocmask(SIG_SETMASK, &oset, NULL); 330 } 331 332 int 333 bread(int fd, char *buf, daddr64_t blk, long size) 334 { 335 char *cp; 336 int i, errs; 337 off_t offset; 338 339 offset = blk; 340 offset *= dev_bsize; 341 if (lseek(fd, offset, SEEK_SET) < 0) 342 rwerror("SEEK", blk); 343 else if (read(fd, buf, (int)size) == size) 344 return (0); 345 rwerror("READ", blk); 346 if (lseek(fd, offset, SEEK_SET) < 0) 347 rwerror("SEEK", blk); 348 errs = 0; 349 memset(buf, 0, (size_t)size); 350 printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); 351 for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { 352 if (read(fd, cp, (int)secsize) != secsize) { 353 (void)lseek(fd, offset + i + secsize, SEEK_SET); 354 if (secsize != dev_bsize && dev_bsize != 1) 355 printf(" %lld (%lld),", 356 (blk * dev_bsize + i) / secsize, 357 blk + i / dev_bsize); 358 else 359 printf(" %lld,", blk + i / dev_bsize); 360 errs++; 361 } 362 } 363 printf("\n"); 364 return (errs); 365 } 366 367 void 368 bwrite(int fd, char *buf, daddr64_t blk, long size) 369 { 370 int i; 371 char *cp; 372 off_t offset; 373 374 if (fd < 0) 375 return; 376 offset = blk; 377 offset *= dev_bsize; 378 if (lseek(fd, offset, SEEK_SET) < 0) 379 rwerror("SEEK", blk); 380 else if (write(fd, buf, (int)size) == size) { 381 fsmodified = 1; 382 return; 383 } 384 rwerror("WRITE", blk); 385 if (lseek(fd, offset, SEEK_SET) < 0) 386 rwerror("SEEK", blk); 387 printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 388 for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) 389 if (write(fd, cp, (int)dev_bsize) != dev_bsize) { 390 (void)lseek(fd, offset + i + dev_bsize, SEEK_SET); 391 printf(" %lld,", blk + i / dev_bsize); 392 } 393 printf("\n"); 394 return; 395 } 396 397 /* 398 * allocate a data block with the specified number of fragments 399 */ 400 int 401 allocblk(long frags) 402 { 403 int i, j, k, cg, baseblk; 404 struct cg *cgp = &cgrp; 405 406 if (frags <= 0 || frags > sblock.fs_frag) 407 return (0); 408 for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) { 409 for (j = 0; j <= sblock.fs_frag - frags; j++) { 410 if (testbmap(i + j)) 411 continue; 412 for (k = 1; k < frags; k++) 413 if (testbmap(i + j + k)) 414 break; 415 if (k < frags) { 416 j += k; 417 continue; 418 } 419 cg = dtog(&sblock, i + j); 420 getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize); 421 if (!cg_chkmagic(cgp)) 422 pfatal("CG %d: BAD MAGIC NUMBER\n", cg); 423 baseblk = dtogd(&sblock, i + j); 424 425 for (k = 0; k < frags; k++) { 426 setbmap(i + j + k); 427 clrbit(cg_blksfree(cgp), baseblk + k); 428 } 429 n_blks += frags; 430 if (frags == sblock.fs_frag) 431 cgp->cg_cs.cs_nbfree--; 432 else 433 cgp->cg_cs.cs_nffree -= frags; 434 return (i + j); 435 } 436 } 437 return (0); 438 } 439 440 /* 441 * Free a previously allocated block 442 */ 443 void 444 freeblk(daddr64_t blkno, long frags) 445 { 446 struct inodesc idesc; 447 448 idesc.id_blkno = blkno; 449 idesc.id_numfrags = frags; 450 (void)pass4check(&idesc); 451 } 452 453 /* 454 * Find a pathname 455 */ 456 void 457 getpathname(char *namebuf, size_t namebuflen, ino_t curdir, ino_t ino) 458 { 459 int len; 460 char *cp; 461 struct inodesc idesc; 462 static int busy = 0; 463 464 if (curdir == ino && ino == ROOTINO) { 465 (void)strlcpy(namebuf, "/", namebuflen); 466 return; 467 } 468 if (busy || 469 (GET_ISTATE(curdir) != DSTATE && GET_ISTATE(curdir) != DFOUND)) { 470 (void)strlcpy(namebuf, "?", namebuflen); 471 return; 472 } 473 busy = 1; 474 memset(&idesc, 0, sizeof(struct inodesc)); 475 idesc.id_type = DATA; 476 idesc.id_fix = IGNORE; 477 cp = &namebuf[MAXPATHLEN - 1]; 478 *cp = '\0'; 479 if (curdir != ino) { 480 idesc.id_parent = curdir; 481 goto namelookup; 482 } 483 while (ino != ROOTINO) { 484 idesc.id_number = ino; 485 idesc.id_func = findino; 486 idesc.id_name = ".."; 487 if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) 488 break; 489 namelookup: 490 idesc.id_number = idesc.id_parent; 491 idesc.id_parent = ino; 492 idesc.id_func = findname; 493 idesc.id_name = namebuf; 494 if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0) 495 break; 496 len = strlen(namebuf); 497 cp -= len; 498 memcpy(cp, namebuf, (size_t)len); 499 *--cp = '/'; 500 if (cp < &namebuf[MAXNAMLEN]) 501 break; 502 ino = idesc.id_number; 503 } 504 busy = 0; 505 if (ino != ROOTINO) 506 *--cp = '?'; 507 memcpy(namebuf, cp, (size_t)(&namebuf[MAXPATHLEN] - cp)); 508 } 509 510 /*ARGSUSED*/ 511 void 512 catch(int signo) 513 { 514 ckfini(0); /* XXX signal race */ 515 _exit(12); 516 } 517 518 /* 519 * When preening, allow a single quit to signal 520 * a special exit after filesystem checks complete 521 * so that reboot sequence may be interrupted. 522 */ 523 /*ARGSUSED*/ 524 void 525 catchquit(int signo) 526 { 527 extern volatile sig_atomic_t returntosingle; 528 char buf[1024]; 529 530 snprintf(buf, sizeof buf, 531 "returning to single-user after filesystem check\n"); 532 write(STDOUT_FILENO, buf, strlen(buf)); 533 returntosingle = 1; 534 (void)signal(SIGQUIT, SIG_DFL); 535 } 536 537 /* 538 * Ignore a single quit signal; wait and flush just in case. 539 * Used by child processes in preen. 540 */ 541 /*ARGSUSED*/ 542 void 543 voidquit(int signo) 544 { 545 int save_errno = errno; 546 547 sleep(1); 548 (void)signal(SIGQUIT, SIG_IGN); 549 (void)signal(SIGQUIT, SIG_DFL); 550 errno = save_errno; 551 } 552 553 /* 554 * determine whether an inode should be fixed. 555 */ 556 int 557 dofix(struct inodesc *idesc, char *msg) 558 { 559 switch (idesc->id_fix) { 560 561 case DONTKNOW: 562 if (idesc->id_type == DATA) 563 direrror(idesc->id_number, msg); 564 else 565 pwarn("%s", msg); 566 if (preen) { 567 printf(" (SALVAGED)\n"); 568 idesc->id_fix = FIX; 569 return (ALTERED); 570 } 571 if (reply("SALVAGE") == 0) { 572 idesc->id_fix = NOFIX; 573 return (0); 574 } 575 idesc->id_fix = FIX; 576 return (ALTERED); 577 578 case FIX: 579 return (ALTERED); 580 581 case NOFIX: 582 case IGNORE: 583 return (0); 584 585 default: 586 errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix); 587 } 588 /* NOTREACHED */ 589 } 590 591 int (* info_fn)(char *, size_t) = NULL; 592 char *info_filesys = "?"; 593 594 /*ARGSUSED*/ 595 void 596 catchinfo(int signo) 597 { 598 int save_errno = errno, fd; 599 struct iovec iov[4]; 600 char buf[1024]; 601 602 if (info_fn != NULL && info_fn(buf, sizeof buf)) { 603 fd = open(_PATH_TTY, O_WRONLY); 604 if (fd >= 0) { 605 iov[0].iov_base = info_filesys; 606 iov[0].iov_len = strlen(info_filesys); 607 iov[1].iov_base = ": "; 608 iov[1].iov_len = sizeof ": " - 1; 609 iov[2].iov_base = buf; 610 iov[2].iov_len = strlen(buf); 611 iov[3].iov_base = "\n"; 612 iov[3].iov_len = sizeof "\n" - 1; 613 614 writev(fd, iov, 4); 615 close(fd); 616 } 617 } 618 errno = save_errno; 619 } 620 621