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