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