1 /*- 2 * Copyright (c) 1992 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)library.c 5.9 (Berkeley) 05/17/93"; 10 #endif /* not lint */ 11 12 #include <sys/param.h> 13 #include <sys/time.h> 14 #include <sys/stat.h> 15 #include <sys/mount.h> 16 #include <sys/types.h> 17 #include <sys/mman.h> 18 19 #include <ufs/ufs/dinode.h> 20 #include <ufs/lfs/lfs.h> 21 22 #include <fcntl.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <unistd.h> 27 28 #include "clean.h" 29 30 void add_blocks __P((FS_INFO *, BLOCK_INFO *, int *, SEGSUM *, caddr_t, 31 daddr_t, daddr_t)); 32 void add_inodes __P((FS_INFO *, BLOCK_INFO *, int *, SEGSUM *, caddr_t, 33 daddr_t)); 34 int bi_compare __P((const void *, const void *)); 35 int bi_toss __P((const void *, const void *, const void *)); 36 void get_ifile __P((FS_INFO *, int)); 37 int get_superblock __P((FS_INFO *, struct lfs *)); 38 int pseg_valid __P((FS_INFO *, SEGSUM *)); 39 40 /* 41 * This function will get information on all mounted file systems 42 * of a given type. 43 */ 44 int 45 fs_getmntinfo(buf, type) 46 struct statfs **buf; 47 int type; 48 { 49 struct statfs *tstatfsp; 50 struct statfs *sbp; 51 int count, i, tcount; 52 53 tcount = getmntinfo(&tstatfsp, MNT_NOWAIT); 54 55 if (tcount < 0) { 56 err(0, "getmntinfo failed"); 57 return (-1); 58 } 59 60 for (count = 0, i = 0; i < tcount ; ++i) 61 if (tstatfsp[i].f_type == type) 62 ++count; 63 64 if (count) { 65 if (!(*buf = (struct statfs *) 66 malloc(count * sizeof(struct statfs)))) 67 err(1, "fs_getmntinfo: out of space"); 68 for (i = 0, sbp = *buf; i < tcount ; ++i) { 69 if (tstatfsp[i].f_type == type) { 70 *sbp = tstatfsp[i]; 71 ++sbp; 72 } 73 } 74 } 75 return (count); 76 } 77 78 /* 79 * Get all the information available on an LFS file system. 80 * Returns an array of FS_INFO structures, NULL on error. 81 */ 82 FS_INFO * 83 get_fs_info (lstatfsp, count, use_mmap) 84 struct statfs *lstatfsp; /* IN: array of statfs structs */ 85 int count; /* IN: number of file systems */ 86 int use_mmap; /* IN: mmap or read */ 87 { 88 FS_INFO *fp, *fsp; 89 int i; 90 91 fsp = (FS_INFO *)calloc(count, sizeof(FS_INFO)); 92 93 for (fp = fsp, i = 0; i < count; ++i, ++fp) { 94 fp->fi_statfsp = lstatfsp++; 95 if (get_superblock (fp, &fp->fi_lfs)) 96 err(1, "get_fs_info: get_superblock failed"); 97 fp->fi_daddr_shift = 98 fp->fi_lfs.lfs_bshift - fp->fi_lfs.lfs_fsbtodb; 99 get_ifile (fp, use_mmap); 100 } 101 return (fsp); 102 } 103 104 /* 105 * If we are reading the ifile then we need to refresh it. Even if 106 * we are mmapping it, it might have grown. Finally, we need to 107 * refresh the file system information (statfs) info. 108 */ 109 void 110 reread_fs_info(fsp, count, use_mmap) 111 FS_INFO *fsp; /* IN: array of fs_infos to free */ 112 int count; /* IN: number of file systems */ 113 int use_mmap; 114 { 115 int i; 116 117 for (i = 0; i < count; ++i, ++fsp) { 118 if (statfs(fsp->fi_statfsp->f_mntonname, fsp->fi_statfsp)) 119 err(0, "reread_fs_info: statfs failed"); 120 get_ifile (fsp, use_mmap); 121 } 122 } 123 124 /* 125 * Gets the superblock from disk (possibly in face of errors) 126 */ 127 int 128 get_superblock (fsp, sbp) 129 FS_INFO *fsp; /* local file system info structure */ 130 struct lfs *sbp; 131 { 132 char mntfromname[MNAMELEN+1]; 133 int fid; 134 135 strcpy(mntfromname, "/dev/r"); 136 strcat(mntfromname, fsp->fi_statfsp->f_mntfromname+5); 137 138 if ((fid = open(mntfromname, O_RDONLY, (mode_t)0)) < 0) { 139 err(0, "get_superblock: bad open"); 140 return (-1); 141 } 142 143 get(fid, LFS_LABELPAD, sbp, sizeof(struct lfs)); 144 close (fid); 145 146 return (0); 147 } 148 149 /* 150 * This function will map the ifile into memory. It causes a 151 * fatal error on failure. 152 */ 153 void 154 get_ifile (fsp, use_mmap) 155 FS_INFO *fsp; 156 int use_mmap; 157 158 { 159 struct stat file_stat; 160 caddr_t ifp; 161 char *ifile_name; 162 int count, fid; 163 164 ifp = NULL; 165 ifile_name = malloc(strlen(fsp->fi_statfsp->f_mntonname) + 166 strlen(IFILE_NAME)+2); 167 strcat(strcat(strcpy(ifile_name, fsp->fi_statfsp->f_mntonname), "/"), 168 IFILE_NAME); 169 170 if ((fid = open(ifile_name, O_RDWR, (mode_t)0)) < 0) 171 err(1, "get_ifile: bad open"); 172 173 if (fstat (fid, &file_stat)) 174 err(1, "get_ifile: fstat failed"); 175 176 if (use_mmap && file_stat.st_size == fsp->fi_ifile_length) { 177 (void) close(fid); 178 return; 179 } 180 181 /* get the ifile */ 182 if (use_mmap) { 183 if (fsp->fi_cip) 184 munmap((caddr_t)fsp->fi_cip, fsp->fi_ifile_length); 185 ifp = mmap ((caddr_t)0, file_stat.st_size, 186 PROT_READ|PROT_WRITE, 0, fid, (off_t)0); 187 if (ifp == (caddr_t)(-1)) 188 err(1, "get_ifile: mmap failed"); 189 } else { 190 if (fsp->fi_cip) 191 free(fsp->fi_cip); 192 if (!(ifp = malloc (file_stat.st_size))) 193 err (1, "get_ifile: malloc failed"); 194 redo_read: 195 count = read (fid, ifp, (size_t) file_stat.st_size); 196 197 if (count < 0) 198 err(1, "get_ifile: bad ifile read"); 199 else if (count < file_stat.st_size) { 200 err(0, "get_ifile"); 201 if (lseek(fid, 0, SEEK_SET) < 0) 202 err(1, "get_ifile: bad ifile lseek"); 203 goto redo_read; 204 } 205 } 206 fsp->fi_ifile_length = file_stat.st_size; 207 close (fid); 208 209 fsp->fi_cip = (CLEANERINFO *)ifp; 210 fsp->fi_segusep = (SEGUSE *)(ifp + CLEANSIZE(fsp)); 211 fsp->fi_ifilep = (IFILE *)((caddr_t)fsp->fi_segusep + SEGTABSIZE(fsp)); 212 213 /* 214 * The number of ifile entries is equal to the number of blocks 215 * blocks in the ifile minus the ones allocated to cleaner info 216 * and segment usage table multiplied by the number of ifile 217 * entries per page. 218 */ 219 fsp->fi_ifile_count = (fsp->fi_ifile_length >> fsp->fi_lfs.lfs_bshift - 220 fsp->fi_lfs.lfs_cleansz - fsp->fi_lfs.lfs_segtabsz) * 221 fsp->fi_lfs.lfs_ifpb; 222 223 free (ifile_name); 224 } 225 226 /* 227 * This function will scan a segment and return a list of 228 * <inode, blocknum> pairs which indicate which blocks were 229 * contained as live data within the segment when the segment 230 * summary was read (it may have "died" since then). Any given 231 * pair will be listed at most once. 232 */ 233 int 234 lfs_segmapv(fsp, seg, seg_buf, blocks, bcount) 235 FS_INFO *fsp; /* pointer to local file system information */ 236 int seg; /* the segment number */ 237 caddr_t seg_buf; /* the buffer containing the segment's data */ 238 BLOCK_INFO **blocks; /* OUT: array of block_info for live blocks */ 239 int *bcount; /* OUT: number of active blocks in segment */ 240 { 241 BLOCK_INFO *bip; 242 SEGSUM *sp; 243 SEGUSE *sup; 244 FINFO *fip; 245 struct lfs *lfsp; 246 caddr_t s, segend; 247 daddr_t pseg_addr, seg_addr; 248 int i, nelem, nblocks, sumsize; 249 time_t timestamp; 250 251 lfsp = &fsp->fi_lfs; 252 nelem = 2 * lfsp->lfs_ssize; 253 if (!(bip = malloc(nelem * sizeof(BLOCK_INFO)))) 254 goto err0; 255 256 sup = SEGUSE_ENTRY(lfsp, fsp->fi_segusep, seg); 257 s = seg_buf + (sup->su_flags & SEGUSE_SUPERBLOCK ? LFS_SBPAD : 0); 258 seg_addr = sntoda(lfsp, seg); 259 pseg_addr = seg_addr + (sup->su_flags & SEGUSE_SUPERBLOCK ? btodb(LFS_SBPAD) : 0); 260 #ifdef VERBOSE 261 printf("\tsegment buffer at: 0x%x\tseg_addr 0x%x\n", s, seg_addr); 262 #endif /* VERBOSE */ 263 264 *bcount = 0; 265 for (segend = seg_buf + seg_size(lfsp), timestamp = 0; s < segend; ) { 266 sp = (SEGSUM *)s; 267 268 #ifdef VERBOSE 269 printf("\tpartial at: 0x%x\n", pseg_addr); 270 print_SEGSUM(lfsp, sp); 271 fflush(stdout); 272 #endif /* VERBOSE */ 273 274 nblocks = pseg_valid(fsp, sp); 275 if (nblocks <= 0) 276 break; 277 278 /* Check if we have hit old data */ 279 if (timestamp > ((SEGSUM*)s)->ss_create) 280 break; 281 timestamp = ((SEGSUM*)s)->ss_create; 282 283 #ifdef DIAGNOSTIC 284 /* Verfiy size of summary block */ 285 sumsize = sizeof(SEGSUM) + 286 (sp->ss_ninos + INOPB(lfsp) - 1) / INOPB(lfsp); 287 for (fip = (FINFO *)(sp + 1); i < sp->ss_nfinfo; ++i) { 288 sumsize += sizeof(FINFO) + 289 (fip->fi_nblocks - 1) * sizeof(daddr_t); 290 fip = (FINFO *)(&fip->fi_blocks[fip->fi_nblocks]); 291 } 292 if (sumsize > LFS_SUMMARY_SIZE) { 293 fprintf(stderr, 294 "Segment %d summary block too big: %d\n", 295 seg, sumsize); 296 exit(1); 297 } 298 #endif 299 300 if (*bcount + nblocks + sp->ss_ninos > nelem) { 301 nelem = *bcount + nblocks + sp->ss_ninos; 302 bip = realloc (bip, nelem * sizeof(BLOCK_INFO)); 303 if (!bip) 304 goto err0; 305 } 306 add_blocks(fsp, bip, bcount, sp, seg_buf, seg_addr, pseg_addr); 307 add_inodes(fsp, bip, bcount, sp, seg_buf, seg_addr); 308 pseg_addr += fsbtodb(lfsp, nblocks) + 309 bytetoda(fsp, LFS_SUMMARY_SIZE); 310 s += (nblocks << lfsp->lfs_bshift) + LFS_SUMMARY_SIZE; 311 } 312 qsort(bip, *bcount, sizeof(BLOCK_INFO), bi_compare); 313 toss(bip, bcount, sizeof(BLOCK_INFO), bi_toss, NULL); 314 #ifdef VERBOSE 315 { 316 BLOCK_INFO *_bip; 317 int i; 318 319 printf("BLOCK INFOS\n"); 320 for (_bip = bip, i=0; i < *bcount; ++_bip, ++i) 321 PRINT_BINFO(_bip); 322 } 323 #endif 324 *blocks = bip; 325 return (0); 326 327 err0: *bcount = 0; 328 return (-1); 329 330 } 331 332 /* 333 * This will parse a partial segment and fill in BLOCK_INFO structures 334 * for each block described in the segment summary. It will not include 335 * blocks or inodes from files with new version numbers. 336 */ 337 void 338 add_blocks (fsp, bip, countp, sp, seg_buf, segaddr, psegaddr) 339 FS_INFO *fsp; /* pointer to super block */ 340 BLOCK_INFO *bip; /* Block info array */ 341 int *countp; /* IN/OUT: number of blocks in array */ 342 SEGSUM *sp; /* segment summmary pointer */ 343 caddr_t seg_buf; /* buffer containing segment */ 344 daddr_t segaddr; /* address of this segment */ 345 daddr_t psegaddr; /* address of this partial segment */ 346 { 347 IFILE *ifp; 348 FINFO *fip; 349 caddr_t bp; 350 daddr_t *dp, *iaddrp; 351 int db_per_block, i, j; 352 u_long page_size; 353 354 #ifdef VERBOSE 355 printf("FILE INFOS\n"); 356 #endif 357 db_per_block = fsbtodb(&fsp->fi_lfs, 1); 358 page_size = fsp->fi_lfs.lfs_bsize; 359 bp = seg_buf + datobyte(fsp, psegaddr - segaddr) + LFS_SUMMARY_SIZE; 360 bip += *countp; 361 psegaddr += bytetoda(fsp, LFS_SUMMARY_SIZE); 362 iaddrp = (daddr_t *)((caddr_t)sp + LFS_SUMMARY_SIZE); 363 --iaddrp; 364 for (fip = (FINFO *)(sp + 1), i = 0; i < sp->ss_nfinfo; 365 ++i, fip = (FINFO *)(&fip->fi_blocks[fip->fi_nblocks])) { 366 367 ifp = IFILE_ENTRY(&fsp->fi_lfs, fsp->fi_ifilep, fip->fi_ino); 368 PRINT_FINFO(fip, ifp); 369 if (ifp->if_version > fip->fi_version) 370 continue; 371 dp = &(fip->fi_blocks[0]); 372 for (j = 0; j < fip->fi_nblocks; j++, dp++) { 373 while (psegaddr == *iaddrp) { 374 psegaddr += db_per_block; 375 bp += page_size; 376 --iaddrp; 377 } 378 bip->bi_inode = fip->fi_ino; 379 bip->bi_lbn = *dp; 380 bip->bi_daddr = psegaddr; 381 bip->bi_segcreate = (time_t)(sp->ss_create); 382 bip->bi_bp = bp; 383 bip->bi_version = ifp->if_version; 384 psegaddr += db_per_block; 385 bp += page_size; 386 ++bip; 387 ++(*countp); 388 } 389 } 390 } 391 392 /* 393 * For a particular segment summary, reads the inode blocks and adds 394 * INODE_INFO structures to the array. Returns the number of inodes 395 * actually added. 396 */ 397 void 398 add_inodes (fsp, bip, countp, sp, seg_buf, seg_addr) 399 FS_INFO *fsp; /* pointer to super block */ 400 BLOCK_INFO *bip; /* block info array */ 401 int *countp; /* pointer to current number of inodes */ 402 SEGSUM *sp; /* segsum pointer */ 403 caddr_t seg_buf; /* the buffer containing the segment's data */ 404 daddr_t seg_addr; /* disk address of seg_buf */ 405 { 406 struct dinode *di; 407 struct lfs *lfsp; 408 IFILE *ifp; 409 BLOCK_INFO *bp; 410 daddr_t *daddrp; 411 ino_t inum; 412 int i; 413 414 if (sp->ss_ninos <= 0) 415 return; 416 417 bp = bip + *countp; 418 lfsp = &fsp->fi_lfs; 419 #ifdef VERBOSE 420 (void) printf("INODES:\n"); 421 #endif 422 daddrp = (daddr_t *)((caddr_t)sp + LFS_SUMMARY_SIZE); 423 for (i = 0; i < sp->ss_ninos; ++i) { 424 if (i % INOPB(lfsp) == 0) { 425 --daddrp; 426 di = (struct dinode *)(seg_buf + 427 ((*daddrp - seg_addr) << fsp->fi_daddr_shift)); 428 } else 429 ++di; 430 431 inum = di->di_inumber; 432 bp->bi_lbn = LFS_UNUSED_LBN; 433 bp->bi_inode = inum; 434 bp->bi_daddr = *daddrp; 435 bp->bi_bp = di; 436 bp->bi_segcreate = sp->ss_create; 437 438 if (inum == LFS_IFILE_INUM) { 439 bp->bi_version = 1; /* Ifile version should be 1 */ 440 bp++; 441 ++(*countp); 442 PRINT_INODE(1, bp); 443 } else { 444 ifp = IFILE_ENTRY(lfsp, fsp->fi_ifilep, inum); 445 PRINT_INODE(ifp->if_daddr == *daddrp, bp); 446 bp->bi_version = ifp->if_version; 447 if (ifp->if_daddr == *daddrp) { 448 bp++; 449 ++(*countp); 450 } 451 } 452 } 453 } 454 455 /* 456 * Checks the summary checksum and the data checksum to determine if the 457 * segment is valid or not. Returns the size of the partial segment if it 458 * is valid, * and 0 otherwise. Use dump_summary to figure out size of the 459 * the partial as well as whether or not the checksum is valid. 460 */ 461 int 462 pseg_valid (fsp, ssp) 463 FS_INFO *fsp; /* pointer to file system info */ 464 SEGSUM *ssp; /* pointer to segment summary block */ 465 { 466 caddr_t p; 467 int i, nblocks; 468 u_long *datap; 469 470 if ((nblocks = dump_summary(&fsp->fi_lfs, ssp, 0, NULL)) <= 0 || 471 nblocks > fsp->fi_lfs.lfs_ssize - 1) 472 return(0); 473 474 /* check data/inode block(s) checksum too */ 475 datap = (u_long *)malloc(nblocks * sizeof(u_long)); 476 p = (caddr_t)ssp + LFS_SUMMARY_SIZE; 477 for (i = 0; i < nblocks; ++i) { 478 datap[i] = *((u_long *)p); 479 p += fsp->fi_lfs.lfs_bsize; 480 } 481 if (cksum ((void *)datap, nblocks * sizeof(u_long)) != ssp->ss_datasum) 482 return (0); 483 484 return (nblocks); 485 } 486 487 488 /* #define MMAP_SEGMENT */ 489 /* 490 * read a segment into a memory buffer 491 */ 492 int 493 mmap_segment (fsp, segment, segbuf, use_mmap) 494 FS_INFO *fsp; /* file system information */ 495 int segment; /* segment number */ 496 caddr_t *segbuf; /* pointer to buffer area */ 497 int use_mmap; /* mmap instead of read */ 498 { 499 struct lfs *lfsp; 500 int fid; /* fildes for file system device */ 501 daddr_t seg_daddr; /* base disk address of segment */ 502 off_t seg_byte; 503 size_t ssize; 504 char mntfromname[MNAMELEN+2]; 505 506 lfsp = &fsp->fi_lfs; 507 508 /* get the disk address of the beginning of the segment */ 509 seg_daddr = sntoda(lfsp, segment); 510 seg_byte = datobyte(fsp, seg_daddr); 511 ssize = seg_size(lfsp); 512 513 strcpy(mntfromname, "/dev/r"); 514 strcat(mntfromname, fsp->fi_statfsp->f_mntfromname+5); 515 516 if ((fid = open(mntfromname, O_RDONLY, (mode_t)0)) < 0) { 517 err(0, "mmap_segment: bad open"); 518 return (-1); 519 } 520 521 if (use_mmap) { 522 *segbuf = mmap ((caddr_t)0, seg_size(lfsp), PROT_READ, 523 0, fid, seg_byte); 524 if (*(long *)segbuf < 0) { 525 err(0, "mmap_segment: mmap failed"); 526 return (NULL); 527 } 528 } else { 529 #ifdef VERBOSE 530 printf("mmap_segment\tseg_daddr: %lu\tseg_size: %lu\tseg_offset: %qu\n", 531 seg_daddr, ssize, seg_byte); 532 #endif 533 /* malloc the space for the buffer */ 534 *segbuf = malloc(ssize); 535 if (!*segbuf) { 536 err(0, "mmap_segment: malloc failed"); 537 return(NULL); 538 } 539 540 /* read the segment data into the buffer */ 541 if (lseek (fid, seg_byte, SEEK_SET) != seg_byte) { 542 err (0, "mmap_segment: bad lseek"); 543 free(*segbuf); 544 return (-1); 545 } 546 547 if (read (fid, *segbuf, ssize) != ssize) { 548 err (0, "mmap_segment: bad read"); 549 free(*segbuf); 550 return (-1); 551 } 552 } 553 close (fid); 554 555 return (0); 556 } 557 558 void 559 munmap_segment (fsp, seg_buf, use_mmap) 560 FS_INFO *fsp; /* file system information */ 561 caddr_t seg_buf; /* pointer to buffer area */ 562 int use_mmap; /* mmap instead of read/write */ 563 { 564 if (use_mmap) 565 munmap (seg_buf, seg_size(&fsp->fi_lfs)); 566 else 567 free (seg_buf); 568 } 569 570 571 /* 572 * USEFUL DEBUGGING TOOLS: 573 */ 574 void 575 print_SEGSUM (lfsp, p) 576 struct lfs *lfsp; 577 SEGSUM *p; 578 { 579 if (p) 580 (void) dump_summary(lfsp, p, DUMP_ALL, NULL); 581 else printf("0x0"); 582 fflush(stdout); 583 } 584 585 int 586 bi_compare(a, b) 587 const void *a; 588 const void *b; 589 { 590 const BLOCK_INFO *ba, *bb; 591 int diff; 592 593 ba = a; 594 bb = b; 595 596 if (diff = (int)(ba->bi_inode - bb->bi_inode)) 597 return (diff); 598 if (diff = (int)(ba->bi_lbn - bb->bi_lbn)) { 599 if (ba->bi_lbn == LFS_UNUSED_LBN) 600 return(-1); 601 else if (bb->bi_lbn == LFS_UNUSED_LBN) 602 return(1); 603 else if (ba->bi_lbn < 0 && bb->bi_lbn >= 0) 604 return(1); 605 else if (bb->bi_lbn < 0 && ba->bi_lbn >= 0) 606 return(-1); 607 else 608 return (diff); 609 } 610 if (diff = (int)(ba->bi_segcreate - bb->bi_segcreate)) 611 return (diff); 612 diff = (int)(ba->bi_daddr - bb->bi_daddr); 613 return (diff); 614 } 615 616 int 617 bi_toss(dummy, a, b) 618 const void *dummy; 619 const void *a; 620 const void *b; 621 { 622 const BLOCK_INFO *ba, *bb; 623 624 ba = a; 625 bb = b; 626 627 return(ba->bi_inode == bb->bi_inode && ba->bi_lbn == bb->bi_lbn); 628 } 629 630 void 631 toss(p, nump, size, dotoss, client) 632 void *p; 633 int *nump; 634 size_t size; 635 int (*dotoss) __P((const void *, const void *, const void *)); 636 void *client; 637 { 638 int i; 639 void *p1; 640 641 if (*nump == 0) 642 return; 643 644 for (i = *nump; --i > 0;) { 645 p1 = p + size; 646 if (dotoss(client, p, p1)) { 647 memmove(p, p1, i * size); 648 --(*nump); 649 } else 650 p += size; 651 } 652 } 653