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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 #include <stdio.h> 28 #include <string.h> 29 #include <strings.h> 30 #include <unistd.h> 31 #include <stdlib.h> 32 #include <thread.h> 33 #include <synch.h> 34 #include <sys/types.h> 35 #include <ctype.h> 36 #include <sys/stat.h> 37 #include <fcntl.h> 38 #include <sys/modctl.h> 39 #include <errno.h> 40 #include <sys/openpromio.h> 41 #include <ftw.h> 42 #include <sys/ddi.h> 43 #include <sys/sunddi.h> 44 #include <limits.h> 45 46 #include "device_info.h" 47 48 /* 49 * #define's 50 */ 51 52 /* alias node searching return values */ 53 #define NO_MATCH -1 54 #define EXACT_MATCH 1 55 #define INEXACT_MATCH 2 56 57 /* for prom io operations */ 58 #define BUFSIZE 4096 59 #define MAXPROPSIZE 256 60 #define MAXVALSIZE (BUFSIZE - MAXPROPSIZE - sizeof (uint_t)) 61 62 /* prom_obp_vers() return values */ 63 #define OBP_OF 0x4 /* versions OBP 3.x */ 64 #define OBP_NO_ALIAS_NODE 0x8 /* No alias node */ 65 66 /* for nftw call */ 67 #define FT_DEPTH 15 68 69 /* default logical and physical device name space */ 70 #define DEV "/dev" 71 #define DEVICES "/devices" 72 73 /* for boot device identification on x86 */ 74 #define CREATE_DISKMAP "/boot/solaris/bin/create_diskmap" 75 #define GRUBDISK_MAP "/var/run/solaris_grubdisk.map" 76 77 /* 78 * internal structure declarations 79 */ 80 81 /* for prom io functions */ 82 typedef union { 83 char buf[BUFSIZE]; 84 struct openpromio opp; 85 } Oppbuf; 86 87 /* used to manage lists of devices and aliases */ 88 struct name_list { 89 char *name; 90 struct name_list *next; 91 }; 92 93 /* 94 * internal global data 95 */ 96 97 /* global since nftw does not let you pass args to be updated */ 98 static struct name_list **dev_list; 99 100 /* global since nftw does not let you pass args to be updated */ 101 static struct boot_dev **bootdev_list; 102 103 /* mutex to protect bootdev_list and dev_list */ 104 static mutex_t dev_lists_lk = DEFAULTMUTEX; 105 106 /* 107 * internal function prototypes 108 */ 109 110 static int prom_open(int); 111 static void prom_close(int); 112 static int is_openprom(int); 113 114 static int prom_dev_to_alias(char *dev, uint_t options, char ***ret_buf); 115 static int alias_to_prom_dev(char *alias, char *ret_buf); 116 static int prom_srch_aliases_by_def(char *, struct name_list **, 117 struct name_list **, int); 118 static int prom_find_aliases_node(int fd); 119 static int prom_compare_devs(char *prom_dev1, char *prom_dev2); 120 static int _prom_strcmp(char *s1, char *s2); 121 static int prom_srch_node(int fd, char *prop_name, char *ret_buf); 122 static uint_t prom_next_node(int fd, uint_t node_id); 123 static uint_t prom_child_node(int fd, uint_t node_id); 124 125 static int prom_obp_vers(void); 126 127 static void parse_name(char *, char **, char **, char **); 128 static int process_bootdev(const char *, const char *, struct boot_dev ***); 129 static int process_minor_name(char *dev_path, const char *default_root); 130 static void options_override(char *prom_path, char *alias_name); 131 static int devfs_phys_to_logical(struct boot_dev **bootdev_array, 132 const int array_size, const char *default_root); 133 static int check_logical_dev(const char *, const struct stat *, int, 134 struct FTW *); 135 static struct boot_dev *alloc_bootdev(char *); 136 static void free_name_list(struct name_list *list, int free_name); 137 static int insert_alias_list(struct name_list **list, 138 char *alias_name); 139 static int get_boot_dev_var(struct openpromio *opp); 140 static int set_boot_dev_var(struct openpromio *opp, char *bootdev); 141 static int devfs_prom_to_dev_name(char *prom_path, char *dev_path); 142 static int devfs_dev_to_prom_names(char *dev_path, char *prom_path, size_t len); 143 144 /* 145 * frees a list of paths from devfs_get_prom_name_list 146 */ 147 static void 148 prom_list_free(char **prom_list) 149 { 150 int i = 0; 151 152 if (!prom_list) 153 return; 154 155 while (prom_list[i]) { 156 free(prom_list[i]); 157 i++; 158 } 159 free(prom_list); 160 } 161 162 static int 163 devfs_get_prom_name_list(const char *dev_name, char ***prom_list) 164 { 165 char *prom_path = NULL; 166 int count = 0; /* # of slots we will need in prom_list */ 167 int ret, i, len; 168 char **list; 169 char *ptr; 170 171 if (dev_name == NULL) 172 return (DEVFS_INVAL); 173 if (*dev_name != '/') 174 return (DEVFS_INVAL); 175 if (prom_list == NULL) 176 return (DEVFS_INVAL); 177 178 /* 179 * make sure we are on a machine which supports a prom 180 * and we have permission to use /dev/openprom 181 */ 182 if ((ret = prom_obp_vers()) < 0) 183 return (ret); 184 if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL) 185 return (DEVFS_NOMEM); 186 /* 187 * get the prom path name 188 */ 189 ret = devfs_dev_to_prom_names((char *)dev_name, prom_path, MAXVALSIZE); 190 if (ret < 0) { 191 free(prom_path); 192 return (ret); 193 } 194 /* deal with list of names */ 195 for (i = 0; i < ret; i++) 196 if (prom_path[i] == '\0') 197 count++; 198 199 if ((list = (char **)calloc(count + 1, sizeof (char *))) == NULL) { 200 free(prom_path); 201 return (DEVFS_NOMEM); 202 } 203 204 ptr = prom_path; 205 for (i = 0; i < count; i++) { 206 len = strlen(ptr) + 1; 207 if ((list[i] = (char *)malloc(len)) == NULL) { 208 free(prom_path); 209 free(list); 210 return (DEVFS_NOMEM); 211 } 212 (void) snprintf(list[i], len, "%s", ptr); 213 ptr += len; 214 } 215 216 free(prom_path); 217 218 *prom_list = list; 219 return (0); 220 } 221 222 /* 223 * retrieve the list of prom representations for a given device name 224 * the list will be sorted in the following order: exact aliases, 225 * inexact aliases, prom device path name. If multiple matches occur 226 * for exact or inexact aliases, then these are sorted in collating 227 * order. The list is returned in prom_list 228 * 229 * the list may be restricted by specifying the correct flags in options. 230 */ 231 int 232 devfs_get_prom_names(const char *dev_name, uint_t options, char ***prom_list) 233 { 234 char *prom_path = NULL; 235 int count = 0; /* # of slots we will need in prom_list */ 236 char **alias_list = NULL; 237 char **list; 238 int ret; 239 240 if (dev_name == NULL) { 241 return (DEVFS_INVAL); 242 } 243 if (*dev_name != '/') { 244 return (DEVFS_INVAL); 245 } 246 if (prom_list == NULL) { 247 return (DEVFS_INVAL); 248 } 249 /* 250 * make sure we are on a machine which supports a prom 251 * and we have permission to use /dev/openprom 252 */ 253 if ((ret = prom_obp_vers()) < 0) { 254 return (ret); 255 } 256 if ((prom_path = (char *)malloc(MAXPATHLEN)) == NULL) { 257 return (DEVFS_NOMEM); 258 } 259 /* 260 * get the prom path name 261 */ 262 ret = devfs_dev_to_prom_name((char *)dev_name, prom_path); 263 if (ret < 0) { 264 free(prom_path); 265 return (ret); 266 } 267 /* get the list of aliases (exact and inexact) */ 268 if ((ret = prom_dev_to_alias(prom_path, options, &alias_list)) < 0) { 269 free(prom_path); 270 return (ret); 271 } 272 /* now figure out how big the return array must be */ 273 if (alias_list != NULL) { 274 while (alias_list[count] != NULL) { 275 count++; 276 } 277 } 278 if ((options & BOOTDEV_NO_PROM_PATH) == 0) { 279 count++; /* # of slots we will need in prom_list */ 280 } 281 count++; /* for the null terminator */ 282 283 /* allocate space for the list */ 284 if ((list = (char **)calloc(count, sizeof (char *))) == NULL) { 285 count = 0; 286 while ((alias_list) && (alias_list[count] != NULL)) { 287 free(alias_list[count]); 288 count++; 289 } 290 free(alias_list); 291 free(prom_path); 292 return (DEVFS_NOMEM); 293 } 294 /* fill in the array and free the name list of aliases. */ 295 count = 0; 296 while ((alias_list) && (alias_list[count] != NULL)) { 297 list[count] = alias_list[count]; 298 count++; 299 } 300 if ((options & BOOTDEV_NO_PROM_PATH) == 0) { 301 list[count] = prom_path; 302 } 303 if (alias_list != NULL) { 304 free(alias_list); 305 } 306 *prom_list = list; 307 return (0); 308 } 309 310 /* 311 * Get a list prom-path translations for a solaris device. 312 * 313 * Returns the number of and all OBP paths and alias variants that 314 * reference the Solaris device path passed in. 315 */ 316 int 317 devfs_get_all_prom_names(const char *solaris_path, uint_t flags, 318 struct devfs_prom_path **paths) 319 { 320 int ret, len, i, count = 0; 321 char *ptr, *prom_path; 322 struct devfs_prom_path *cur = NULL, *new; 323 324 if ((ret = prom_obp_vers()) < 0) 325 return (ret); 326 if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL) 327 return (DEVFS_NOMEM); 328 329 if ((ret = devfs_dev_to_prom_names((char *)solaris_path, 330 prom_path, MAXVALSIZE)) < 0) { 331 free(prom_path); 332 return (ret); 333 } 334 335 for (i = 0; i < ret; i++) 336 if (prom_path[i] == '\0') 337 count++; 338 339 *paths = NULL; 340 ptr = prom_path; 341 for (i = 0; i < count; i++) { 342 if ((new = (struct devfs_prom_path *)calloc( 343 sizeof (struct devfs_prom_path), 1)) == NULL) { 344 free(prom_path); 345 devfs_free_all_prom_names(*paths); 346 return (DEVFS_NOMEM); 347 } 348 349 if (cur == NULL) 350 *paths = new; 351 else 352 cur->next = new; 353 cur = new; 354 355 len = strlen(ptr) + 1; 356 if ((cur->obp_path = (char *)calloc(len, 1)) == NULL) { 357 free(prom_path); 358 devfs_free_all_prom_names(*paths); 359 return (DEVFS_NOMEM); 360 } 361 362 (void) snprintf(cur->obp_path, len, "%s", ptr); 363 ptr += len; 364 if ((ret = prom_dev_to_alias(cur->obp_path, flags, 365 &(cur->alias_list))) < 0) { 366 free(prom_path); 367 devfs_free_all_prom_names(*paths); 368 return (ret); 369 } 370 } 371 372 free(prom_path); 373 return (count); 374 } 375 376 void 377 devfs_free_all_prom_names(struct devfs_prom_path *paths) 378 { 379 int i; 380 381 if (paths == NULL) 382 return; 383 384 devfs_free_all_prom_names(paths->next); 385 386 if (paths->obp_path != NULL) 387 free(paths->obp_path); 388 389 if (paths->alias_list != NULL) { 390 for (i = 0; paths->alias_list[i] != NULL; i++) 391 if (paths->alias_list[i] != NULL) 392 free(paths->alias_list[i]); 393 394 free(paths->alias_list); 395 } 396 397 free(paths); 398 } 399 400 /* 401 * Accepts a device name as an input argument. Uses this to set the 402 * boot-device (or like) variable 403 * 404 * By default, this routine prepends to the list and converts the 405 * logical device name to its most compact prom representation. 406 * Available options include: converting the device name to a prom 407 * path name (but not an alias) or performing no conversion at all; 408 * overwriting the existing contents of boot-device rather than 409 * prepending. 410 */ 411 int 412 devfs_bootdev_set_list(const char *dev_name, const uint_t options) 413 { 414 char *prom_path; 415 char *new_bootdev; 416 char *ptr; 417 char **alias_list = NULL; 418 char **prom_list = NULL; 419 Oppbuf oppbuf; 420 struct openpromio *opp = &(oppbuf.opp); 421 int ret, len, i, j; 422 423 if (devfs_bootdev_modifiable() != 0) { 424 return (DEVFS_NOTSUP); 425 } 426 if (dev_name == NULL) { 427 return (DEVFS_INVAL); 428 } 429 if (strlen(dev_name) >= MAXPATHLEN) 430 return (DEVFS_INVAL); 431 432 if ((*dev_name != '/') && !(options & BOOTDEV_LITERAL)) { 433 return (DEVFS_INVAL); 434 } 435 if ((options & BOOTDEV_LITERAL) && (options & BOOTDEV_PROMDEV)) { 436 return (DEVFS_INVAL); 437 } 438 /* 439 * if we are prepending, make sure that this obp rev 440 * supports multiple boot device entries. 441 */ 442 ret = prom_obp_vers(); 443 if (ret < 0) { 444 return (ret); 445 } 446 447 if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL) { 448 return (DEVFS_NOMEM); 449 } 450 if (options & BOOTDEV_LITERAL) { 451 (void) strcpy(prom_path, dev_name); 452 } else { 453 /* need to convert to prom representation */ 454 ret = devfs_get_prom_name_list(dev_name, &prom_list); 455 if (ret < 0) { 456 free(prom_path); 457 return (ret); 458 } 459 460 len = MAXVALSIZE; 461 i = 0; 462 ptr = prom_path; 463 while (prom_list && prom_list[i]) { 464 if (!(options & BOOTDEV_PROMDEV)) { 465 ret = prom_dev_to_alias(prom_list[i], 0, 466 &alias_list); 467 if (ret < 0) { 468 free(prom_path); 469 prom_list_free(prom_list); 470 return (ret); 471 } 472 if ((alias_list != NULL) && 473 (alias_list[0] != NULL)) { 474 (void) snprintf(ptr, len, "%s ", 475 alias_list[0]); 476 for (ret = 0; alias_list[ret] != NULL; 477 ret++) 478 free(alias_list[ret]); 479 } else { 480 (void) snprintf(ptr, len, "%s ", 481 prom_list[i]); 482 } 483 if (alias_list != NULL) 484 free(alias_list); 485 } else { 486 (void) snprintf(ptr, len, "%s ", prom_list[i]); 487 } 488 j = strlen(ptr); 489 len -= j; 490 ptr += j; 491 i++; 492 } 493 ptr--; 494 *ptr = NULL; 495 496 prom_list_free(prom_list); 497 } 498 if (options & BOOTDEV_OVERWRITE) { 499 new_bootdev = prom_path; 500 } else { 501 /* retrieve the current value of boot-device */ 502 ret = get_boot_dev_var(opp); 503 if (ret < 0) { 504 free(prom_path); 505 return (ret); 506 } 507 /* prepend new entry - deal with duplicates */ 508 new_bootdev = (char *)malloc(strlen(opp->oprom_array) 509 + strlen(prom_path) + 2); 510 if (new_bootdev == NULL) { 511 free(prom_path); 512 return (DEVFS_NOMEM); 513 } 514 (void) strcpy(new_bootdev, prom_path); 515 if (opp->oprom_size > 0) { 516 for (ptr = strtok(opp->oprom_array, " "); ptr != NULL; 517 ptr = strtok(NULL, " ")) { 518 /* we strip out duplicates */ 519 if (strcmp(prom_path, ptr) == 0) { 520 continue; 521 } 522 (void) strcat(new_bootdev, " "); 523 (void) strcat(new_bootdev, ptr); 524 } 525 } 526 } 527 528 /* now set the new value */ 529 ret = set_boot_dev_var(opp, new_bootdev); 530 531 if (options & BOOTDEV_OVERWRITE) { 532 free(prom_path); 533 } else { 534 free(new_bootdev); 535 free(prom_path); 536 } 537 538 return (ret); 539 } 540 541 /* 542 * sets the string bootdev as the new value for boot-device 543 */ 544 static int 545 set_boot_dev_var(struct openpromio *opp, char *bootdev) 546 { 547 int prom_fd; 548 int i; 549 int ret; 550 char *valbuf; 551 char *save_bootdev; 552 char *bootdev_variables[] = { 553 "boot-device", 554 "bootdev", 555 "boot-from", 556 NULL 557 }; 558 int found = 0; 559 int *ip = (int *)((void *)opp->oprom_array); 560 561 /* query the prom */ 562 prom_fd = prom_open(O_RDWR); 563 if (prom_fd < 0) { 564 return (prom_fd); 565 } 566 567 /* get the diagnostic-mode? property */ 568 (void) strcpy(opp->oprom_array, "diagnostic-mode?"); 569 opp->oprom_size = MAXVALSIZE; 570 if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) { 571 if ((opp->oprom_size > 0) && 572 (strcmp(opp->oprom_array, "true") == 0)) { 573 prom_close(prom_fd); 574 return (DEVFS_ERR); 575 } 576 } 577 /* get the diag-switch? property */ 578 (void) strcpy(opp->oprom_array, "diag-switch?"); 579 opp->oprom_size = MAXVALSIZE; 580 if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) { 581 if ((opp->oprom_size > 0) && 582 (strcmp(opp->oprom_array, "true") == 0)) { 583 prom_close(prom_fd); 584 return (DEVFS_ERR); 585 } 586 } 587 /* 588 * look for one of the following properties in order: 589 * boot-device 590 * bootdev 591 * boot-from 592 * 593 * Use the first one that we find. 594 */ 595 *ip = 0; 596 opp->oprom_size = MAXPROPSIZE; 597 while ((opp->oprom_size != 0) && (!found)) { 598 opp->oprom_size = MAXPROPSIZE; 599 if (ioctl(prom_fd, OPROMNXTOPT, opp) < 0) { 600 break; 601 } 602 for (i = 0; bootdev_variables[i] != NULL; i++) { 603 if (strcmp(opp->oprom_array, bootdev_variables[i]) 604 == 0) { 605 found = 1; 606 break; 607 } 608 } 609 } 610 if (found) { 611 (void) strcpy(opp->oprom_array, bootdev_variables[i]); 612 opp->oprom_size = MAXVALSIZE; 613 if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) { 614 prom_close(prom_fd); 615 return (DEVFS_NOTSUP); 616 } 617 } else { 618 prom_close(prom_fd); 619 return (DEVFS_NOTSUP); 620 } 621 622 /* save the old copy in case we fail */ 623 if ((save_bootdev = strdup(opp->oprom_array)) == NULL) { 624 prom_close(prom_fd); 625 return (DEVFS_NOMEM); 626 } 627 /* set up the new value of boot-device */ 628 (void) strcpy(opp->oprom_array, bootdev_variables[i]); 629 valbuf = opp->oprom_array + strlen(opp->oprom_array) + 1; 630 (void) strcpy(valbuf, bootdev); 631 632 opp->oprom_size = strlen(valbuf) + strlen(opp->oprom_array) + 2; 633 634 if (ioctl(prom_fd, OPROMSETOPT, opp) < 0) { 635 free(save_bootdev); 636 prom_close(prom_fd); 637 return (DEVFS_ERR); 638 } 639 640 /* 641 * now read it back to make sure it took 642 */ 643 (void) strcpy(opp->oprom_array, bootdev_variables[i]); 644 opp->oprom_size = MAXVALSIZE; 645 if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) { 646 if (_prom_strcmp(opp->oprom_array, bootdev) == 0) { 647 /* success */ 648 free(save_bootdev); 649 prom_close(prom_fd); 650 return (0); 651 } 652 /* deal with setting it to "" */ 653 if ((strlen(bootdev) == 0) && (opp->oprom_size == 0)) { 654 /* success */ 655 free(save_bootdev); 656 prom_close(prom_fd); 657 return (0); 658 } 659 } 660 /* 661 * something did not take - write out the old value and 662 * hope that we can restore things... 663 * 664 * unfortunately, there is no way for us to differentiate 665 * whether we exceeded the maximum number of characters 666 * allowable. The limit varies from prom rev to prom 667 * rev, and on some proms, when the limit is 668 * exceeded, whatever was in the 669 * boot-device variable becomes unreadable. 670 * 671 * so if we fail, we will assume we ran out of room. If we 672 * not able to restore the original setting, then we will 673 * return DEVFS_ERR instead. 674 */ 675 ret = DEVFS_LIMIT; 676 (void) strcpy(opp->oprom_array, bootdev_variables[i]); 677 valbuf = opp->oprom_array + strlen(opp->oprom_array) + 1; 678 (void) strcpy(valbuf, save_bootdev); 679 680 opp->oprom_size = strlen(valbuf) + strlen(opp->oprom_array) + 2; 681 682 if (ioctl(prom_fd, OPROMSETOPT, opp) < 0) { 683 ret = DEVFS_ERR; 684 } 685 free(save_bootdev); 686 prom_close(prom_fd); 687 return (ret); 688 } 689 /* 690 * retrieve the current value for boot-device 691 */ 692 static int 693 get_boot_dev_var(struct openpromio *opp) 694 { 695 int prom_fd; 696 int i; 697 char *bootdev_variables[] = { 698 "boot-device", 699 "bootdev", 700 "boot-from", 701 NULL 702 }; 703 int found = 0; 704 int *ip = (int *)((void *)opp->oprom_array); 705 706 /* query the prom */ 707 prom_fd = prom_open(O_RDONLY); 708 if (prom_fd < 0) { 709 return (prom_fd); 710 } 711 712 /* get the diagnostic-mode? property */ 713 (void) strcpy(opp->oprom_array, "diagnostic-mode?"); 714 opp->oprom_size = MAXVALSIZE; 715 if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) { 716 if ((opp->oprom_size > 0) && 717 (strcmp(opp->oprom_array, "true") == 0)) { 718 prom_close(prom_fd); 719 return (DEVFS_ERR); 720 } 721 } 722 /* get the diag-switch? property */ 723 (void) strcpy(opp->oprom_array, "diag-switch?"); 724 opp->oprom_size = MAXVALSIZE; 725 if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) { 726 if ((opp->oprom_size > 0) && 727 (strcmp(opp->oprom_array, "true") == 0)) { 728 prom_close(prom_fd); 729 return (DEVFS_ERR); 730 } 731 } 732 /* 733 * look for one of the following properties in order: 734 * boot-device 735 * bootdev 736 * boot-from 737 * 738 * Use the first one that we find. 739 */ 740 *ip = 0; 741 opp->oprom_size = MAXPROPSIZE; 742 while ((opp->oprom_size != 0) && (!found)) { 743 opp->oprom_size = MAXPROPSIZE; 744 if (ioctl(prom_fd, OPROMNXTOPT, opp) < 0) { 745 break; 746 } 747 for (i = 0; bootdev_variables[i] != NULL; i++) { 748 if (strcmp(opp->oprom_array, bootdev_variables[i]) 749 == 0) { 750 found = 1; 751 break; 752 } 753 } 754 } 755 if (found) { 756 (void) strcpy(opp->oprom_array, bootdev_variables[i]); 757 opp->oprom_size = MAXVALSIZE; 758 if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) { 759 prom_close(prom_fd); 760 return (DEVFS_ERR); 761 } 762 /* boot-device exists but contains nothing */ 763 if (opp->oprom_size == 0) { 764 *opp->oprom_array = '\0'; 765 } 766 } else { 767 prom_close(prom_fd); 768 return (DEVFS_NOTSUP); 769 } 770 prom_close(prom_fd); 771 return (0); 772 } 773 774 #ifndef __sparc 775 static FILE * 776 open_diskmap(void) 777 { 778 FILE *fp; 779 char cmd[PATH_MAX]; 780 781 /* make sure we have a map file */ 782 fp = fopen(GRUBDISK_MAP, "r"); 783 if (fp == NULL) { 784 (void) snprintf(cmd, sizeof (cmd), 785 "%s > /dev/null", CREATE_DISKMAP); 786 (void) system(cmd); 787 fp = fopen(GRUBDISK_MAP, "r"); 788 } 789 return (fp); 790 } 791 792 static int 793 find_x86_boot_device(struct openpromio *opp) 794 { 795 int ret = DEVFS_ERR; 796 char *cp, line[MAXVALSIZE + 6]; 797 FILE *file; 798 799 file = open_diskmap(); 800 if (file == NULL) 801 return (DEVFS_ERR); 802 803 while (fgets(line, MAXVALSIZE + 6, file)) { 804 if (strncmp(line, "0 ", 2) != 0) 805 continue; 806 /* drop new-line */ 807 line[strlen(line) - 1] = '\0'; 808 /* 809 * an x86 BIOS only boots a disk, not a partition 810 * or a slice, so hard-code :q (p0) 811 */ 812 cp = strchr(line + 2, ' '); 813 if (cp == NULL) 814 break; 815 (void) snprintf(opp->oprom_array, MAXVALSIZE, 816 "%s:q", cp + 1); 817 opp->oprom_size = MAXVALSIZE; 818 ret = 0; 819 break; 820 } 821 (void) fclose(file); 822 return (ret); 823 } 824 #endif /* ndef __sparc */ 825 826 /* 827 * retrieve the list of entries in the boot-device configuration 828 * variable. An array of boot_dev structs will be created, one entry 829 * for each device name in the boot-device variable. Each entry 830 * in the array will contain the logical device representation of the 831 * boot-device entry, if any. 832 * 833 * default_root. if set, is used to locate logical device entries in 834 * directories other than /dev 835 */ 836 int 837 devfs_bootdev_get_list(const char *default_root, 838 struct boot_dev ***bootdev_list) 839 { 840 Oppbuf oppbuf; 841 struct openpromio *opp = &(oppbuf.opp); 842 int i; 843 struct boot_dev **tmp_list; 844 845 if (default_root == NULL) { 846 default_root = ""; 847 } else if (*default_root != '/') { 848 return (DEVFS_INVAL); 849 } 850 851 if (bootdev_list == NULL) { 852 return (DEVFS_INVAL); 853 } 854 855 /* get the boot-device variable */ 856 #if defined(sparc) 857 i = get_boot_dev_var(opp); 858 #else 859 i = find_x86_boot_device(opp); 860 #endif 861 if (i < 0) { 862 return (i); 863 } 864 /* now try to translate each entry to a logical device. */ 865 i = process_bootdev(opp->oprom_array, default_root, &tmp_list); 866 if (i == 0) { 867 *bootdev_list = tmp_list; 868 return (0); 869 } else { 870 return (i); 871 } 872 } 873 874 /* 875 * loop thru the list of entries in a boot-device configuration 876 * variable. 877 */ 878 static int 879 process_bootdev(const char *bootdevice, const char *default_root, 880 struct boot_dev ***list) 881 { 882 int i; 883 char *entry, *ptr; 884 char prom_path[MAXPATHLEN]; 885 char ret_buf[MAXPATHLEN]; 886 struct boot_dev **bootdev_array; 887 int num_entries = 0; 888 int found = 0; 889 int vers; 890 891 if ((entry = (char *)malloc(strlen(bootdevice) + 1)) == NULL) { 892 return (DEVFS_NOMEM); 893 } 894 /* count the number of entries */ 895 (void) strcpy(entry, bootdevice); 896 for (ptr = strtok(entry, " "); ptr != NULL; 897 ptr = strtok(NULL, " ")) { 898 num_entries++; 899 } 900 (void) strcpy(entry, bootdevice); 901 902 bootdev_array = (struct boot_dev **) 903 calloc((size_t)num_entries + 1, sizeof (struct boot_dev *)); 904 905 if (bootdev_array == NULL) { 906 free(entry); 907 return (DEVFS_NOMEM); 908 } 909 910 vers = prom_obp_vers(); 911 if (vers < 0) { 912 free(entry); 913 return (vers); 914 } 915 916 /* for each entry in boot-device, do... */ 917 for (ptr = strtok(entry, " "), i = 0; ptr != NULL; 918 ptr = strtok(NULL, " "), i++) { 919 920 if ((bootdev_array[i] = alloc_bootdev(ptr)) == NULL) { 921 devfs_bootdev_free_list(bootdev_array); 922 free(entry); 923 return (DEVFS_NOMEM); 924 } 925 926 /* 927 * prom boot-device may be aliased, so we need to do 928 * the necessary prom alias to dev translation. 929 */ 930 if (*ptr != '/') { 931 if (alias_to_prom_dev(ptr, prom_path) < 0) { 932 continue; 933 } 934 } else { 935 (void) strcpy(prom_path, ptr); 936 } 937 938 /* now we have a prom device path - convert to a devfs name */ 939 if (devfs_prom_to_dev_name(prom_path, ret_buf) < 0) { 940 continue; 941 } 942 943 /* append any default minor names necessary */ 944 if (process_minor_name(ret_buf, default_root) < 0) { 945 continue; 946 } 947 found = 1; 948 949 /* 950 * store the physical device path for now - when 951 * we are all done with the entries, we will convert 952 * these to their logical device name equivalents 953 */ 954 bootdev_array[i]->bootdev_trans[0] = strdup(ret_buf); 955 } 956 /* 957 * Convert all of the boot-device entries that translated to a 958 * physical device path in /devices to a logical device path 959 * in /dev (note that there may be several logical device paths 960 * associated with a single physical device path - return them all 961 */ 962 if (found) { 963 if (devfs_phys_to_logical(bootdev_array, num_entries, 964 default_root) < 0) { 965 devfs_bootdev_free_list(bootdev_array); 966 bootdev_array = NULL; 967 } 968 } 969 free(entry); 970 *list = bootdev_array; 971 return (0); 972 } 973 974 /* 975 * We may get a device path from the prom that has no minor name 976 * information included in it. Since this device name will not 977 * correspond directly to a physical device in /devices, we do our 978 * best to append what the default minor name should be and try this. 979 * 980 * For sparc: we append slice 0 (:a). 981 * For x86: we append fdisk partition 0 (:q). 982 */ 983 static int 984 process_minor_name(char *dev_path, const char *root) 985 { 986 char *cp; 987 #if defined(sparc) 988 const char *default_minor_name = "a"; 989 #else 990 const char *default_minor_name = "q"; 991 #endif 992 int n; 993 struct stat stat_buf; 994 char path[MAXPATHLEN]; 995 996 (void) snprintf(path, sizeof (path), "%s%s%s", root, DEVICES, dev_path); 997 /* 998 * if the device file already exists as given to us, there 999 * is nothing to do but return. 1000 */ 1001 if (stat(path, &stat_buf) == 0) { 1002 return (0); 1003 } 1004 /* 1005 * if there is no ':' after the last '/' character, or if there is 1006 * a ':' with no specifier, append the default segment specifier 1007 * ; if there is a ':' followed by a digit, this indicates 1008 * a partition number (which does not map into the /devices name 1009 * space), so strip the number and replace it with the letter 1010 * that represents the partition index 1011 */ 1012 if ((cp = strrchr(dev_path, '/')) != NULL) { 1013 if ((cp = strchr(cp, ':')) == NULL) { 1014 (void) strcat(dev_path, ":"); 1015 (void) strcat(dev_path, default_minor_name); 1016 } else if (*++cp == '\0') { 1017 (void) strcat(dev_path, default_minor_name); 1018 } else if (isdigit(*cp)) { 1019 n = atoi(cp); 1020 /* make sure to squash the digit */ 1021 *cp = '\0'; 1022 switch (n) { 1023 case 0: (void) strcat(dev_path, "q"); 1024 break; 1025 case 1: (void) strcat(dev_path, "r"); 1026 break; 1027 case 2: (void) strcat(dev_path, "s"); 1028 break; 1029 case 3: (void) strcat(dev_path, "t"); 1030 break; 1031 case 4: (void) strcat(dev_path, "u"); 1032 break; 1033 default: (void) strcat(dev_path, "a"); 1034 break; 1035 } 1036 } 1037 } 1038 /* 1039 * see if we can find something now. 1040 */ 1041 (void) snprintf(path, sizeof (path), "%s%s%s", root, DEVICES, dev_path); 1042 1043 if (stat(path, &stat_buf) == 0) { 1044 return (0); 1045 } else { 1046 return (-1); 1047 } 1048 } 1049 1050 /* 1051 * for each entry in bootdev_array, convert the physical device 1052 * representation of the boot-device entry to one or more logical device 1053 * entries. We use the hammer method - walk through the logical device 1054 * name space looking for matches (/dev). We use nftw to do this. 1055 */ 1056 static int 1057 devfs_phys_to_logical(struct boot_dev **bootdev_array, const int array_size, 1058 const char *default_root) 1059 { 1060 int walk_flags = FTW_PHYS | FTW_MOUNT; 1061 char *full_path; 1062 struct name_list *list; 1063 int count, i; 1064 char **dev_name_array; 1065 size_t default_root_len; 1066 char *dev_dir = DEV; 1067 int len; 1068 1069 if (array_size < 0) { 1070 return (-1); 1071 } 1072 1073 if (bootdev_array == NULL) { 1074 return (-1); 1075 } 1076 if (default_root == NULL) { 1077 return (-1); 1078 } 1079 default_root_len = strlen(default_root); 1080 if ((default_root_len != 0) && (*default_root != '/')) { 1081 return (-1); 1082 } 1083 1084 /* short cut for an empty array */ 1085 if (*bootdev_array == NULL) { 1086 return (0); 1087 } 1088 1089 /* tell nftw where to start (default: /dev) */ 1090 len = default_root_len + strlen(dev_dir) + 1; 1091 if ((full_path = (char *)malloc(len)) == NULL) { 1092 return (-1); 1093 } 1094 1095 /* 1096 * if the default root path is terminated with a /, we have to 1097 * make sure we don't end up with one too many slashes in the 1098 * path we are building. 1099 */ 1100 if ((default_root_len > (size_t)0) && 1101 (default_root[default_root_len - 1] == '/')) { 1102 (void) snprintf(full_path, len, "%s%s", default_root, 1103 &dev_dir[1]); 1104 } else { 1105 (void) snprintf(full_path, len, "%s%s", default_root, dev_dir); 1106 } 1107 1108 /* 1109 * we need to muck with global data to make nftw work 1110 * so single thread access 1111 */ 1112 (void) mutex_lock(&dev_lists_lk); 1113 1114 /* 1115 * set the global vars bootdev_list and dev_list for use by nftw 1116 * dev_list is an array of lists - one for each boot-device 1117 * entry. The nftw function will create a list of logical device 1118 * entries for each boot-device and put all of the lists in 1119 * dev_list. 1120 */ 1121 dev_list = (struct name_list **) 1122 calloc(array_size, sizeof (struct name_list *)); 1123 if (dev_list == NULL) { 1124 free(full_path); 1125 (void) mutex_unlock(&dev_lists_lk); 1126 return (-1); 1127 } 1128 bootdev_list = bootdev_array; 1129 1130 if (nftw(full_path, check_logical_dev, FT_DEPTH, walk_flags) == -1) { 1131 bootdev_list = NULL; 1132 free(full_path); 1133 for (i = 0; i < array_size; i++) { 1134 free_name_list(dev_list[i], 1); 1135 } 1136 /* don't free dev_list here because it's been handed off */ 1137 dev_list = NULL; 1138 (void) mutex_unlock(&dev_lists_lk); 1139 return (-1); 1140 } 1141 1142 /* 1143 * now we have a filled in dev_list. So for each logical device 1144 * list in dev_list, count the number of entries in the list, 1145 * create an array of strings of logical devices, and save in the 1146 * corresponding boot_dev structure. 1147 */ 1148 for (i = 0; i < array_size; i++) { 1149 /* get the next list */ 1150 list = dev_list[i]; 1151 count = 0; 1152 1153 /* count the number of entries in the list */ 1154 while (list != NULL) { 1155 count++; 1156 list = list->next; 1157 } 1158 if ((dev_name_array = 1159 (char **)malloc((count + 1) * sizeof (char *))) 1160 == NULL) { 1161 continue; 1162 } 1163 list = dev_list[i]; 1164 count = 0; 1165 1166 /* fill in the array */ 1167 while (list != NULL) { 1168 dev_name_array[count] = list->name; 1169 count++; 1170 list = list->next; 1171 } 1172 1173 /* 1174 * null terminate the array 1175 */ 1176 dev_name_array[count] = NULL; 1177 if ((bootdev_array[i] != NULL) && (bootdev_array[i]-> 1178 bootdev_trans[0] != NULL)) { 1179 free(bootdev_array[i]->bootdev_trans[0]); 1180 } 1181 if (bootdev_array[i] != NULL) { 1182 free(bootdev_array[i]->bootdev_trans); 1183 bootdev_array[i]->bootdev_trans = dev_name_array; 1184 } 1185 } 1186 bootdev_list = NULL; 1187 free(full_path); 1188 for (i = 0; i < array_size; i++) { 1189 free_name_list(dev_list[i], 0); 1190 } 1191 free(dev_list); 1192 dev_list = NULL; 1193 (void) mutex_unlock(&dev_lists_lk); 1194 return (0); 1195 } 1196 /* 1197 * nftw function 1198 * for a logical dev entry, it walks the list of boot-devices and 1199 * sees if there are any matches. If so, it saves the logical device 1200 * name off in the appropriate list in dev_list 1201 */ 1202 /* ARGSUSED */ 1203 static int 1204 check_logical_dev(const char *node, const struct stat *node_stat, int flags, 1205 struct FTW *ftw_info) 1206 { 1207 char link_buf[MAXPATHLEN]; 1208 int link_buf_len; 1209 char *name; 1210 struct name_list *dev; 1211 char *physdev; 1212 int i; 1213 1214 if (flags != FTW_SL) { 1215 return (0); 1216 } 1217 1218 if ((link_buf_len = readlink(node, (void *)link_buf, MAXPATHLEN)) 1219 == -1) { 1220 return (0); 1221 } 1222 link_buf[link_buf_len] = '\0'; 1223 if ((name = strstr(link_buf, DEVICES)) == NULL) { 1224 return (0); 1225 } 1226 name = (char *)(name + strlen(DEVICES)); 1227 1228 for (i = 0; bootdev_list[i] != NULL; i++) { 1229 if (bootdev_list[i]->bootdev_trans[0] == NULL) { 1230 continue; 1231 } 1232 /* 1233 * compare the contents of the link with the physical 1234 * device representation of this boot device 1235 */ 1236 physdev = bootdev_list[i]->bootdev_trans[0]; 1237 if ((strcmp(name, physdev) == 0) && 1238 (strlen(name) == strlen(physdev))) { 1239 if ((dev = (struct name_list *) 1240 malloc(sizeof (struct name_list))) == NULL) { 1241 return (-1); 1242 } 1243 if ((dev->name = strdup(node)) == NULL) { 1244 free(dev); 1245 return (-1); 1246 } 1247 if (dev_list[i] == NULL) { 1248 dev_list[i] = dev; 1249 dev_list[i]->next = NULL; 1250 } else { 1251 dev->next = dev_list[i]; 1252 dev_list[i] = dev; 1253 } 1254 } 1255 } 1256 return (0); 1257 } 1258 1259 /* 1260 * frees a list of boot_dev struct pointers 1261 */ 1262 void 1263 devfs_bootdev_free_list(struct boot_dev **array) 1264 { 1265 int i = 0; 1266 int j; 1267 1268 if (array == NULL) { 1269 return; 1270 } 1271 1272 while (array[i] != NULL) { 1273 free(array[i]->bootdev_element); 1274 j = 0; 1275 while (array[i]->bootdev_trans[j] != NULL) { 1276 free(array[i]->bootdev_trans[j++]); 1277 } 1278 free(array[i]->bootdev_trans); 1279 free(array[i]); 1280 i++; 1281 } 1282 free(array); 1283 } 1284 /* 1285 * allocates a boot_dev struct and fills in the bootdev_element portion 1286 */ 1287 static struct boot_dev * 1288 alloc_bootdev(char *entry_name) 1289 { 1290 struct boot_dev *entry; 1291 1292 entry = (struct boot_dev *)calloc(1, sizeof (struct boot_dev)); 1293 1294 if (entry == NULL) { 1295 return (NULL); 1296 } 1297 if ((entry->bootdev_element = strdup(entry_name)) == NULL) { 1298 free(entry); 1299 return (NULL); 1300 } 1301 /* 1302 * Allocate room for 1 name and a null terminator - the caller of 1303 * this function will need the first slot right away. 1304 */ 1305 if ((entry->bootdev_trans = (char **)calloc(2, sizeof (char *))) 1306 == NULL) { 1307 free(entry->bootdev_element); 1308 free(entry); 1309 return (NULL); 1310 } 1311 return (entry); 1312 } 1313 1314 /* 1315 * will come back with a concatenated list of paths 1316 */ 1317 int 1318 devfs_dev_to_prom_names(char *dev_path, char *prom_path, size_t len) 1319 { 1320 Oppbuf oppbuf; 1321 struct openpromio *opp = &(oppbuf.opp); 1322 int prom_fd; 1323 int ret = DEVFS_INVAL; 1324 int i; 1325 1326 if (prom_path == NULL) { 1327 return (DEVFS_INVAL); 1328 } 1329 if (dev_path == NULL) { 1330 return (DEVFS_INVAL); 1331 } 1332 if (strlen(dev_path) >= MAXPATHLEN) 1333 return (DEVFS_INVAL); 1334 1335 if (*dev_path != '/') 1336 return (DEVFS_INVAL); 1337 1338 prom_fd = prom_open(O_RDONLY); 1339 if (prom_fd < 0) { 1340 return (prom_fd); 1341 } 1342 1343 /* query the prom */ 1344 (void) snprintf(opp->oprom_array, MAXVALSIZE, "%s", dev_path); 1345 opp->oprom_size = MAXVALSIZE; 1346 1347 if (ioctl(prom_fd, OPROMDEV2PROMNAME, opp) == 0) { 1348 prom_close(prom_fd); 1349 1350 /* return the prom path in prom_path */ 1351 1352 i = len - opp->oprom_size; 1353 if (i < 0) { 1354 bcopy(opp->oprom_array, prom_path, len); 1355 prom_path[len - 1] = NULL; 1356 return (len); 1357 } else { 1358 bcopy(opp->oprom_array, prom_path, len); 1359 return (opp->oprom_size); 1360 } 1361 } 1362 /* 1363 * either the prom does not support this ioctl or the argument 1364 * was invalid. 1365 */ 1366 if (errno == ENXIO) { 1367 ret = DEVFS_NOTSUP; 1368 } 1369 prom_close(prom_fd); 1370 return (ret); 1371 } 1372 1373 /* 1374 * Convert a physical or logical device name to a name the prom would 1375 * understand. Fail if this platform does not support a prom or if 1376 * the device does not correspond to a valid prom device. 1377 * dev_path should be the name of a device in the logical or 1378 * physical device namespace. 1379 * prom_path is the prom version of the device name 1380 * prom_path must be large enough to contain the result and is 1381 * supplied by the user. 1382 * 1383 * This routine only supports converting leaf device paths 1384 */ 1385 int 1386 devfs_dev_to_prom_name(char *dev_path, char *prom_path) 1387 { 1388 int rval; 1389 1390 rval = devfs_dev_to_prom_names(dev_path, prom_path, MAXPATHLEN); 1391 1392 if (rval < 0) 1393 return (rval); 1394 else 1395 return (0); 1396 } 1397 1398 /* 1399 * Use the openprom driver's OPROMPATH2DRV ioctl to convert a devfs 1400 * path to a driver name. 1401 * devfs_path - the pathname of interest. This must be the physcical device 1402 * path with the mount point prefix (ie. /devices) stripped off. 1403 * drv_buf - user supplied buffer - the driver name will be stored here. 1404 * 1405 * If the prom lookup fails, we return the name of the last component in 1406 * the pathname. This routine is useful for looking up driver names 1407 * associated with generically named devices. 1408 * 1409 * This routine returns driver names that have aliases resolved. 1410 */ 1411 int 1412 devfs_path_to_drv(char *devfs_path, char *drv_buf) 1413 { 1414 Oppbuf oppbuf; 1415 struct openpromio *opp = &(oppbuf.opp); 1416 char *slash, *colon, *dev_addr; 1417 char driver_path[MAXPATHLEN]; 1418 int prom_fd; 1419 1420 if (drv_buf == NULL) { 1421 return (-1); 1422 } 1423 if (devfs_path == NULL) { 1424 return (-1); 1425 } 1426 1427 if (strlen(devfs_path) >= MAXPATHLEN) 1428 return (-1); 1429 1430 if (*devfs_path != '/') 1431 return (-1); 1432 1433 1434 /* strip off any minor node info at the end of the path */ 1435 (void) strcpy(driver_path, devfs_path); 1436 slash = strrchr(driver_path, '/'); 1437 if (slash == NULL) 1438 return (-1); 1439 colon = strrchr(slash, ':'); 1440 if (colon != NULL) 1441 *colon = '\0'; 1442 1443 /* query the prom */ 1444 if ((prom_fd = prom_open(O_RDONLY)) >= 0) { 1445 (void) strcpy(opp->oprom_array, driver_path); 1446 opp->oprom_size = MAXVALSIZE; 1447 1448 if (ioctl(prom_fd, OPROMPATH2DRV, opp) == 0) { 1449 prom_close(prom_fd); 1450 /* return the driver name in drv_buf */ 1451 (void) strcpy(drv_buf, opp->oprom_array); 1452 return (0); 1453 } 1454 prom_close(prom_fd); 1455 } else if (prom_fd != DEVFS_NOTSUP) 1456 return (-1); 1457 /* 1458 * If we get here, then either: 1459 * 1. this platform does not support an openprom driver 1460 * 2. we were asked to look up a device the prom does 1461 * not know about (e.g. a pseudo device) 1462 * In this case, we use the last component of the devfs path 1463 * name and try to derive the driver name 1464 */ 1465 1466 /* use the last component of devfs_path as the driver name */ 1467 if ((dev_addr = strrchr(slash, '@')) != NULL) 1468 *dev_addr = '\0'; 1469 slash++; 1470 1471 /* use opp->oprom_array as a buffer */ 1472 (void) strcpy(opp->oprom_array, slash); 1473 if (devfs_resolve_aliases(opp->oprom_array) == NULL) 1474 return (-1); 1475 (void) strcpy(drv_buf, opp->oprom_array); 1476 return (0); 1477 } 1478 1479 /* 1480 * These modctl calls do the equivalent of: 1481 * ddi_name_to_major() 1482 * ddi_major_to_name() 1483 * This results in two things: 1484 * - the driver name must be a valid one 1485 * - any driver aliases are resolved. 1486 * drv is overwritten with the resulting name. 1487 */ 1488 char * 1489 devfs_resolve_aliases(char *drv) 1490 { 1491 major_t maj; 1492 char driver_name[MAXNAMELEN + 1]; 1493 1494 if (drv == NULL) { 1495 return (NULL); 1496 } 1497 1498 if (modctl(MODGETMAJBIND, drv, strlen(drv) + 1, &maj) < 0) 1499 return (NULL); 1500 else if (modctl(MODGETNAME, driver_name, sizeof (driver_name), &maj) 1501 < 0) { 1502 return (NULL); 1503 } else { 1504 (void) strcpy(drv, driver_name); 1505 return (drv); 1506 } 1507 } 1508 1509 /* 1510 * open the openprom device. and verify that we are on an 1511 * OBP/1275 OF machine. If the prom does not exist, then we 1512 * return an error 1513 */ 1514 static int 1515 prom_open(int oflag) 1516 { 1517 int prom_fd = -1; 1518 char *promdev = "/dev/openprom"; 1519 1520 while (prom_fd < 0) { 1521 if ((prom_fd = open(promdev, oflag)) < 0) { 1522 if (errno == EAGAIN) { 1523 (void) sleep(5); 1524 continue; 1525 } 1526 if ((errno == ENXIO) || (errno == ENOENT)) { 1527 return (DEVFS_NOTSUP); 1528 } 1529 if ((errno == EPERM) || (errno == EACCES)) { 1530 return (DEVFS_PERM); 1531 } 1532 return (DEVFS_ERR); 1533 } else 1534 break; 1535 } 1536 if (is_openprom(prom_fd)) 1537 return (prom_fd); 1538 else { 1539 prom_close(prom_fd); 1540 return (DEVFS_ERR); 1541 } 1542 } 1543 1544 static void 1545 prom_close(int prom_fd) 1546 { 1547 (void) close(prom_fd); 1548 } 1549 1550 /* 1551 * is this an OBP/1275 OF machine? 1552 */ 1553 static int 1554 is_openprom(int prom_fd) 1555 { 1556 Oppbuf oppbuf; 1557 struct openpromio *opp = &(oppbuf.opp); 1558 unsigned int i; 1559 1560 opp->oprom_size = MAXVALSIZE; 1561 if (ioctl(prom_fd, OPROMGETCONS, opp) < 0) 1562 return (0); 1563 1564 i = (unsigned int)((unsigned char)opp->oprom_array[0]); 1565 return ((i & OPROMCONS_OPENPROM) == OPROMCONS_OPENPROM); 1566 } 1567 1568 /* 1569 * convert a prom device path name to an equivalent physical device 1570 * path in the kernel. 1571 */ 1572 static int 1573 devfs_prom_to_dev_name(char *prom_path, char *dev_path) 1574 { 1575 Oppbuf oppbuf; 1576 struct openpromio *opp = &(oppbuf.opp); 1577 int prom_fd; 1578 int ret = DEVFS_INVAL; 1579 1580 if (dev_path == NULL) { 1581 return (DEVFS_INVAL); 1582 } 1583 if (prom_path == NULL) { 1584 return (DEVFS_INVAL); 1585 } 1586 if (strlen(prom_path) >= MAXPATHLEN) 1587 return (DEVFS_INVAL); 1588 1589 if (*prom_path != '/') { 1590 return (DEVFS_INVAL); 1591 } 1592 1593 /* query the prom */ 1594 prom_fd = prom_open(O_RDONLY); 1595 if (prom_fd < 0) { 1596 return (prom_fd); 1597 } 1598 (void) strcpy(opp->oprom_array, prom_path); 1599 opp->oprom_size = MAXVALSIZE; 1600 1601 if (ioctl(prom_fd, OPROMPROM2DEVNAME, opp) == 0) { 1602 prom_close(prom_fd); 1603 /* 1604 * success 1605 * return the prom path in prom_path 1606 */ 1607 (void) strcpy(dev_path, opp->oprom_array); 1608 return (0); 1609 } 1610 /* 1611 * either the argument was not a valid name or the openprom 1612 * driver does not support this ioctl. 1613 */ 1614 if (errno == ENXIO) { 1615 ret = DEVFS_NOTSUP; 1616 } 1617 prom_close(prom_fd); 1618 return (ret); 1619 } 1620 /* 1621 * convert a prom device path to a list of equivalent alias names 1622 * If there is no alias node, or there are no aliases that correspond 1623 * to dev, we return empty lists. 1624 */ 1625 static int 1626 prom_dev_to_alias(char *dev, uint_t options, char ***ret_buf) 1627 { 1628 struct name_list *exact_list; 1629 struct name_list *inexact_list; 1630 struct name_list *list; 1631 char *ptr; 1632 char **array; 1633 int prom_fd; 1634 int count; 1635 int vers; 1636 1637 vers = prom_obp_vers(); 1638 if (vers < 0) { 1639 return (vers); 1640 } 1641 1642 if (dev == NULL) { 1643 return (DEVFS_INVAL); 1644 } 1645 1646 if (*dev != '/') 1647 return (DEVFS_INVAL); 1648 1649 if (strlen(dev) >= MAXPATHLEN) 1650 return (DEVFS_INVAL); 1651 1652 if ((ptr = strchr(dev, ':')) != NULL) { 1653 if (strchr(ptr, '/') != NULL) 1654 return (DEVFS_INVAL); 1655 } 1656 if (ret_buf == NULL) { 1657 return (DEVFS_INVAL); 1658 } 1659 1660 prom_fd = prom_open(O_RDONLY); 1661 if (prom_fd < 0) { 1662 return (prom_fd); 1663 } 1664 1665 (void) prom_srch_aliases_by_def(dev, &exact_list, 1666 &inexact_list, prom_fd); 1667 1668 prom_close(prom_fd); 1669 1670 if ((options & BOOTDEV_NO_EXACT_ALIAS) != 0) { 1671 free_name_list(exact_list, 1); 1672 exact_list = NULL; 1673 } 1674 1675 if ((options & BOOTDEV_NO_INEXACT_ALIAS) != 0) { 1676 free_name_list(inexact_list, 1); 1677 inexact_list = NULL; 1678 } 1679 1680 count = 0; 1681 list = exact_list; 1682 while (list != NULL) { 1683 list = list->next; 1684 count++; 1685 } 1686 list = inexact_list; 1687 while (list != NULL) { 1688 list = list->next; 1689 count++; 1690 } 1691 1692 if ((*ret_buf = (char **)malloc((count + 1) * sizeof (char *))) 1693 == NULL) { 1694 free_name_list(inexact_list, 1); 1695 free_name_list(exact_list, 1); 1696 return (DEVFS_NOMEM); 1697 } 1698 1699 array = *ret_buf; 1700 count = 0; 1701 list = exact_list; 1702 while (list != NULL) { 1703 array[count] = list->name; 1704 list = list->next; 1705 count++; 1706 } 1707 list = inexact_list; 1708 while (list != NULL) { 1709 array[count] = list->name; 1710 list = list->next; 1711 count++; 1712 } 1713 array[count] = NULL; 1714 free_name_list(inexact_list, 0); 1715 free_name_list(exact_list, 0); 1716 1717 return (0); 1718 } 1719 1720 /* 1721 * determine the version of prom we are running on. 1722 * Also include any prom revision specific information. 1723 */ 1724 static int 1725 prom_obp_vers(void) 1726 { 1727 Oppbuf oppbuf; 1728 struct openpromio *opp = &(oppbuf.opp); 1729 int prom_fd; 1730 static int version = 0; 1731 1732 /* cache version */ 1733 if (version > 0) { 1734 return (version); 1735 } 1736 1737 prom_fd = prom_open(O_RDONLY); 1738 if (prom_fd < 0) { 1739 return (prom_fd); 1740 } 1741 1742 opp->oprom_size = MAXVALSIZE; 1743 1744 if ((ioctl(prom_fd, OPROMGETVERSION, opp)) < 0) { 1745 prom_close(prom_fd); 1746 return (DEVFS_ERR); 1747 } 1748 prom_close(prom_fd); 1749 1750 version |= OBP_OF; 1751 1752 return (version); 1753 } 1754 /* 1755 * search the aliases node by definition - compile a list of 1756 * alias names that are both exact and inexact matches. 1757 */ 1758 static int 1759 prom_srch_aliases_by_def(char *promdev_def, struct name_list **exact_list, 1760 struct name_list **inexact_list, int prom_fd) 1761 { 1762 Oppbuf oppbuf; 1763 Oppbuf propdef_oppbuf; 1764 struct openpromio *opp = &(oppbuf.opp); 1765 struct openpromio *propdef_opp = &(propdef_oppbuf.opp); 1766 int *ip = (int *)((void *)opp->oprom_array); 1767 int ret; 1768 struct name_list *inexact_match = *inexact_list = NULL; 1769 struct name_list *exact_match = *exact_list = NULL; 1770 char alias_buf[MAXNAMELEN]; 1771 int found = 0; 1772 1773 if ((ret = prom_find_aliases_node(prom_fd)) < 0) 1774 return (0); 1775 1776 (void) memset(oppbuf.buf, 0, BUFSIZE); 1777 opp->oprom_size = MAXPROPSIZE; 1778 *ip = 0; 1779 1780 if ((ret = ioctl(prom_fd, OPROMNXTPROP, opp)) < 0) 1781 return (0); 1782 if (opp->oprom_size == 0) 1783 return (0); 1784 1785 while ((ret >= 0) && (opp->oprom_size > 0)) { 1786 (void) strcpy(propdef_opp->oprom_array, opp->oprom_array); 1787 opp->oprom_size = MAXPROPSIZE; 1788 propdef_opp->oprom_size = MAXVALSIZE; 1789 if ((ioctl(prom_fd, OPROMGETPROP, propdef_opp) < 0) || 1790 (propdef_opp->oprom_size == 0)) { 1791 ret = ioctl(prom_fd, OPROMNXTPROP, opp); 1792 continue; 1793 } 1794 ret = prom_compare_devs(promdev_def, propdef_opp->oprom_array); 1795 if (ret == EXACT_MATCH) { 1796 found++; 1797 if (insert_alias_list(exact_list, opp->oprom_array) 1798 != 0) { 1799 free_name_list(exact_match, 1); 1800 free_name_list(inexact_match, 1); 1801 return (-1); 1802 } 1803 } 1804 if (ret == INEXACT_MATCH) { 1805 found++; 1806 (void) strcpy(alias_buf, opp->oprom_array); 1807 options_override(promdev_def, alias_buf); 1808 if (insert_alias_list(inexact_list, alias_buf) 1809 != 0) { 1810 free_name_list(exact_match, 1); 1811 free_name_list(inexact_match, 1); 1812 return (-1); 1813 } 1814 } 1815 ret = ioctl(prom_fd, OPROMNXTPROP, opp); 1816 } 1817 if (found) { 1818 return (0); 1819 } else { 1820 return (-1); 1821 } 1822 } 1823 1824 /* 1825 * free a list of name_list structs and optionally 1826 * free the strings they contain. 1827 */ 1828 static void 1829 free_name_list(struct name_list *list, int free_name) 1830 { 1831 struct name_list *next = list; 1832 1833 while (next != NULL) { 1834 list = list->next; 1835 if (free_name) 1836 free(next->name); 1837 free(next); 1838 next = list; 1839 } 1840 } 1841 1842 /* 1843 * insert a new alias in a list of aliases - the list is sorted 1844 * in collating order (ignoring anything that comes after the 1845 * ':' in the name). 1846 */ 1847 static int 1848 insert_alias_list(struct name_list **list, char *alias_name) 1849 { 1850 struct name_list *entry = *list; 1851 struct name_list *new_entry, *prev_entry; 1852 int ret; 1853 char *colon1, *colon2; 1854 1855 if ((new_entry = 1856 (struct name_list *)malloc(sizeof (struct name_list))) 1857 == NULL) { 1858 return (-1); 1859 } 1860 if ((new_entry->name = strdup(alias_name)) == NULL) { 1861 free(new_entry); 1862 return (-1); 1863 } 1864 new_entry->next = NULL; 1865 1866 if (entry == NULL) { 1867 *list = new_entry; 1868 return (0); 1869 } 1870 1871 if ((colon1 = strchr(alias_name, ':')) != NULL) { 1872 *colon1 = '\0'; 1873 } 1874 prev_entry = NULL; 1875 while (entry != NULL) { 1876 if ((colon2 = strchr(entry->name, ':')) != NULL) { 1877 *colon2 = '\0'; 1878 } 1879 ret = strcmp(alias_name, entry->name); 1880 if (colon2 != NULL) { 1881 *colon2 = ':'; 1882 } 1883 /* duplicate */ 1884 if (ret == 0) { 1885 free(new_entry->name); 1886 free(new_entry); 1887 if (colon1 != NULL) { 1888 *colon1 = ':'; 1889 } 1890 return (0); 1891 } 1892 if (ret < 0) { 1893 new_entry->next = entry; 1894 if (prev_entry == NULL) { 1895 /* in beginning of list */ 1896 *list = new_entry; 1897 } else { 1898 /* in middle of list */ 1899 prev_entry->next = new_entry; 1900 } 1901 if (colon1 != NULL) { 1902 *colon1 = ':'; 1903 } 1904 return (0); 1905 } 1906 prev_entry = entry; 1907 entry = entry->next; 1908 } 1909 /* at end of list */ 1910 prev_entry->next = new_entry; 1911 new_entry->next = NULL; 1912 if (colon1 != NULL) { 1913 *colon1 = ':'; 1914 } 1915 return (0); 1916 } 1917 /* 1918 * append :x to alias_name to override any default minor name options 1919 */ 1920 static void 1921 options_override(char *prom_path, char *alias_name) 1922 { 1923 char *colon; 1924 1925 if ((colon = strrchr(alias_name, ':')) != NULL) { 1926 /* 1927 * XXX - should alias names in /aliases ever have a 1928 * : embedded in them? 1929 * If so we ignore it. 1930 */ 1931 *colon = '\0'; 1932 } 1933 1934 if ((colon = strrchr(prom_path, ':')) != NULL) { 1935 (void) strcat(alias_name, colon); 1936 } 1937 } 1938 1939 /* 1940 * compare to prom device names. 1941 * if the device names are not fully qualified. we convert them - 1942 * we only do this as a last resort though since it requires 1943 * jumping into the kernel. 1944 */ 1945 static int 1946 prom_compare_devs(char *prom_dev1, char *prom_dev2) 1947 { 1948 char *dev1, *dev2; 1949 char *ptr1, *ptr2; 1950 char *drvname1, *addrname1, *minorname1; 1951 char *drvname2, *addrname2, *minorname2; 1952 char component1[MAXNAMELEN], component2[MAXNAMELEN]; 1953 char devname1[MAXPATHLEN], devname2[MAXPATHLEN]; 1954 int unqualified_name = 0; 1955 int error = EXACT_MATCH; 1956 int len1, len2; 1957 char *wildcard = ",0"; 1958 1959 ptr1 = prom_dev1; 1960 ptr2 = prom_dev2; 1961 1962 if ((ptr1 == NULL) || (*ptr1 != '/')) { 1963 return (NO_MATCH); 1964 } 1965 if ((ptr2 == NULL) || (*ptr2 != '/')) { 1966 return (NO_MATCH); 1967 } 1968 1969 /* 1970 * compare device names one component at a time. 1971 */ 1972 while ((ptr1 != NULL) && (ptr2 != NULL)) { 1973 *ptr1 = *ptr2 = '/'; 1974 dev1 = ptr1 + 1; 1975 dev2 = ptr2 + 1; 1976 if ((ptr1 = strchr(dev1, '/')) != NULL) 1977 *ptr1 = '\0'; 1978 if ((ptr2 = strchr(dev2, '/')) != NULL) 1979 *ptr2 = '\0'; 1980 1981 (void) strcpy(component1, dev1); 1982 (void) strcpy(component2, dev2); 1983 1984 parse_name(component1, &drvname1, &addrname1, &minorname1); 1985 parse_name(component2, &drvname2, &addrname2, &minorname2); 1986 1987 if ((drvname1 == NULL) && (addrname1 == NULL)) { 1988 error = NO_MATCH; 1989 break; 1990 } 1991 1992 if ((drvname2 == NULL) && (addrname2 == NULL)) { 1993 error = NO_MATCH; 1994 break; 1995 } 1996 1997 if (_prom_strcmp(drvname1, drvname2) != 0) { 1998 error = NO_MATCH; 1999 break; 2000 } 2001 2002 /* 2003 * a possible name is driver_name@address. The address 2004 * portion is optional (i.e. the name is not fully 2005 * qualified.). We have to deal with the case where 2006 * the component name is either driver_name or 2007 * driver_name@address 2008 */ 2009 if ((addrname1 == NULL) ^ (addrname2 == NULL)) { 2010 unqualified_name = 1; 2011 } else if (addrname1 && 2012 (_prom_strcmp(addrname1, addrname2) != 0)) { 2013 /* 2014 * check to see if appending a ",0" to the 2015 * shorter address causes a match to occur. 2016 * If so succeed. 2017 */ 2018 len1 = strlen(addrname1); 2019 len2 = strlen(addrname2); 2020 if ((len1 < len2) && 2021 (strncmp(addrname1, addrname2, len1) == 0) && 2022 (strcmp(wildcard, &addrname2[len1]) == 0)) { 2023 continue; 2024 } else if ((len2 < len1) && 2025 (strncmp(addrname1, addrname2, len2) == 0) && 2026 (strcmp(wildcard, &addrname1[len2]) == 0)) { 2027 continue; 2028 } 2029 error = NO_MATCH; 2030 break; 2031 } 2032 } 2033 2034 /* 2035 * if either of the two device paths still has more components, 2036 * then we do not have a match. 2037 */ 2038 if (ptr1 != NULL) { 2039 *ptr1 = '/'; 2040 error = NO_MATCH; 2041 } 2042 if (ptr2 != NULL) { 2043 *ptr2 = '/'; 2044 error = NO_MATCH; 2045 } 2046 if (error == NO_MATCH) { 2047 return (error); 2048 } 2049 2050 /* 2051 * OK - we found a possible match but one or more of the 2052 * path components was not fully qualified (did not have any 2053 * address information. So we need to convert it to a form 2054 * that is fully qualified and then compare the resulting 2055 * strings. 2056 */ 2057 if (unqualified_name != 0) { 2058 if ((devfs_prom_to_dev_name(prom_dev1, devname1) < 0) || 2059 (devfs_prom_to_dev_name(prom_dev2, devname2) < 0)) { 2060 return (NO_MATCH); 2061 } 2062 if ((dev1 = strrchr(devname1, ':')) != NULL) { 2063 *dev1 = '\0'; 2064 } 2065 if ((dev2 = strrchr(devname2, ':')) != NULL) { 2066 *dev2 = '\0'; 2067 } 2068 if (strcmp(devname1, devname2) != 0) { 2069 return (NO_MATCH); 2070 } 2071 } 2072 /* 2073 * the resulting strings matched. If the minorname information 2074 * matches, then we have an exact match, otherwise an inexact match 2075 */ 2076 if (_prom_strcmp(minorname1, minorname2) == 0) { 2077 return (EXACT_MATCH); 2078 } else { 2079 return (INEXACT_MATCH); 2080 } 2081 } 2082 2083 /* 2084 * wrapper or strcmp - deals with null strings. 2085 */ 2086 static int 2087 _prom_strcmp(char *s1, char *s2) 2088 { 2089 if ((s1 == NULL) && (s2 == NULL)) 2090 return (0); 2091 if ((s1 == NULL) && (s2 != NULL)) { 2092 return (-1); 2093 } 2094 if ((s1 != NULL) && (s2 == NULL)) { 2095 return (1); 2096 } 2097 return (strcmp(s1, s2)); 2098 } 2099 /* 2100 * break device@a,b:minor into components 2101 */ 2102 static void 2103 parse_name(char *name, char **drvname, char **addrname, char **minorname) 2104 { 2105 char *cp, ch; 2106 2107 cp = *drvname = name; 2108 *addrname = *minorname = NULL; 2109 if (*name == '@') 2110 *drvname = NULL; 2111 2112 while ((ch = *cp) != '\0') { 2113 if (ch == '@') 2114 *addrname = ++cp; 2115 else if (ch == ':') 2116 *minorname = ++cp; 2117 ++cp; 2118 } 2119 if (*addrname) { 2120 *((*addrname)-1) = '\0'; 2121 } 2122 if (*minorname) { 2123 *((*minorname)-1) = '\0'; 2124 } 2125 } 2126 2127 /* 2128 * converts a prom alias to a prom device name. 2129 * if we find no matching device, then we fail since if were 2130 * given a valid alias, then by definition, there must be a 2131 * device pathname associated with it in the /aliases node. 2132 */ 2133 static int 2134 alias_to_prom_dev(char *alias, char *ret_buf) 2135 { 2136 char *options_ptr; 2137 char alias_buf[MAXNAMELEN]; 2138 char alias_def[MAXPATHLEN]; 2139 char options[16] = ""; 2140 int prom_fd = -1; 2141 int ret; 2142 int i; 2143 2144 if (strchr(alias, '/') != NULL) 2145 return (DEVFS_INVAL); 2146 2147 if (strlen(alias) > (MAXNAMELEN - 1)) 2148 return (DEVFS_INVAL); 2149 2150 if (ret_buf == NULL) { 2151 return (DEVFS_INVAL); 2152 } 2153 2154 prom_fd = prom_open(O_RDONLY); 2155 if (prom_fd < 0) { 2156 return (prom_fd); 2157 } 2158 2159 (void) strlcpy(alias_buf, alias, sizeof (alias_buf)); 2160 2161 /* 2162 * save off any options (minor name info) that is 2163 * explicitly called out in the alias name 2164 */ 2165 if ((options_ptr = strchr(alias_buf, ':')) != NULL) { 2166 *options_ptr = '\0'; 2167 (void) strlcpy(options, ++options_ptr, sizeof (options)); 2168 } 2169 2170 *alias_def = '\0'; 2171 2172 ret = prom_find_aliases_node(prom_fd); 2173 if (ret == 0) { 2174 /* 2175 * we loop because one alias may define another... we have 2176 * to work our way down to an actual device definition. 2177 */ 2178 for (i = 0; i <= 10; i++) { 2179 ret = prom_srch_node(prom_fd, alias_buf, alias_def); 2180 if (ret == -1) { 2181 break; 2182 } 2183 (void) strlcpy(alias_buf, alias_def, 2184 sizeof (alias_buf)); 2185 if (*alias_def == '/') { 2186 break; 2187 } 2188 2189 /* 2190 * save off any explicit options (minor name info) 2191 * if none has been encountered yet 2192 */ 2193 if (options_ptr == NULL) { 2194 options_ptr = strchr(alias_buf, ':'); 2195 if (options_ptr != NULL) { 2196 *options_ptr = '\0'; 2197 (void) strlcpy(options, ++options_ptr, 2198 sizeof (options)); 2199 } 2200 } 2201 } 2202 } 2203 prom_close(prom_fd); 2204 2205 /* error */ 2206 if (ret == -1) { 2207 return (ret); 2208 } 2209 2210 (void) strlcpy(ret_buf, alias_def, MAXPATHLEN); 2211 2212 /* override minor name information */ 2213 if (options_ptr != NULL) { 2214 if ((options_ptr = strrchr(ret_buf, ':')) == NULL) { 2215 (void) strcat(ret_buf, ":"); 2216 } else { 2217 *(++options_ptr) = '\0'; 2218 } 2219 (void) strcat(ret_buf, options); 2220 } 2221 return (0); 2222 } 2223 2224 /* 2225 * search a prom node for a property name 2226 */ 2227 static int 2228 prom_srch_node(int fd, char *prop_name, char *ret_buf) 2229 { 2230 Oppbuf oppbuf; 2231 struct openpromio *opp = &(oppbuf.opp); 2232 int *ip = (int *)((void *)opp->oprom_array); 2233 2234 (void) memset(oppbuf.buf, 0, BUFSIZE); 2235 opp->oprom_size = MAXPROPSIZE; 2236 *ip = 0; 2237 2238 if (ioctl(fd, OPROMNXTPROP, opp) < 0) 2239 return (-1); 2240 if (opp->oprom_size == 0) 2241 return (-1); 2242 2243 while (strcmp(prop_name, opp->oprom_array) != 0) { 2244 opp->oprom_size = MAXPROPSIZE; 2245 if (ioctl(fd, OPROMNXTPROP, opp) < 0) 2246 return (-1); 2247 if (opp->oprom_size == 0) 2248 return (-1); 2249 } 2250 opp->oprom_size = MAXVALSIZE; 2251 if (ioctl(fd, OPROMGETPROP, opp) < 0) 2252 return (-1); 2253 2254 if (opp->oprom_size == 0) 2255 return (-1); 2256 (void) strlcpy(ret_buf, opp->oprom_array, MAXPATHLEN); 2257 return (0); 2258 } 2259 2260 /* 2261 * return the aliases node. 2262 */ 2263 static int 2264 prom_find_aliases_node(int fd) 2265 { 2266 uint_t child_id; 2267 char buf[MAXPATHLEN]; 2268 2269 if ((child_id = prom_next_node(fd, 0)) == 0) 2270 return (-1); 2271 if ((child_id = prom_child_node(fd, child_id)) == 0) 2272 return (-1); 2273 2274 while (child_id != 0) { 2275 if (prom_srch_node(fd, "name", buf) == 0) { 2276 if (strcmp(buf, "aliases") == 0) { 2277 return (0); 2278 } 2279 } 2280 child_id = prom_next_node(fd, child_id); 2281 } 2282 return (-1); 2283 } 2284 2285 /* 2286 * get sibling 2287 */ 2288 static uint_t 2289 prom_next_node(int fd, uint_t node_id) 2290 { 2291 Oppbuf oppbuf; 2292 struct openpromio *opp = &(oppbuf.opp); 2293 uint_t *ip = (uint_t *)((void *)opp->oprom_array); 2294 2295 (void) memset(oppbuf.buf, 0, BUFSIZE); 2296 opp->oprom_size = MAXVALSIZE; 2297 *ip = node_id; 2298 2299 if (ioctl(fd, OPROMNEXT, opp) < 0) 2300 return (0); 2301 2302 return (*(uint_t *)((void *)opp->oprom_array)); 2303 } 2304 2305 /* 2306 * get child 2307 */ 2308 static uint_t 2309 prom_child_node(int fd, uint_t node_id) 2310 { 2311 Oppbuf oppbuf; 2312 struct openpromio *opp = &(oppbuf.opp); 2313 uint_t *ip = (uint_t *)((void *)opp->oprom_array); 2314 2315 (void) memset(oppbuf.buf, 0, BUFSIZE); 2316 opp->oprom_size = MAXVALSIZE; 2317 *ip = node_id; 2318 2319 if (ioctl(fd, OPROMCHILD, opp) < 0) 2320 return (0); 2321 2322 return (*(uint_t *)((void *)opp->oprom_array)); 2323 } 2324 2325 /* 2326 * only on sparc for now 2327 */ 2328 int 2329 devfs_bootdev_modifiable(void) 2330 { 2331 #if defined(sparc) 2332 return (0); 2333 #else 2334 return (DEVFS_NOTSUP); 2335 #endif 2336 } 2337