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