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