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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * Copyright 2025 MNX Cloud, Inc. 25 */ 26 27 /* 28 * Basic file system reading code for standalone I/O system. 29 * Simulates a primitive UNIX I/O system (read(), write(), open(), etc). 30 * Does not support writes. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/sysmacros.h> 35 #include <sys/vnode.h> 36 #include <sys/fs/ufs_fsdir.h> 37 #include <sys/fs/ufs_fs.h> 38 #include <sys/fs/ufs_inode.h> 39 40 #include <sys/fs/hsfs_spec.h> 41 #include <sys/fs/hsfs_isospec.h> 42 #include <sys/fs/hsfs_node.h> 43 #include <sys/fs/hsfs_susp.h> 44 #include <sys/fs/hsfs_rrip.h> 45 #include <sys/bootvfs.h> 46 #include <sys/kobj.h> 47 #include <sys/filep.h> 48 #include <sys/sunddi.h> 49 50 #define hdbtodb(n) ((ISO_SECTOR_SIZE / DEV_BSIZE) * (n)) 51 52 #define HSFS_NUM_SIG 14 53 54 #define SUSP_SP_IX 0 55 #define SUSP_CE_IX 1 56 #define SUSP_PD_IX 2 57 #define SUSP_ST_IX 3 58 #define SUSP_ER_IX 4 59 #define RRIP_PX_IX 5 60 #define RRIP_PN_IX 6 61 #define RRIP_SL_IX 7 62 #define RRIP_CL_IX 8 63 #define RRIP_PL_IX 9 64 #define RRIP_RE_IX 10 65 #define RRIP_RF_IX 11 66 #define RRIP_RR_IX 12 67 #define RRIP_NM_IX 13 68 69 extern int bootrd_debug; 70 extern void *bkmem_alloc(size_t); 71 extern void bkmem_free(void *, size_t); 72 extern int cf_check_compressed(fileid_t *); 73 extern void cf_close(fileid_t *); 74 extern void cf_seek(fileid_t *, off_t, int); 75 extern int cf_read(fileid_t *, caddr_t, size_t); 76 77 struct dirstuff { 78 int loc; 79 fileid_t *filep; 80 }; 81 82 struct hs_direct { 83 struct direct hs_ufs_dir; 84 struct hs_direntry hs_dir; 85 }; 86 87 static uint_t root_ino = 0; 88 static struct hs_volume *hsfsp; 89 static fileid_t *head; 90 91 static char *hsfs_sig_tab[] = { 92 SUSP_SP, 93 SUSP_CE, 94 SUSP_PD, 95 SUSP_ST, 96 SUSP_ER, 97 RRIP_PX, 98 RRIP_PN, 99 RRIP_SL, 100 RRIP_CL, 101 RRIP_PL, 102 RRIP_RE, 103 RRIP_TF, 104 RRIP_RR, 105 RRIP_NM 106 }; 107 108 static int hsfs_num_sig = sizeof (hsfs_sig_tab) / sizeof (hsfs_sig_tab[0]); 109 110 /* 111 * Local prototypes 112 */ 113 static struct hs_direct *readdir(struct dirstuff *); 114 static uint_t parse_dir(fileid_t *, int, struct hs_direct *); 115 static uint_t parse_susp(char *, uint_t *, struct hs_direct *); 116 static ino_t dlook(char *, fileid_t *); 117 static int opendir(ino_t, fileid_t *); 118 static ino_t find(char *, fileid_t *); 119 120 static int bhsfs_mountroot(char *str); 121 static int bhsfs_unmountroot(void); 122 static int bhsfs_open(char *str, int flags); 123 static int bhsfs_close(int fd); 124 static void bhsfs_closeall(void); 125 static ssize_t bhsfs_read(int fdesc, char *buf, size_t count); 126 static off_t bhsfs_lseek(int fdesc, off_t addr, int whence); 127 static int bhsfs_fstat(int fdesc, struct bootstat *stp); 128 129 static fileid_t * 130 find_fp(int fd) 131 { 132 fileid_t *filep = head; 133 134 if (fd >= 0) { 135 while ((filep = filep->fi_forw) != head) 136 if (fd == filep->fi_filedes) 137 return (filep->fi_taken ? filep : 0); 138 } 139 140 return (0); 141 } 142 143 static int 144 opendir(ino_t inode, fileid_t *filep) 145 { 146 struct hs_direct hsdep; 147 148 if (bootrd_debug) 149 kobj_printf("opendir: inode = %ld\n", inode); 150 /* Set up the IO request */ 151 filep->fi_offset = 0; 152 filep->fi_blocknum = hdbtodb(inode); 153 filep->fi_count = ISO_SECTOR_SIZE; 154 filep->fi_memp = 0; 155 156 if (diskread(filep)) 157 return (0); 158 159 filep->fi_offset = 0; 160 filep->fi_blocknum = hdbtodb(inode); 161 162 if (inode != root_ino) 163 return (0); 164 165 if (parse_dir(filep, 0, &hsdep) > 0) { 166 struct inode *ip; 167 168 ip = filep->fi_inode; 169 if (ip == NULL) 170 ip = filep->fi_inode = bkmem_alloc(sizeof (*ip)); 171 172 ip->i_size = hsdep.hs_dir.ext_size; 173 ip->i_smode = hsdep.hs_dir.mode; 174 ip->i_number = inode; 175 return (0); 176 } 177 return (1); 178 } 179 180 static ino_t 181 find(char *path, fileid_t *filep) 182 { 183 char *q; 184 char c; 185 ino_t n; 186 187 n = 0; 188 if (bootrd_debug) 189 kobj_printf("find: %s\n", path); 190 if (path == NULL || *path == '\0') 191 return (0); 192 193 if (opendir(root_ino, filep)) 194 return (0); 195 196 while (*path) { 197 while (*path == '/') 198 path++; 199 q = path; 200 while (*q != '/' && *q != '\0') 201 q++; 202 c = *q; 203 *q = '\0'; 204 n = dlook(path, filep); 205 *q = c; 206 path = q; 207 208 if (n != 0) { 209 if (c == '\0') 210 break; 211 if (opendir(n, filep)) 212 return (0); 213 continue; 214 } else { 215 return (0); 216 } 217 } 218 return ((ino_t)n); 219 } 220 221 static ino_t 222 dlook(char *s, fileid_t *filep) 223 { 224 struct hs_direct *hsdep; 225 struct direct *udp; 226 struct inode *ip; 227 struct dirstuff dirp; 228 int len; 229 230 if (bootrd_debug) 231 kobj_printf("dlook: %s\n", s); 232 ip = filep->fi_inode; 233 if (s == NULL || *s == '\0') 234 return (0); 235 if ((ip->i_smode & IFMT) != IFDIR) { 236 return (0); 237 } 238 if (ip->i_size == 0) { 239 return (0); 240 } 241 len = strlen(s); 242 dirp.loc = 0; 243 dirp.filep = filep; 244 for (hsdep = readdir(&dirp); hsdep != NULL; hsdep = readdir(&dirp)) { 245 udp = &hsdep->hs_ufs_dir; 246 if (udp->d_namlen == 1 && 247 udp->d_name[0] == '.' && 248 udp->d_name[1] == '\0') 249 continue; 250 if (udp->d_namlen == 2 && 251 udp->d_name[0] == '.' && 252 udp->d_name[1] == '.' && 253 udp->d_name[2] == '\0') 254 continue; 255 if (udp->d_namlen == len && (strcmp(s, udp->d_name)) == 0) { 256 struct inode *ip = filep->fi_inode; 257 258 filep->fi_offset = 0; 259 filep->fi_blocknum = hdbtodb(udp->d_ino); 260 261 bzero(filep->fi_inode, sizeof (struct inode)); 262 ip->i_size = hsdep->hs_dir.ext_size; 263 ip->i_smode = hsdep->hs_dir.mode; 264 ip->i_number = udp->d_ino; 265 return (udp->d_ino); 266 } 267 } 268 return (0); 269 } 270 271 /* 272 * get next entry in a directory. 273 */ 274 static struct hs_direct * 275 readdir(struct dirstuff *dirp) 276 { 277 static struct hs_direct hsdep; 278 struct direct *udp = &hsdep.hs_ufs_dir; 279 struct inode *ip; 280 fileid_t *filep; 281 daddr_t lbn; 282 int off; 283 284 if (bootrd_debug) 285 kobj_printf("readdir: start\n"); 286 filep = dirp->filep; 287 ip = filep->fi_inode; 288 for (;;) { 289 if (dirp->loc >= ip->i_size) { 290 return (NULL); 291 } 292 off = dirp->loc & ((1 << ISO_SECTOR_SHIFT) - 1); 293 if (off == 0) { 294 lbn = hdbtodb(dirp->loc >> ISO_SECTOR_SHIFT); 295 filep->fi_blocknum = lbn + hdbtodb(ip->i_number); 296 filep->fi_count = ISO_SECTOR_SIZE; 297 filep->fi_memp = 0; 298 if (diskread(filep)) { 299 if (bootrd_debug) { 300 kobj_printf( 301 "readdir: diskread failed\n"); 302 } 303 return (NULL); 304 } 305 } 306 dirp->loc += parse_dir(filep, off, &hsdep); 307 if (udp->d_reclen == 0 && dirp->loc <= ip->i_size) { 308 dirp->loc = roundup(dirp->loc, ISO_SECTOR_SIZE); 309 continue; 310 } 311 return (&hsdep); 312 } 313 } 314 315 static int 316 getblock(fileid_t *filep) 317 { 318 struct inode *ip = filep->fi_inode; 319 int off, size, diff; 320 daddr_t lbn; 321 322 if (bootrd_debug) 323 kobj_printf("getblock: start\n"); 324 diff = ip->i_size - filep->fi_offset; 325 if (diff <= 0) 326 return (-1); 327 328 /* which block (or frag) in the file do we read? */ 329 lbn = hdbtodb(filep->fi_offset >> ISO_SECTOR_SHIFT); 330 filep->fi_blocknum = lbn + hdbtodb(ip->i_number); 331 332 off = filep->fi_offset & ((1 << ISO_SECTOR_SHIFT) - 1); 333 size = filep->fi_count = ISO_SECTOR_SIZE; 334 filep->fi_memp = 0; 335 if (diskread(filep)) /* Trap errors */ 336 return (-1); 337 338 if (filep->fi_offset - off + size >= ip->i_size) 339 filep->fi_count = diff + off; 340 filep->fi_count -= off; 341 filep->fi_memp += off; 342 if (bootrd_debug) 343 kobj_printf("getblock: end\n"); 344 return (0); 345 } 346 347 static ssize_t 348 bhsfs_read(int fd, caddr_t buf, size_t count) 349 { 350 int i, j; 351 fileid_t *filep; 352 struct inode *ip; 353 caddr_t n; 354 355 if (bootrd_debug) 356 kobj_printf("bhsfs_read %d, count 0x%lx\n", fd, count); 357 filep = find_fp(fd); 358 if (filep == NULL) 359 return (-1); 360 361 ip = filep->fi_inode; 362 n = buf; 363 if ((filep->fi_flags & FI_COMPRESSED) == 0 && 364 filep->fi_offset + count > ip->i_size) 365 count = ip->i_size - filep->fi_offset; 366 367 if ((i = count) <= 0) 368 return (0); 369 370 while (i > 0) { 371 if (filep->fi_flags & FI_COMPRESSED) { 372 if ((j = cf_read(filep, buf, count)) < 0) 373 return (0); /* encountered an error */ 374 if (j < i) 375 i = j; /* short read, must have hit EOF */ 376 } else { 377 if (filep->fi_count == 0) { 378 if (getblock(filep) == -1) 379 return (0); 380 } 381 j = MIN(i, filep->fi_count); 382 bcopy(filep->fi_memp, buf, (uint_t)j); 383 } 384 filep->fi_memp += j; 385 filep->fi_offset += j; 386 filep->fi_count -= j; 387 buf += j; 388 i -= j; 389 } 390 391 if (bootrd_debug) 392 kobj_printf("bhsfs_read: read 0x%x\n", (int)(buf - n)); 393 return (buf - n); 394 } 395 396 static int 397 bhsfs_mountroot(char *str __unused) 398 { 399 char *bufp; 400 401 if (hsfsp != NULL) 402 return (0); /* already mounted */ 403 404 if (bootrd_debug) 405 kobj_printf("mounting ramdisk as hsfs\n"); 406 407 hsfsp = bkmem_alloc(sizeof (*hsfsp)); 408 bzero(hsfsp, sizeof (*hsfsp)); 409 head = bkmem_alloc(sizeof (*head)); 410 bzero(head, sizeof (*head)); 411 head->fi_back = head->fi_forw = head; 412 413 /* now read the superblock. */ 414 head->fi_blocknum = hdbtodb(ISO_VOLDESC_SEC); 415 head->fi_offset = 0; 416 head->fi_count = ISO_SECTOR_SIZE; 417 head->fi_memp = head->fi_buf; 418 if (diskread(head)) { 419 kobj_printf("failed to read superblock\n"); 420 bhsfs_closeall(); 421 return (-1); 422 } 423 424 /* Since RRIP is based on ISO9660, that's where we start */ 425 bufp = head->fi_buf; 426 if ((ISO_DESC_TYPE(bufp) != ISO_VD_PVD) || 427 (strncmp((const char *)ISO_std_id(bufp), ISO_ID_STRING, 428 ISO_ID_STRLEN) != 0) || (ISO_STD_VER(bufp) != ISO_ID_VER)) { 429 if (bootrd_debug) 430 kobj_printf("volume type does not match\n"); 431 bhsfs_closeall(); 432 return (-1); 433 } 434 435 /* Now we fill in the volume descriptor */ 436 hsfsp->vol_size = ISO_VOL_SIZE(bufp); 437 hsfsp->lbn_size = ISO_BLK_SIZE(bufp); 438 hsfsp->lbn_shift = ISO_SECTOR_SHIFT; 439 hsfsp->lbn_secshift = ISO_SECTOR_SHIFT; 440 hsfsp->vol_set_size = (ushort_t)ISO_SET_SIZE(bufp); 441 hsfsp->vol_set_seq = (ushort_t)ISO_SET_SEQ(bufp); 442 443 /* Make sure we have a valid logical block size */ 444 if (hsfsp->lbn_size & ~(1 << hsfsp->lbn_shift)) { 445 kobj_printf("%d invalid logical block size\n", hsfsp->lbn_size); 446 bhsfs_closeall(); 447 return (-1); 448 } 449 450 /* Since an HSFS root could be located anywhere on the media! */ 451 root_ino = IDE_EXT_LBN(ISO_root_dir(bufp)); 452 return (0); 453 } 454 455 static int 456 bhsfs_unmountroot(void) 457 { 458 if (hsfsp == NULL) 459 return (-1); 460 461 bhsfs_closeall(); 462 463 return (0); 464 } 465 466 /* 467 * Open a file. 468 */ 469 int 470 bhsfs_open(char *str, int flags __unused) 471 { 472 static int filedes = 1; 473 474 fileid_t *filep; 475 ino_t ino; 476 477 if (bootrd_debug) 478 kobj_printf("open %s\n", str); 479 filep = (fileid_t *)bkmem_alloc(sizeof (fileid_t)); 480 filep->fi_back = head->fi_back; 481 filep->fi_forw = head; 482 head->fi_back->fi_forw = filep; 483 head->fi_back = filep; 484 filep->fi_filedes = filedes++; 485 filep->fi_taken = 1; 486 filep->fi_path = (char *)bkmem_alloc(strlen(str) + 1); 487 (void) strcpy(filep->fi_path, str); 488 filep->fi_inode = NULL; 489 bzero(filep->fi_buf, MAXBSIZE); 490 filep->fi_getblock = getblock; 491 filep->fi_flags = 0; 492 493 ino = find(str, filep); 494 if (ino == 0) { 495 (void) bhsfs_close(filep->fi_filedes); 496 return (-1); 497 } 498 499 filep->fi_blocknum = hdbtodb(ino); 500 filep->fi_offset = 0; 501 filep->fi_count = 0; 502 filep->fi_memp = 0; 503 504 if (cf_check_compressed(filep) != 0) 505 return (-1); 506 if (bootrd_debug) 507 kobj_printf("open done\n"); 508 return (filep->fi_filedes); 509 } 510 511 int 512 bhsfs_close(int fd) 513 { 514 fileid_t *filep; 515 516 if (bootrd_debug) 517 kobj_printf("close %d\n", fd); 518 if (!(filep = find_fp(fd))) 519 return (-1); 520 521 if (filep->fi_taken == 0 || filep == head) { 522 kobj_printf("File descripter %d not allocated!\n", fd); 523 return (-1); 524 } 525 526 cf_close(filep); 527 /* unlink and deallocate node */ 528 filep->fi_forw->fi_back = filep->fi_back; 529 filep->fi_back->fi_forw = filep->fi_forw; 530 if (filep->fi_inode) 531 bkmem_free(filep->fi_inode, sizeof (struct inode)); 532 bkmem_free(filep->fi_path, strlen(filep->fi_path) + 1); 533 bkmem_free((char *)filep, sizeof (fileid_t)); 534 if (bootrd_debug) 535 kobj_printf("close done\n"); 536 return (0); 537 } 538 539 static void 540 bhsfs_closeall(void) 541 { 542 fileid_t *filep; 543 544 while ((filep = head->fi_forw) != head) 545 if (filep->fi_taken && bhsfs_close(filep->fi_filedes)) 546 kobj_printf("Filesystem may be inconsistent.\n"); 547 548 bkmem_free(hsfsp, sizeof (*hsfsp)); 549 bkmem_free(head, sizeof (fileid_t)); 550 hsfsp = NULL; 551 head = NULL; 552 } 553 554 /* 555 * This version of seek() only performs absolute seeks (whence == 0). 556 */ 557 static off_t 558 bhsfs_lseek(int fd, off_t addr, int whence) 559 { 560 fileid_t *filep; 561 562 if (bootrd_debug) 563 kobj_printf("lseek %d, off = %lx\n", fd, addr); 564 if (!(filep = find_fp(fd))) 565 return (-1); 566 567 if (filep->fi_flags & FI_COMPRESSED) { 568 cf_seek(filep, addr, whence); 569 } else { 570 switch (whence) { 571 case SEEK_CUR: 572 filep->fi_offset += addr; 573 break; 574 case SEEK_SET: 575 filep->fi_offset = addr; 576 break; 577 default: 578 case SEEK_END: 579 kobj_printf("lseek(): invalid whence value %d\n", 580 whence); 581 break; 582 } 583 filep->fi_blocknum = addr / DEV_BSIZE; 584 } 585 586 filep->fi_count = 0; 587 return (0); 588 } 589 590 static int 591 bhsfs_fstat(int fd, struct bootstat *stp) 592 { 593 fileid_t *filep; 594 struct inode *ip; 595 596 if (!(filep = find_fp(fd))) 597 return (-1); 598 599 ip = filep->fi_inode; 600 601 stp->st_mode = 0; 602 stp->st_size = 0; 603 604 if (ip == NULL) 605 return (0); 606 607 switch (ip->i_smode & IFMT) { 608 case IFDIR: 609 stp->st_mode = S_IFDIR; 610 break; 611 case IFREG: 612 stp->st_mode = S_IFREG; 613 break; 614 default: 615 break; 616 } 617 /* 618 * NOTE: this size will be the compressed size for a compressed file 619 * This could confuse the caller since we decompress the file behind 620 * the scenes when the file is read. 621 */ 622 stp->st_size = ip->i_size; 623 624 /* file times */ 625 stp->st_atim.tv_sec = ip->i_atime.tv_sec; 626 stp->st_atim.tv_nsec = ip->i_atime.tv_usec * 1000; 627 stp->st_mtim.tv_sec = ip->i_mtime.tv_sec; 628 stp->st_mtim.tv_nsec = ip->i_mtime.tv_usec * 1000; 629 stp->st_ctim.tv_sec = ip->i_ctime.tv_sec; 630 stp->st_ctim.tv_nsec = ip->i_ctime.tv_usec * 1000; 631 632 return (0); 633 634 } 635 636 637 /* 638 * Parse a directory entry. 639 * 640 */ 641 static uint_t 642 parse_dir(fileid_t *filep, int offset, struct hs_direct *hsdep) 643 { 644 char *bufp = (char *)(filep->fi_memp + offset); 645 struct direct *udp = &hsdep->hs_ufs_dir; /* ufs-style dir info */ 646 struct hs_direntry *hdp = &hsdep->hs_dir; /* hsfs-style dir info */ 647 uint_t ce_lbn; 648 uint_t ce_len; 649 uint_t nmlen; 650 uint_t i; 651 uchar_t c; 652 653 if (bootrd_debug) 654 kobj_printf("parse_dir: offset = %d\n", offset); 655 /* a zero length dir entry terminates the dir block */ 656 udp->d_reclen = IDE_DIR_LEN(bufp); 657 if (udp->d_reclen == 0) 658 return (0); 659 660 /* fill in some basic hsfs info */ 661 hdp->ext_lbn = IDE_EXT_LBN(bufp); 662 hdp->ext_size = IDE_EXT_SIZE(bufp); 663 hdp->xar_len = IDE_XAR_LEN(bufp); 664 hdp->intlf_sz = IDE_INTRLV_SIZE(bufp); 665 hdp->intlf_sk = IDE_INTRLV_SKIP(bufp); 666 hdp->sym_link = NULL; 667 668 /* we use lbn of data extent as an inode # equivalent */ 669 udp->d_ino = hdp->ext_lbn; 670 671 c = IDE_FLAGS(bufp); 672 if (IDE_REGULAR_FILE(c)) { 673 hdp->type = VREG; 674 hdp->mode = IFREG; 675 hdp->nlink = 1; 676 } else if (IDE_REGULAR_DIR(c)) { 677 hdp->type = VDIR; 678 hdp->mode = IFDIR; 679 hdp->nlink = 2; 680 } else { 681 kobj_printf("pd(): file type=0x%x unknown.\n", c); 682 } 683 684 /* 685 * Massage hsfs name, recognizing special entries for . and .. 686 * else lopping off version junk. 687 */ 688 689 /* Some initial conditions */ 690 nmlen = IDE_NAME_LEN(bufp); 691 c = *IDE_NAME(bufp); 692 /* Special Case: Current Directory */ 693 if (nmlen == 1 && c == '\0') { 694 udp->d_name[0] = '.'; 695 udp->d_name[1] = '\0'; 696 udp->d_namlen = 1; 697 /* Special Case: Parent Directory */ 698 } else if (nmlen == 1 && c == '\001') { 699 udp->d_name[0] = '.'; 700 udp->d_name[1] = '.'; 701 udp->d_name[2] = '\0'; 702 udp->d_namlen = 2; 703 /* Other file name */ 704 } else { 705 udp->d_namlen = 0; 706 for (i = 0; i < nmlen; i++) { 707 c = *(IDE_name(bufp)+i); 708 if (c == ';') 709 break; 710 else if (c == ' ') 711 continue; 712 else 713 udp->d_name[udp->d_namlen++] = c; 714 } 715 udp->d_name[udp->d_namlen] = '\0'; 716 } 717 718 /* System Use Fields */ 719 ce_len = IDE_SUA_LEN(bufp); 720 721 if (ce_len == 0) 722 return (udp->d_reclen); 723 724 /* there is an SUA for this dir entry; go parse it */ 725 ce_lbn = parse_susp((char *)IDE_sys_use_area(bufp), &ce_len, hsdep); 726 727 if (ce_lbn) { 728 /* 729 * store away current position in dir, 730 * as we will be using the iobuf to reading SUA. 731 */ 732 daddr_t save_bn = filep->fi_blocknum; 733 daddr_t save_offset = filep->fi_offset; 734 caddr_t save_ma = filep->fi_memp; 735 int save_cc = filep->fi_count; 736 do { 737 filep->fi_count = ISO_SECTOR_SIZE; 738 filep->fi_offset = 0; 739 filep->fi_blocknum = hdbtodb(ce_lbn); 740 filep->fi_memp = 0; 741 if (diskread(filep)) { 742 kobj_printf("failed to read cont. area\n"); 743 ce_len = 0; 744 ce_lbn = 0; 745 break; 746 } 747 ce_lbn = parse_susp(filep->fi_memp, &ce_len, 748 hsdep); 749 } while (ce_lbn); 750 filep->fi_count = save_cc; 751 filep->fi_offset = save_offset; 752 filep->fi_blocknum = save_bn; 753 filep->fi_memp = save_ma; 754 } 755 return (udp->d_reclen); 756 } 757 758 /* 759 * Parse the System Use Fields in this System Use Area. 760 * Return blk number of continuation/SUA, or 0 if no continuation/not a SUA. 761 */ 762 static uint_t 763 parse_susp(char *bufp, uint_t *len, struct hs_direct *hsdep) 764 { 765 struct direct *udp = &hsdep->hs_ufs_dir; /* ufs-style info */ 766 char *susp; 767 uint_t cur_off = 0; 768 uint_t blk_len = *len; 769 uint_t susp_len = 0; 770 uint_t ce_lbn = 0; 771 uint_t i; 772 773 if (bootrd_debug) 774 kobj_printf("parse_susp: len = %d\n", *len); 775 while (cur_off < blk_len) { 776 susp = (char *)(bufp + cur_off); 777 778 /* 779 * A null entry, or an entry with zero length 780 * terminates the SUSP. 781 */ 782 if (susp[0] == '\0' || susp[1] == '\0' || 783 (susp_len = SUF_LEN(susp)) == 0) 784 break; 785 786 /* 787 * Compare current entry to all known signatures. 788 */ 789 for (i = 0; i < hsfs_num_sig; i++) 790 if (strncmp(hsfs_sig_tab[i], susp, SUF_SIG_LEN) == 0) 791 break; 792 switch (i) { 793 case SUSP_CE_IX: 794 /* 795 * CE signature: continuation of SUSP. 796 * will want to return new lbn, len. 797 */ 798 ce_lbn = CE_BLK_LOC(susp); 799 *len = CE_CONT_LEN(susp); 800 break; 801 case RRIP_NM_IX: 802 /* NM signature: POSIX-style file name */ 803 if (!RRIP_NAME_FLAGS(susp)) { 804 udp->d_namlen = RRIP_NAME_LEN(susp); 805 bcopy((char *)RRIP_name(susp), 806 udp->d_name, udp->d_namlen); 807 udp->d_name[udp->d_namlen] = '\0'; 808 } 809 break; 810 case HSFS_NUM_SIG: 811 /* couldn't find a legit susp, terminate loop */ 812 case SUSP_ST_IX: 813 /* ST signature: terminates SUSP */ 814 return (ce_lbn); 815 case SUSP_SP_IX: 816 case RRIP_RR_IX: 817 default: 818 break; 819 } 820 cur_off += susp_len; 821 } 822 return (ce_lbn); 823 } 824 825 struct boot_fs_ops bhsfs_ops = { 826 "boot_hsfs", 827 bhsfs_mountroot, 828 bhsfs_unmountroot, 829 bhsfs_open, 830 bhsfs_close, 831 bhsfs_read, 832 bhsfs_lseek, 833 bhsfs_fstat, 834 NULL 835 }; 836