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