1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/param.h> 27 #include <sys/vnode.h> 28 #include <sys/fs/ufs_fsdir.h> 29 #include <sys/fs/ufs_fs.h> 30 #include <sys/fs/ufs_inode.h> 31 #include <sys/sysmacros.h> 32 #include <sys/promif.h> 33 34 #include <sys/stat.h> 35 #include <sys/bootvfs.h> 36 #include <sys/bootdebug.h> 37 #include <sys/salib.h> 38 #include <sys/sacache.h> 39 40 41 int print_cache_stats = 0; 42 43 /* 44 * This fd is used when talking to the device file itself. 45 */ 46 static fileid_t *head; 47 /* 48 * hooks into ufs logging support 49 */ 50 extern void lufs_boot_init(fileid_t *); 51 extern void lufs_closeall(void); 52 extern void lufs_merge_deltas(fileid_t *); 53 54 /* Only got one of these...ergo, only 1 fs open at once */ 55 /* static */ 56 devid_t *ufs_devp; 57 58 struct dirinfo { 59 int loc; 60 fileid_t *fi; 61 }; 62 63 /* 64 * Function prototypes 65 */ 66 static int boot_ufs_mountroot(char *str); 67 static int boot_ufs_unmountroot(void); 68 static int boot_ufs_open(char *filename, int flags); 69 static int boot_ufs_close(int fd); 70 static ssize_t boot_ufs_read(int fd, caddr_t buf, size_t size); 71 static off_t boot_ufs_lseek(int, off_t, int); 72 static int boot_ufs_fstat(int fd, struct bootstat *stp); 73 static void boot_ufs_closeall(int flag); 74 static int boot_ufs_getdents(int fd, struct dirent *dep, unsigned size); 75 76 struct boot_fs_ops boot_ufs_ops = { 77 "ufs", 78 boot_ufs_mountroot, 79 boot_ufs_unmountroot, 80 boot_ufs_open, 81 boot_ufs_close, 82 boot_ufs_read, 83 boot_ufs_lseek, 84 boot_ufs_fstat, 85 boot_ufs_closeall, 86 boot_ufs_getdents 87 }; 88 89 static ino_t find(fileid_t *filep, char *path); 90 static ino_t dlook(fileid_t *filep, char *path); 91 static daddr32_t sbmap(fileid_t *filep, daddr32_t bn); 92 static struct direct *readdir(struct dirinfo *dstuff); 93 94 /* These are the pools of buffers, etc. */ 95 #define NBUFS (NIADDR+1) 96 /* Compilers like to play with alignment, so force the issue here */ 97 static union { 98 char *blk[NBUFS]; 99 daddr32_t *dummy; 100 } b; 101 daddr32_t blknos[NBUFS]; 102 103 /* 104 * There is only 1 open (mounted) device at any given time. 105 * So we can keep a single, global devp file descriptor to 106 * use to index into the di[] array. This is not true for the 107 * fi[] array. We can have more than one file open at once, 108 * so there is no global fd for the fi[]. 109 * The user program must save the fd passed back from open() 110 * and use it to do subsequent read()'s. 111 */ 112 113 static int 114 openi(fileid_t *filep, ino_t inode) 115 { 116 int retval; 117 struct dinode *dp; 118 devid_t *devp = filep->fi_devp; 119 120 /* Try the inode cache first */ 121 if ((filep->fi_inode = get_icache(devp->di_dcookie, inode)) != NULL) 122 return (0); 123 /* Nope, not there so lets read it off the disk. */ 124 filep->fi_offset = 0; 125 filep->fi_blocknum = fsbtodb(&devp->un_fs.di_fs, 126 itod(&devp->un_fs.di_fs, inode)); 127 128 /* never more than 1 disk block */ 129 filep->fi_count = devp->un_fs.di_fs.fs_bsize; 130 filep->fi_memp = filep->fi_buf; 131 132 /* Maybe the block is in the disk block cache */ 133 if ((filep->fi_memp = get_bcache(filep)) == NULL) { 134 /* Not in the block cache so read it from disk */ 135 if (retval = set_bcache(filep)) 136 return (retval); 137 lufs_merge_deltas(filep); 138 } 139 140 dp = (struct dinode *)filep->fi_memp; 141 filep->fi_inode = (struct inode *) 142 bkmem_alloc(sizeof (struct inode)); 143 bzero((char *)filep->fi_inode, sizeof (struct inode)); 144 filep->fi_inode->i_ic = 145 dp[itoo(&devp->un_fs.di_fs, inode)].di_un.di_icom; 146 filep->fi_inode->i_number = inode; 147 if (set_ricache(devp->di_dcookie, inode, (void *)filep->fi_inode, 148 sizeof (struct inode))) 149 filep->fi_inode->i_flag = FI_NOCACHE; 150 return (0); 151 } 152 153 static fileid_t * 154 find_fp(int fd) 155 { 156 fileid_t *filep = head; 157 158 if (fd >= 0) { 159 while ((filep = filep->fi_forw) != head) 160 if (fd == filep->fi_filedes) 161 return (filep->fi_taken ? filep : 0); 162 } 163 164 return (0); 165 } 166 167 static ino_t 168 find(fileid_t *filep, char *path) 169 { 170 char *q; 171 char c; 172 ino_t inode; 173 char lpath[MAXPATHLEN]; 174 char *lpathp = lpath; 175 int len, r; 176 devid_t *devp; 177 178 if (path == NULL || *path == '\0') { 179 printf("null path\n"); 180 return ((ino_t)0); 181 } 182 183 bzero(lpath, sizeof (lpath)); 184 bcopy(path, lpath, strlen(path)); 185 devp = filep->fi_devp; 186 while (*lpathp) { 187 /* if at the beginning of pathname get root inode */ 188 r = (lpathp == lpath); 189 if (r && openi(filep, (ino_t)UFSROOTINO)) 190 return ((ino_t)0); 191 while (*lpathp == '/') 192 lpathp++; /* skip leading slashes */ 193 q = lpathp; 194 while (*q != '/' && *q != '\0') 195 q++; /* find end of component */ 196 c = *q; 197 *q = '\0'; /* terminate component */ 198 199 /* Bail out early if opening root */ 200 if (r && (*lpathp == '\0')) 201 return ((ino_t)UFSROOTINO); 202 if ((inode = dlook(filep, lpathp)) != 0) { 203 if (openi(filep, inode)) 204 return ((ino_t)0); 205 if ((filep->fi_inode->i_smode & IFMT) == IFLNK) { 206 filep->fi_blocknum = 207 fsbtodb(&devp->un_fs.di_fs, 208 filep->fi_inode->i_db[0]); 209 filep->fi_count = DEV_BSIZE; 210 /* check the block cache */ 211 if ((filep->fi_memp = 212 get_bcache(filep)) == NULL) { 213 if (set_bcache(filep)) 214 return ((ino_t)0); 215 lufs_merge_deltas(filep); 216 } 217 len = strlen(filep->fi_memp); 218 if (filep->fi_memp[0] == '/') 219 /* absolute link */ 220 lpathp = lpath; 221 /* copy rest of unprocessed path up */ 222 bcopy(q, lpathp + len, strlen(q + 1) + 2); 223 /* point to unprocessed path */ 224 *(lpathp + len) = c; 225 /* prepend link in before unprocessed path */ 226 bcopy(filep->fi_memp, lpathp, len); 227 lpathp = lpath; 228 continue; 229 } else 230 *q = c; 231 if (c == '\0') 232 break; 233 lpathp = q; 234 continue; 235 } else { 236 return ((ino_t)0); 237 } 238 } 239 return (inode); 240 } 241 242 /* 243 * Map <file, file logical block> into a file system block number. 244 * Reads indirect blocks as needed to find the block. Returns zero when 245 * block isn't there; returns negative fsbn when block is uninitialized. 246 */ 247 static daddr32_t 248 sbmap(fileid_t *filep, daddr32_t bn) 249 { 250 struct inode *inodep; 251 int i, j, sh; 252 daddr32_t nb, *bap; 253 daddr32_t *db; 254 devid_t *devp; 255 256 devp = filep->fi_devp; 257 inodep = filep->fi_inode; 258 db = inodep->i_db; 259 260 /* 261 * blocks 0..NDADDR are direct blocks 262 */ 263 if (bn < NDADDR) { 264 nb = db[bn]; 265 return (nb); 266 } 267 268 /* 269 * addresses NIADDR have single and double indirect blocks. 270 * the first step is to determine how many levels of indirection. 271 */ 272 sh = 1; 273 bn -= NDADDR; 274 for (j = NIADDR; j > 0; j--) { 275 sh *= NINDIR(&devp->un_fs.di_fs); 276 if (bn < sh) 277 break; 278 bn -= sh; 279 } 280 if (j == 0) { 281 return ((daddr32_t)0); 282 } 283 284 /* 285 * fetch the first indirect block address from the inode 286 */ 287 nb = inodep->i_ib[NIADDR - j]; 288 if (nb == 0) { 289 return ((daddr32_t)0); 290 } 291 292 /* 293 * fetch through the indirect blocks 294 */ 295 for (; j <= NIADDR; j++) { 296 if (blknos[j] != nb) { 297 filep->fi_blocknum = fsbtodb(&devp->un_fs.di_fs, nb); 298 filep->fi_count = devp->un_fs.di_fs.fs_bsize; 299 /* First look through the disk block cache */ 300 if ((filep->fi_memp = get_bcache(filep)) == NULL) { 301 if (set_bcache(filep)) /* Gotta do I/O */ 302 return (0); 303 lufs_merge_deltas(filep); 304 } 305 b.blk[j] = filep->fi_memp; 306 blknos[j] = nb; 307 } 308 bap = (daddr32_t *)b.blk[j]; 309 sh /= NINDIR(&devp->un_fs.di_fs); 310 i = (bn / sh) % NINDIR(&devp->un_fs.di_fs); 311 nb = bap[i]; 312 if (nb == 0) { 313 return ((daddr32_t)0); 314 } 315 } 316 return (nb); 317 } 318 319 static ino_t 320 dlook(fileid_t *filep, char *path) 321 { 322 devid_t *devp = filep->fi_devp; 323 struct direct *dp; 324 struct inode *ip; 325 struct dirinfo dirp; 326 int len; 327 ino_t in; 328 #ifdef DEBUG 329 static int warned = 0; 330 #endif 331 332 ip = filep->fi_inode; 333 if (path == NULL || *path == '\0') 334 return (0); 335 if ((ip->i_smode & IFMT) != IFDIR) 336 return (0); 337 if (ip->i_size == 0) 338 return (0); 339 len = strlen(path); 340 341 /* 342 * First look through the directory entry cache 343 */ 344 if ((in = get_dcache(devp->di_dcookie, path, ip->i_number)) != 0) 345 return (in); 346 347 /* 348 * If the entire directory is cached, return failure 349 */ 350 if (ip->i_flag & FI_CACHED) 351 return (0); 352 353 /* 354 * Otherwise, read the entire directory into the cache 355 */ 356 in = 0; 357 dirp.loc = 0; 358 dirp.fi = filep; 359 if (!(ip->i_flag & FI_NOCACHE)) 360 ip->i_flag |= FI_CACHED; 361 for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) { 362 if (dp->d_ino == 0) 363 continue; 364 if (dp->d_namlen == len && strcmp(path, dp->d_name) == 0) 365 in = dp->d_ino; 366 367 /* 368 * Allow "*" to print all names at that level, w/out match 369 */ 370 if (strcmp(path, "*") == 0) 371 printf("%s\n", dp->d_name); 372 373 if (ip->i_flag & FI_NOCACHE) 374 continue; 375 376 /* 377 * Put this entry into the cache. If the entry has been 378 * partially cached, check before inserting. This should be 379 * rare if sized correctly 380 */ 381 if ((ip->i_flag & FI_PARTIAL_CACHE) && 382 (get_dcache(devp->di_dcookie, dp->d_name, dp->d_ino) != 0)) 383 continue; 384 385 if (set_rdcache(devp->di_dcookie, dp->d_name, ip->i_number, 386 dp->d_ino)) { 387 ip->i_flag &= ~FI_CACHED; 388 ip->i_flag |= FI_PARTIAL_CACHE; 389 #ifdef DEBUG 390 if (!warned) { 391 printf("ufsboot: directory cache too small\n"); 392 warned++; 393 } 394 #endif 395 } 396 } 397 return (in); 398 } 399 400 /* 401 * get next entry in a directory. 402 */ 403 struct direct * 404 readdir(struct dirinfo *dstuff) 405 { 406 struct direct *dp; 407 fileid_t *filep; 408 daddr32_t lbn, d; 409 int off; 410 devid_t *devp; 411 412 filep = dstuff->fi; 413 devp = filep->fi_devp; 414 for (;;) { 415 if (dstuff->loc >= filep->fi_inode->i_size) { 416 return (NULL); 417 } 418 off = blkoff(&devp->un_fs.di_fs, dstuff->loc); 419 if (off == 0) { 420 lbn = lblkno(&devp->un_fs.di_fs, dstuff->loc); 421 d = sbmap(filep, lbn); 422 423 if (d <= 0) 424 return (NULL); 425 426 filep->fi_blocknum = fsbtodb(&devp->un_fs.di_fs, d); 427 filep->fi_count = 428 blksize(&devp->un_fs.di_fs, filep->fi_inode, lbn); 429 /* check the block cache */ 430 if ((filep->fi_memp = get_bcache(filep)) == NULL) { 431 if (set_bcache(filep)) 432 return (NULL); 433 lufs_merge_deltas(filep); 434 } 435 } 436 dp = (struct direct *)(filep->fi_memp + off); 437 dstuff->loc += dp->d_reclen; 438 if (dp->d_ino == 0) 439 continue; 440 return (dp); 441 } 442 } 443 444 /* 445 * Get the next block of data from the file. If possible, dma right into 446 * user's buffer 447 */ 448 static int 449 getblock(fileid_t *filep, caddr_t buf, int count, int *rcount) 450 { 451 struct fs *fs; 452 caddr_t p; 453 int off, size, diff, zeroize; 454 daddr32_t lbn, fsbn; 455 devid_t *devp; 456 static int pos; 457 static char ind[] = "|/-\\"; /* that's entertainment? */ 458 static int blks_read; 459 devp = filep->fi_devp; 460 p = filep->fi_memp; 461 if ((signed)filep->fi_count <= 0) { 462 463 /* find the amt left to be read in the file */ 464 diff = filep->fi_inode->i_size - filep->fi_offset; 465 if (diff <= 0) { 466 printf("Short read\n"); 467 return (-1); 468 } 469 470 fs = &devp->un_fs.di_fs; 471 /* which block (or frag) in the file do we read? */ 472 lbn = lblkno(fs, filep->fi_offset); 473 474 /* which physical block on the device do we read? */ 475 fsbn = sbmap(filep, lbn); 476 477 /* 478 * zero fsbn -> unallocated hole. 479 * negative fsbn -> allocated but uninitialized. 480 * since we only read from the fs, treat both the same. 481 */ 482 zeroize = (fsbn <= 0); 483 484 filep->fi_blocknum = fsbtodb(fs, fsbn); 485 486 off = blkoff(fs, filep->fi_offset); 487 488 /* either blksize or fragsize */ 489 size = blksize(fs, filep->fi_inode, lbn); 490 filep->fi_count = size; 491 filep->fi_memp = filep->fi_buf; 492 493 /* 494 * optimization if we are reading large blocks of data then 495 * we can go directly to user's buffer 496 */ 497 *rcount = 0; 498 if (off == 0 && count >= size) { 499 filep->fi_memp = buf; 500 if (zeroize) { 501 bzero(buf, size); 502 } else if (diskread(filep)) { 503 return (-1); 504 } 505 *rcount = size; 506 filep->fi_count = 0; 507 read_opt++; 508 if ((blks_read++ & 0x3) == 0) 509 printf("%c\b", ind[pos++ & 3]); 510 return (0); 511 } else { 512 if (zeroize) { 513 bzero(filep->fi_memp, size); 514 } else if (diskread(filep)) 515 return (-1); 516 } 517 518 /* 519 * round and round she goes (though not on every block.. 520 * - OBP's take a fair bit of time to actually print stuff) 521 * On x86, the screen oriented bootconf program doesn't 522 * want this noise... 523 */ 524 if ((blks_read++ & 0x3) == 0) 525 printf("%c\b", ind[pos++ & 3]); 526 527 if (filep->fi_offset - off + size >= filep->fi_inode->i_size) 528 filep->fi_count = diff + off; 529 filep->fi_count -= off; 530 p = &filep->fi_memp[off]; 531 } 532 filep->fi_memp = p; 533 return (0); 534 } 535 536 537 /* 538 * This is the high-level read function. It works like this. 539 * We assume that our IO device buffers up some amount of 540 * data and that we can get a ptr to it. Thus we need 541 * to actually call the device func about filesize/blocksize times 542 * and this greatly increases our IO speed. When we already 543 * have data in the buffer, we just return that data (with bcopy() ). 544 */ 545 546 static ssize_t 547 boot_ufs_read(int fd, caddr_t buf, size_t count) 548 { 549 size_t i, j; 550 caddr_t n; 551 int rcount; 552 fileid_t *filep; 553 554 if (!(filep = find_fp(fd))) { 555 return (-1); 556 } 557 558 if (filep->fi_offset + count > filep->fi_inode->i_size) 559 count = filep->fi_inode->i_size - filep->fi_offset; 560 561 /* that was easy */ 562 if ((i = count) == 0) 563 return (0); 564 565 n = buf; 566 while (i > 0) { 567 /* If we need to reload the buffer, do so */ 568 if ((j = filep->fi_count) == 0) { 569 getblock(filep, buf, i, &rcount); 570 i -= rcount; 571 buf += rcount; 572 filep->fi_offset += rcount; 573 } else { 574 /* else just bcopy from our buffer */ 575 j = MIN(i, j); 576 bcopy(filep->fi_memp, buf, (unsigned)j); 577 buf += j; 578 filep->fi_memp += j; 579 filep->fi_offset += j; 580 filep->fi_count -= j; 581 i -= j; 582 } 583 } 584 return (buf - n); 585 } 586 587 /* 588 * This routine will open a device as it is known by the V2 OBP. 589 * Interface Defn: 590 * err = boot_ufs_mountroot(string); 591 * err = 0 on success 592 * err = -1 on failure 593 * string: char string describing the properties of the device. 594 * We must not dork with any fi[]'s here. Save that for later. 595 */ 596 597 static int 598 boot_ufs_mountroot(char *str) 599 { 600 int h; 601 602 /* 603 * Open the device and setup the read of the ufs superblock 604 * only the first time mountroot is called. Subsequent calls 605 * to mountroot succeed immediatly 606 */ 607 if (ufs_devp == NULL) { 608 609 /* 610 * Encode the knowledge that we normally boot from the 'a' 611 * slice of the leaf device on the OBP path; we also permit 612 * a 'nolabel' device, i.e. the entire device. Since v2path 613 * points to 'str' as well, changing str should have the 614 * desired result. 615 */ 616 if (strchr(str, ':') == NULL) { 617 (void) strcat(str, ":a"); 618 } 619 h = prom_open(str); 620 if (h == 0) { 621 printf("Cannot open %s\n", str); 622 return (-1); 623 } 624 625 ufs_devp = (devid_t *)bkmem_alloc(sizeof (devid_t)); 626 ufs_devp->di_taken = 1; 627 ufs_devp->di_dcookie = h; 628 ufs_devp->di_desc = (char *)bkmem_alloc(strlen(str) + 1); 629 (void) strcpy(ufs_devp->di_desc, str); 630 bzero(ufs_devp->un_fs.dummy, SBSIZE); 631 head = (fileid_t *)bkmem_alloc(sizeof (fileid_t)); 632 head->fi_back = head->fi_forw = head; 633 head->fi_filedes = 0; 634 head->fi_taken = 0; 635 636 /* Setup read of the superblock */ 637 head->fi_devp = ufs_devp; 638 head->fi_blocknum = SBLOCK; 639 head->fi_count = (uint_t)SBSIZE; 640 head->fi_memp = (caddr_t)&(ufs_devp->un_fs.di_fs); 641 head->fi_offset = 0; 642 643 if (diskread(head) || 644 ufs_devp->un_fs.di_fs.fs_magic != FS_MAGIC) { 645 boot_ufs_closeall(1); 646 return (-1); 647 } 648 lufs_boot_init(head); 649 } 650 return (0); 651 } 652 653 /* 654 * Unmount the currently mounted root fs. In practice, this means 655 * closing all open files and releasing resources. All of this 656 * is done by boot_ufs_closeall(). 657 */ 658 659 int 660 boot_ufs_unmountroot(void) 661 { 662 if (ufs_devp == NULL) 663 return (-1); 664 665 boot_ufs_closeall(1); 666 667 return (0); 668 } 669 670 /* 671 * We allocate an fd here for use when talking 672 * to the file itself. 673 */ 674 675 /*ARGSUSED*/ 676 static int 677 boot_ufs_open(char *filename, int flags) 678 { 679 fileid_t *filep; 680 ino_t inode; 681 static int filedes = 1; 682 683 /* build and link a new file descriptor */ 684 filep = (fileid_t *)bkmem_alloc(sizeof (fileid_t)); 685 filep->fi_back = head->fi_back; 686 filep->fi_forw = head; 687 head->fi_back->fi_forw = filep; 688 head->fi_back = filep; 689 filep->fi_filedes = filedes++; 690 filep->fi_taken = 1; 691 filep->fi_path = (char *)bkmem_alloc(strlen(filename) + 1); 692 (void) strcpy(filep->fi_path, filename); 693 filep->fi_devp = ufs_devp; /* dev is already "mounted" */ 694 filep->fi_inode = NULL; 695 bzero(filep->fi_buf, MAXBSIZE); 696 697 inode = find(filep, filename); 698 if (inode == (ino_t)0) { 699 boot_ufs_close(filep->fi_filedes); 700 return (-1); 701 } 702 if (openi(filep, inode)) { 703 boot_ufs_close(filep->fi_filedes); 704 return (-1); 705 } 706 707 filep->fi_offset = filep->fi_count = 0; 708 709 return (filep->fi_filedes); 710 } 711 712 /* 713 * We don't do any IO here. 714 * We just play games with the device pointers. 715 */ 716 717 static off_t 718 boot_ufs_lseek(int fd, off_t addr, int whence) 719 { 720 fileid_t *filep; 721 722 /* Make sure user knows what file he is talking to */ 723 if (!(filep = find_fp(fd))) 724 return (-1); 725 726 switch (whence) { 727 case SEEK_CUR: 728 filep->fi_offset += addr; 729 break; 730 case SEEK_SET: 731 filep->fi_offset = addr; 732 break; 733 default: 734 case SEEK_END: 735 printf("ufs_lseek(): invalid whence value %d\n", whence); 736 break; 737 } 738 739 filep->fi_blocknum = addr / DEV_BSIZE; 740 filep->fi_count = 0; 741 742 return (0); 743 } 744 745 /* 746 * ufs_fstat() only supports size, mode, and times at present time. 747 */ 748 749 static int 750 boot_ufs_fstat(int fd, struct bootstat *stp) 751 { 752 fileid_t *filep; 753 struct inode *ip; 754 755 if (!(filep = find_fp(fd))) 756 return (-1); 757 758 ip = filep->fi_inode; 759 760 stp->st_mode = 0; 761 stp->st_size = 0; 762 763 if (ip == NULL) 764 return (0); 765 766 switch (ip->i_smode & IFMT) { 767 case IFDIR: 768 stp->st_mode = S_IFDIR; 769 break; 770 case IFLNK: 771 stp->st_mode = S_IFLNK; 772 break; 773 case IFREG: 774 stp->st_mode = S_IFREG; 775 break; 776 default: 777 break; 778 } 779 stp->st_size = ip->i_size; 780 stp->st_atim.tv_sec = ip->i_atime.tv_sec; 781 stp->st_atim.tv_nsec = ip->i_atime.tv_usec * 1000; 782 stp->st_mtim.tv_sec = ip->i_mtime.tv_sec; 783 stp->st_mtim.tv_nsec = ip->i_mtime.tv_usec * 1000; 784 stp->st_ctim.tv_sec = ip->i_ctime.tv_sec; 785 stp->st_ctim.tv_nsec = ip->i_ctime.tv_usec * 1000; 786 787 return (0); 788 } 789 790 static int 791 boot_ufs_close(int fd) 792 { 793 fileid_t *filep; 794 795 /* Make sure user knows what file he is talking to */ 796 if (!(filep = find_fp(fd))) 797 return (-1); 798 799 if (filep->fi_taken && (filep != head)) { 800 /* Clear the ranks */ 801 bkmem_free(filep->fi_path, strlen(filep->fi_path)+1); 802 filep->fi_blocknum = filep->fi_count = filep->fi_offset = 0; 803 filep->fi_memp = (caddr_t)0; 804 filep->fi_devp = 0; 805 filep->fi_taken = 0; 806 807 /* unlink and deallocate node */ 808 filep->fi_forw->fi_back = filep->fi_back; 809 filep->fi_back->fi_forw = filep->fi_forw; 810 bkmem_free((char *)filep, sizeof (fileid_t)); 811 812 return (0); 813 } else { 814 /* Big problem */ 815 printf("\nFile descrip %d not allocated!", fd); 816 return (-1); 817 } 818 } 819 820 /* closeall is now idempotent */ 821 /*ARGSUSED*/ 822 static void 823 boot_ufs_closeall(int flag) 824 { 825 fileid_t *filep = head; 826 827 if (ufs_devp == NULL) { 828 if (head) 829 prom_panic("boot_ufs_closeall: head != NULL.\n"); 830 return; 831 } 832 833 while ((filep = filep->fi_forw) != head) 834 if (filep->fi_taken) 835 if (boot_ufs_close(filep->fi_filedes)) 836 prom_panic("Filesystem may be inconsistent.\n"); 837 838 839 release_cache(ufs_devp->di_dcookie); 840 (void) prom_close(ufs_devp->di_dcookie); 841 ufs_devp->di_taken = 0; 842 if (verbosemode & print_cache_stats) 843 print_cache_data(); 844 lufs_closeall(); 845 bkmem_free((char *)ufs_devp, sizeof (devid_t)); 846 bkmem_free((char *)head, sizeof (fileid_t)); 847 ufs_devp = (devid_t *)NULL; 848 head = (fileid_t *)NULL; 849 } 850 851 static int 852 boot_ufs_getdents(int fd, struct dirent *dep, unsigned size) 853 { 854 /* 855 * Read directory entries from the file open on "fd" into the 856 * "size"-byte buffer at "dep" until the buffer is exhausted 857 * or we reach EOF on the directory. Returns the number of 858 * entries read. 859 */ 860 int n; 861 fileid_t *fp; 862 unsigned long oldoff, oldblok; 863 864 #define SLOP (sizeof (struct dirent) - offsetof(struct dirent, d_name[1])) 865 866 if (fp = find_fp(fd)) { 867 /* 868 * File is open, check type to make sure it's a directory. 869 */ 870 871 while ((fp->fi_inode->i_smode & IFMT) == IFLNK) { 872 /* 873 * If file is a symbolic link, we'll follow 874 * it JIC it points to a directory! 875 */ 876 fileid_t fx; 877 char pn[MAXPATHLEN]; 878 fp->fi_count = DEV_BSIZE; 879 fp->fi_blocknum = fsbtodb(&fp->fi_devp->un_fs.di_fs, 880 fp->fi_inode->i_db[0]); 881 882 /* 883 * Return failure if: 884 * (a) we get an I/O error reading the path name. 885 * (b) the path name points to a non-existant file, 886 * (c) we get an I/O error reading the target inode. 887 */ 888 if ((fp->fi_memp = get_bcache(fp)) == NULL) { 889 if (set_bcache(fp)) 890 return (-1); 891 lufs_merge_deltas(fp); 892 } 893 if (!(n = find(&fx, strcpy(pn, fp->fi_memp))) || 894 openi(fp = &fx, n)) { 895 return (-1); 896 } 897 } 898 899 if ((fp->fi_inode->i_smode & IFMT) == IFDIR) { 900 /* 901 * If target file is a directory, go ahead 902 * and read it. This consists of making 903 * repeated calls to readdir() until we reach 904 * end-of-file or run out of buffer space. 905 */ 906 int cnt = 0; 907 struct direct *dp; 908 struct dirinfo dir; 909 910 dir.fi = fp; 911 oldblok = fp->fi_blocknum; 912 dir.loc = oldoff = fp->fi_offset; 913 914 for (dp = readdir(&dir); dp; dp = readdir(&dir)) { 915 /* 916 * Read all directory entries in the file ... 917 */ 918 919 if (dp->d_ino) { 920 /* 921 * Next entry is valid. 922 * Compute name length and 923 * break loop if there's not 924 * enough space in the output 925 * buffer for the next entry. 926 * 927 * NOTE: "SLOP" is the number 928 * of bytes inserted into the 929 * dirent struct's "d_name" 930 * field by the compiler to 931 * preserve alignment. 932 */ 933 dep->d_ino = dp->d_ino; 934 n = strlen(dp->d_name); 935 n = roundup((sizeof (struct dirent) + 936 ((n > SLOP) ? n : 0)), 937 sizeof (off_t)); 938 939 if (n > size) 940 break; /* user buffer is full */ 941 942 oldblok = fp->fi_blocknum; 943 oldoff = dir.loc; 944 size -= n; 945 cnt += 1; 946 947 (void) strcpy(dep->d_name, dp->d_name); 948 dep->d_off = dir.loc; 949 dep->d_reclen = (ushort_t)n; 950 951 dep = (struct dirent *) 952 ((char *)dep + n); 953 } 954 } 955 /* 956 * Remember where we left off for next time 957 */ 958 fp->fi_blocknum = oldblok; 959 fp->fi_offset = oldoff; 960 961 return (cnt); 962 } 963 } 964 965 #undef SLOP 966 967 return (-1); 968 } 969