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