1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include "cfga_scsi.h" 27 28 typedef struct { 29 char *dyncomp; 30 char *devlink; 31 int l_errno; 32 scfga_ret_t ret; 33 } dyn_t; 34 35 typedef struct { 36 scfga_recur_t (*devlink_to_dyncomp_p)(dyn_t *dyntp); 37 scfga_recur_t (*dyncomp_to_devlink_p)(dyn_t *dyntp); 38 } dynrules_t; 39 40 typedef struct { 41 dyn_t *dynp; 42 dynrules_t *rule_array; 43 int nrules; 44 } dyncvt_t; 45 46 typedef struct { 47 const char *hba_phys; 48 const char *dyncomp; 49 char *path; 50 int l_errno; 51 scfga_ret_t ret; 52 } devpath_t; 53 54 55 56 /* Function prototypes */ 57 58 static int drv_to_hba_logid(di_node_t node, di_minor_t minor, void *arg); 59 static scfga_ret_t drv_dyn_to_devpath(const char *hba_phys, 60 const char *dyncomp, char **pathpp, int *l_errnop); 61 static int do_drv_dyn_to_devpath(di_node_t node, void *arg); 62 static scfga_ret_t devlink_dyn_to_devpath(const char *hba_phys, 63 const char *dyncomp, char **pathpp, int *l_errnop); 64 65 static scfga_recur_t disk_dyncomp_to_devlink(dyn_t *dyntp); 66 static scfga_recur_t tape_dyncomp_to_devlink(dyn_t *dyntp); 67 static scfga_recur_t def_dyncomp_to_devlink(dyn_t *dyntp); 68 69 static scfga_ret_t devlink_to_dyncomp(char *devlink, 70 char **dyncompp, int *l_errnop); 71 static scfga_recur_t disk_devlink_to_dyncomp(dyn_t *dyntp); 72 static scfga_recur_t tape_devlink_to_dyncomp(dyn_t *dyntp); 73 static scfga_recur_t def_devlink_to_dyncomp(dyn_t *dyntp); 74 static scfga_ret_t drv_to_dyncomp(di_node_t node, const char *phys, 75 char **dyncompp, int *l_errnop); 76 static scfga_ret_t get_hba_devlink(const char *hba_phys, 77 char **hba_logpp, int *l_errnop); 78 static scfga_ret_t path_apid_dyn_to_path(const char *hba_phys, const char *dyn, 79 char **pathpp, int *l_errnop); 80 81 82 /* Globals */ 83 84 /* 85 * Rules for converting between a devlink and logical ap_id and vice-versa 86 * The default rules must be the last entry. 87 */ 88 static dynrules_t dyncvt_rules[] = { 89 {disk_devlink_to_dyncomp, disk_dyncomp_to_devlink}, 90 {tape_devlink_to_dyncomp, tape_dyncomp_to_devlink}, 91 {def_devlink_to_dyncomp, def_dyncomp_to_devlink} 92 }; 93 94 #define N_DYNRULES (sizeof (dyncvt_rules)/sizeof (dyncvt_rules[0])) 95 96 /* 97 * Numbering of disk slices is assumed to be 0 through n - 1 98 */ 99 typedef struct { 100 char *prefix; 101 int nslices; 102 } slice_t; 103 104 static slice_t disk_slices[] = { 105 {"s", 16}, 106 {"p", 5}, 107 }; 108 109 #define N_SLICE_TYPES (sizeof (disk_slices) / sizeof (disk_slices[0])) 110 111 static const char *tape_modes[] = { 112 "", 113 "b", "bn", 114 "c", "cb", "cbn", "cn", 115 "h", "hb", "hbn", "hn", 116 "l", "lb", "lbn", "ln", 117 "m", "mb", "mbn", "mn", 118 "n", 119 "u", "ub", "ubn", "un" 120 }; 121 122 #define N_TAPE_MODES (sizeof (tape_modes) / sizeof (tape_modes[0])) 123 124 125 /* Various conversions routines */ 126 127 /* 128 * Generates the HBA logical ap_id from physical ap_id. 129 */ 130 scfga_ret_t 131 make_hba_logid(const char *hba_phys, char **hba_logpp, int *l_errnop) 132 { 133 walkarg_t u; 134 pathm_t pmt = {NULL}; 135 scfga_ret_t ret; 136 137 138 if (*hba_logpp != NULL) { 139 return (SCFGA_ERR); 140 } 141 142 /* A devlink for the HBA may or may not exist */ 143 if (get_hba_devlink(hba_phys, hba_logpp, l_errnop) == SCFGA_OK) { 144 assert(*hba_logpp != NULL); 145 return (SCFGA_OK); 146 } 147 148 /* 149 * No devlink based logical ap_id. 150 * Try driver name and instance number. 151 */ 152 u.minor_args.nodetype = DDI_NT_SCSI_ATTACHMENT_POINT; 153 u.minor_args.fcn = drv_to_hba_logid; 154 155 pmt.phys = (char *)hba_phys; 156 pmt.ret = SCFGA_APID_NOEXIST; 157 158 errno = 0; 159 ret = walk_tree(pmt.phys, &pmt, DINFOMINOR | DINFOPROP, &u, 160 SCFGA_WALK_MINOR, &pmt.l_errno); 161 if (ret == SCFGA_OK && (ret = pmt.ret) == SCFGA_OK) { 162 assert(pmt.log != NULL); 163 *hba_logpp = pmt.log; 164 return (SCFGA_OK); 165 } 166 167 /* failed to create logical ap_id */ 168 if (pmt.log != NULL) { 169 S_FREE(pmt.log); 170 } 171 172 173 *l_errnop = pmt.l_errno; 174 return (ret); 175 } 176 177 static scfga_ret_t 178 get_hba_devlink(const char *hba_phys, char **hba_logpp, int *l_errnop) 179 { 180 size_t len; 181 scfga_ret_t ret; 182 int match_minor = 1; 183 184 ret = physpath_to_devlink((char *)hba_phys, hba_logpp, 185 l_errnop, match_minor); 186 if (ret != SCFGA_OK) { 187 return (ret); 188 } 189 190 assert(*hba_logpp != NULL); 191 192 /* Remove the "/dev/cfg/" prefix */ 193 len = strlen(CFGA_DEV_DIR SLASH); 194 195 (void) memmove(*hba_logpp, *hba_logpp + len, 196 strlen(*hba_logpp + len) + 1); 197 198 return (SCFGA_OK); 199 } 200 201 /* Make logical name for HBA based on driver and instance */ 202 static int 203 drv_to_hba_logid(di_node_t node, di_minor_t minor, void *arg) 204 { 205 int inst; 206 char *drv, *mn, *log; 207 pathm_t *ptp; 208 const size_t loglen = MAXPATHLEN; 209 210 ptp = (pathm_t *)arg; 211 212 errno = 0; 213 214 mn = di_minor_name(minor); 215 drv = di_driver_name(node); 216 inst = di_instance(node); 217 log = calloc(1, loglen); 218 219 if (mn != NULL && drv != NULL && inst != -1 && log != NULL) { 220 /* Count does not include terminating NULL */ 221 if (snprintf(log, loglen, "%s%d:%s", drv, inst, mn) < loglen) { 222 ptp->ret = SCFGA_OK; 223 ptp->log = log; 224 return (DI_WALK_TERMINATE); 225 } 226 } 227 228 S_FREE(log); 229 return (DI_WALK_CONTINUE); 230 } 231 232 /* 233 * Given a bus or device ap_id <hba_phys, dyncomp>, returns the physical 234 * path in pathpp. 235 * Returns: SCFGA_APID_NOEXIST if the path does not exist. 236 */ 237 238 scfga_ret_t 239 apid_to_path( 240 const char *hba_phys, 241 const char *dyncomp, 242 char **pathpp, 243 int *l_errnop) 244 { 245 scfga_ret_t ret; 246 247 if (*pathpp != NULL) { 248 return (SCFGA_LIB_ERR); 249 } 250 251 /* If a bus, the physical ap_id is the physical path */ 252 if (dyncomp == NULL) { 253 if ((*pathpp = strdup(hba_phys)) == NULL) { 254 *l_errnop = errno; 255 return (SCFGA_LIB_ERR); 256 } 257 return (SCFGA_OK); 258 } 259 260 /* Dynamic component exists, we have a device */ 261 262 /* 263 * If the dynamic component has a '/', it was derived from a devlink 264 * Else it was derived from driver name and instance number. 265 * If it is pathinfo instance number based ap id, it will have a format 266 * path#.???. 267 */ 268 if (strchr(dyncomp, '/') != NULL) { 269 ret = devlink_dyn_to_devpath(hba_phys, dyncomp, pathpp, 270 l_errnop); 271 } else if (strstr(dyncomp, PATH_APID_DYN_SEP) != NULL) { 272 ret = path_apid_dyn_to_path(hba_phys, dyncomp, pathpp, 273 l_errnop); 274 } else { 275 ret = drv_dyn_to_devpath(hba_phys, dyncomp, pathpp, l_errnop); 276 } 277 assert(ret != SCFGA_OK || *pathpp != NULL); 278 279 280 return (ret); 281 } 282 283 /* 284 * Get the devfs path of pathinfo node that is associated with 285 * the given dynamic component. 286 * 287 * input 288 * hba_phys: physical path of HBA 289 * dyn : bus address of pathinfo node 290 * output: 291 * pathpp: devfs path of the pathinfo node. 292 */ 293 static scfga_ret_t 294 path_apid_dyn_to_path( 295 const char *hba_phys, 296 const char *dyn, 297 char **pathpp, 298 int *l_errnop) 299 { 300 301 di_node_t root, walk_root; 302 di_path_t pi_node = DI_PATH_NIL; 303 char *root_path, *devpath, *cp; 304 int len; 305 306 *l_errnop = 0; 307 308 /* *pathpp should be NULL if pathpp is not NULL. */ 309 if ((hba_phys == NULL) || (pathpp != NULL) && (*pathpp != NULL)) { 310 return (SCFGA_LIB_ERR); 311 } 312 313 if ((root_path = strdup(hba_phys)) == NULL) { 314 *l_errnop = errno; 315 return (SCFGA_LIB_ERR); 316 } 317 318 /* Fix up path for di_init() */ 319 len = strlen(DEVICES_DIR); 320 if (strncmp(root_path, DEVICES_DIR SLASH, 321 len + strlen(SLASH)) == 0) { 322 cp = root_path + len; 323 (void) memmove(root_path, cp, strlen(cp) + 1); 324 } else if (*root_path != '/') { 325 *l_errnop = 0; 326 S_FREE(root_path); 327 return (SCFGA_ERR); 328 } 329 330 /* Remove dynamic component if any */ 331 if ((cp = GET_DYN(root_path)) != NULL) { 332 *cp = '\0'; 333 } 334 335 /* Remove minor name if any */ 336 if ((cp = strrchr(root_path, ':')) != NULL) { 337 *cp = '\0'; 338 } 339 340 /* 341 * Cached snapshots are always rooted at "/" 342 */ 343 344 /* Get a snapshot */ 345 if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) { 346 *l_errnop = errno; 347 S_FREE(root_path); 348 return (SCFGA_ERR); 349 } 350 351 /* 352 * Lookup the subtree of interest 353 */ 354 walk_root = di_lookup_node(root, root_path); 355 356 if (walk_root == DI_NODE_NIL) { 357 *l_errnop = errno; 358 di_fini(root); 359 S_FREE(root_path); 360 return (SCFGA_LIB_ERR); 361 } 362 363 S_FREE(root_path); 364 365 if ((pi_node = di_path_next_client(walk_root, pi_node)) == 366 DI_PATH_NIL) { 367 di_fini(root); 368 return (SCFGA_APID_NOEXIST); 369 } 370 371 /* 372 * now parse the path info node. 373 */ 374 do { 375 /* check the length first. */ 376 if (strlen(di_path_bus_addr(pi_node)) != strlen(dyn)) { 377 continue; 378 } 379 380 if (strcmp(di_path_bus_addr(pi_node), dyn) == 0) { 381 /* get the devfspath of pathinfo node. */ 382 devpath = di_path_devfs_path(pi_node); 383 if (devpath == NULL) { 384 *l_errnop = errno; 385 di_fini(root); 386 return (SCFGA_ERR); 387 } 388 389 len = strlen(DEVICES_DIR) + strlen(devpath) + 1; 390 *pathpp = calloc(1, len); 391 if (*pathpp == NULL) { 392 *l_errnop = errno; 393 di_devfs_path_free(devpath); 394 di_fini(root); 395 return (SCFGA_ERR); 396 } else { 397 (void) snprintf(*pathpp, len, "%s%s", 398 DEVICES_DIR, devpath); 399 di_devfs_path_free(devpath); 400 di_fini(root); 401 return (SCFGA_OK); 402 } 403 } 404 pi_node = di_path_next_client(walk_root, pi_node); 405 } while (pi_node != DI_PATH_NIL); 406 407 di_fini(root); 408 return (SCFGA_APID_NOEXIST); 409 } 410 411 static scfga_ret_t 412 drv_dyn_to_devpath( 413 const char *hba_phys, 414 const char *dyncomp, 415 char **pathpp, 416 int *l_errnop) 417 { 418 walkarg_t u; 419 devpath_t dpt = {NULL}; 420 scfga_ret_t ret; 421 422 /* A device MUST have a dynamic component */ 423 if (dyncomp == NULL || *pathpp != NULL) { 424 return (SCFGA_LIB_ERR); 425 } 426 427 u.node_args.flags = DI_WALK_CLDFIRST; 428 u.node_args.fcn = do_drv_dyn_to_devpath; 429 430 dpt.hba_phys = hba_phys; 431 dpt.dyncomp = dyncomp; 432 dpt.ret = SCFGA_APID_NOEXIST; 433 434 ret = walk_tree(hba_phys, &dpt, DINFOCPYALL, &u, 435 SCFGA_WALK_NODE, &dpt.l_errno); 436 437 if (ret == SCFGA_OK && (ret = dpt.ret) == SCFGA_OK) { 438 assert(dpt.path != NULL); 439 *pathpp = dpt.path; 440 return (SCFGA_OK); 441 } 442 443 if (dpt.path != NULL) { 444 S_FREE(dpt.path); 445 } 446 447 448 *l_errnop = dpt.l_errno; 449 return (ret); 450 } 451 452 /* Converts a driver and instance number based logid into a physical path */ 453 static int 454 do_drv_dyn_to_devpath(di_node_t node, void *arg) 455 { 456 int inst, rv, match_minor; 457 devpath_t *dptp; 458 char *physpath, *drv; 459 char *drvinst, *devpath; 460 const size_t drvlen = MAXPATHLEN; 461 size_t devlen; 462 463 dptp = (devpath_t *)arg; 464 465 assert(dptp->hba_phys != NULL && dptp->dyncomp != NULL); 466 assert(dptp->path == NULL); 467 468 /* 469 * Skip stub nodes 470 */ 471 if (IS_STUB_NODE(node)) { 472 return (DI_WALK_CONTINUE); 473 } 474 475 errno = 0; 476 477 drv = di_driver_name(node); 478 inst = di_instance(node); 479 physpath = di_devfs_path(node); 480 if (drv == NULL || inst == -1 || physpath == NULL) { 481 rv = DI_WALK_CONTINUE; 482 goto out; 483 } 484 485 devlen = strlen(DEVICES_DIR) + strlen(physpath) + 1; 486 487 devpath = calloc(1, devlen); 488 drvinst = calloc(1, drvlen); 489 if (devpath == NULL || drvinst == NULL) { 490 dptp->l_errno = errno; 491 dptp->ret = SCFGA_LIB_ERR; 492 rv = DI_WALK_TERMINATE; 493 goto out; 494 } 495 496 (void) snprintf(drvinst, drvlen, "%s%d", drv, inst); 497 498 /* Create the physical path */ 499 (void) snprintf(devpath, devlen, "%s%s", DEVICES_DIR, physpath); 500 501 /* Skip node if it is the HBA */ 502 match_minor = 0; 503 if (!dev_cmp(dptp->hba_phys, devpath, match_minor)) { 504 rv = DI_WALK_CONTINUE; 505 goto out; 506 } 507 508 /* Compare the base and dynamic components */ 509 if (!hba_dev_cmp(dptp->hba_phys, devpath) && 510 strcmp(dptp->dyncomp, drvinst) == 0) { 511 dptp->ret = SCFGA_OK; 512 dptp->path = devpath; 513 rv = DI_WALK_TERMINATE; 514 } else { 515 rv = DI_WALK_CONTINUE; 516 } 517 518 /*FALLTHRU*/ 519 out: 520 S_FREE(drvinst); 521 if (physpath != NULL) di_devfs_path_free(physpath); 522 if (dptp->ret != SCFGA_OK) S_FREE(devpath); 523 return (rv); 524 } 525 526 /* readlink wrapper to ensure proper null termination of the results */ 527 static int 528 s_readlink(char *link, char *buf, int len) 529 { 530 int count; 531 532 count = readlink(link, buf, len - 1); 533 if (count != -1) 534 buf[count] = '\0'; 535 return (count); 536 } 537 538 /* Converts a devlink based dynamic component to a path */ 539 static scfga_ret_t 540 devlink_dyn_to_devpath( 541 const char *hba_phys, 542 const char *dyncomp, 543 char **pathpp, 544 int *l_errnop) 545 { 546 dyn_t dynt = {NULL}; 547 int i; 548 scfga_ret_t ret; 549 char buf[PATH_MAX], *path; 550 551 if (*pathpp != NULL) { 552 return (SCFGA_LIB_ERR); 553 } 554 555 /* Convert the dynamic component to the corresponding devlink */ 556 dynt.dyncomp = (char *)dyncomp; 557 dynt.ret = SCFGA_APID_NOEXIST; 558 559 for (i = 0; i < N_DYNRULES; i++) { 560 if (dyncvt_rules[i].dyncomp_to_devlink_p(&dynt) 561 != SCFGA_CONTINUE) { 562 break; 563 } 564 } 565 566 if (i >= N_DYNRULES) { 567 dynt.ret = SCFGA_APID_NOEXIST; 568 } 569 570 if (dynt.ret != SCFGA_OK) { 571 /* No symlink or error */ 572 return (dynt.ret); 573 } 574 575 assert(dynt.devlink != NULL); 576 577 /* 578 * Follow devlink to get the physical path 579 * Note: Do not use realpath(). It will stat() device 580 * and stat() fails under devfs if device is offline. 581 */ 582 errno = 0; 583 if ((s_readlink(dynt.devlink, buf, PATH_MAX) == -1) || 584 ((path = strstr(buf, "/devices/")) == NULL) || 585 ((*pathpp = strdup(path)) == NULL)) { 586 *l_errnop = errno; 587 ret = SCFGA_LIB_ERR; 588 goto out; 589 } 590 591 /* Compare base components as well */ 592 if (!hba_dev_cmp(hba_phys, path)) { 593 ret = SCFGA_OK; 594 } else { 595 /* Mismatched base and dynamic component */ 596 *l_errnop = 0; 597 ret = SCFGA_APID_NOEXIST; 598 } 599 600 /*FALLTHRU*/ 601 out: 602 S_FREE(dynt.devlink); 603 if (ret != SCFGA_OK) S_FREE(*pathpp); 604 return (ret); 605 } 606 607 scfga_ret_t 608 make_dyncomp( 609 di_node_t node, 610 const char *physpath, 611 char **dyncompp, 612 int *l_errnop) 613 { 614 char *devlink = NULL; 615 scfga_ret_t ret; 616 di_minor_t minor; 617 char *path; 618 char pathbuf[MAXPATHLEN]; 619 int match_minor; 620 621 if (*dyncompp != NULL) { 622 return (SCFGA_LIB_ERR); 623 } 624 625 /* tag on minor name */ 626 minor = di_minor_next(node, DI_MINOR_NIL); 627 if (minor == DI_MINOR_NIL) { 628 match_minor = 0; 629 path = (char *)physpath; 630 } else { 631 match_minor = 1; 632 (void) snprintf(pathbuf, MAXPATHLEN, "%s:%s", physpath, 633 di_minor_name(minor)); 634 path = pathbuf; 635 } 636 637 /* Get the corresponding devlink from the physical path */ 638 ret = physpath_to_devlink(path, &devlink, l_errnop, match_minor); 639 if (ret == SCFGA_OK) { 640 assert(devlink != NULL); 641 642 /* Create dynamic component. */ 643 ret = devlink_to_dyncomp(devlink, dyncompp, l_errnop); 644 S_FREE(devlink); 645 if (ret == SCFGA_OK) { 646 assert(*dyncompp != NULL); 647 return (SCFGA_OK); 648 } 649 650 /* 651 * Failed to get devlink based dynamic component. 652 * Try driver and instance 653 */ 654 } 655 656 ret = drv_to_dyncomp(node, physpath, dyncompp, l_errnop); 657 assert(ret != SCFGA_OK || *dyncompp != NULL); 658 659 return (ret); 660 } 661 662 /* 663 * Create a dynamic component of path ap_id for the given path info node. 664 * The caller should free the buffer for the dynamic component. 665 */ 666 scfga_ret_t 667 make_path_dyncomp( 668 di_path_t path, 669 char **dyncompp, 670 int *l_errnop) 671 { 672 char *pi_addr; 673 674 if ((path == DI_PATH_NIL) || (*dyncompp != NULL)) { 675 return (SCFGA_LIB_ERR); 676 } 677 678 if ((pi_addr = di_path_bus_addr(path)) != NULL) { 679 *dyncompp = calloc(1, strlen(pi_addr) + 1); 680 if (*dyncompp == NULL) { 681 *l_errnop = errno; 682 return (SCFGA_LIB_ERR); 683 } 684 (void) strncpy(*dyncompp, pi_addr, strlen(pi_addr)); 685 } else { 686 return (SCFGA_LIB_ERR); 687 } 688 689 return (SCFGA_OK); 690 } 691 692 /*ARGSUSED*/ 693 static scfga_ret_t 694 drv_to_dyncomp(di_node_t node, const char *phys, char **dyncompp, int *l_errnop) 695 { 696 char *drv; 697 int inst; 698 const int dynlen = MAXPATHLEN; 699 scfga_ret_t ret; 700 701 *l_errnop = 0; 702 703 if ((*dyncompp = calloc(1, dynlen)) == NULL) { 704 *l_errnop = errno; 705 return (SCFGA_LIB_ERR); 706 } 707 708 drv = di_driver_name(node); 709 inst = di_instance(node); 710 if (drv != NULL && inst != -1) { 711 if (snprintf(*dyncompp, dynlen, "%s%d", drv, inst) < dynlen) { 712 return (SCFGA_OK); 713 } else { 714 ret = SCFGA_LIB_ERR; 715 } 716 } else { 717 ret = SCFGA_APID_NOEXIST; 718 } 719 720 S_FREE(*dyncompp); 721 return (ret); 722 } 723 724 /* Get a dynamic component from a physical path if possible */ 725 static scfga_ret_t 726 devlink_to_dyncomp(char *devlink, char **dyncompp, int *l_errnop) 727 { 728 int i; 729 dyn_t dynt = {NULL}; 730 731 *l_errnop = 0; 732 733 if (*dyncompp != NULL) { 734 return (SCFGA_LIB_ERR); 735 } 736 737 /* Convert devlink to dynamic component */ 738 dynt.devlink = devlink; 739 dynt.ret = SCFGA_APID_NOEXIST; 740 741 for (i = 0; i < N_DYNRULES; i++) { 742 if (dyncvt_rules[i].devlink_to_dyncomp_p(&dynt) 743 != SCFGA_CONTINUE) { 744 break; 745 } 746 } 747 748 if (i >= N_DYNRULES) { 749 dynt.ret = SCFGA_APID_NOEXIST; 750 } 751 752 if (dynt.ret == SCFGA_OK) { 753 assert(dynt.dyncomp != NULL); 754 *dyncompp = dynt.dyncomp; 755 } 756 757 return (dynt.ret); 758 } 759 760 /* For disks remove partition information, (s or p) */ 761 static scfga_recur_t 762 disk_devlink_to_dyncomp(dyn_t *dyntp) 763 { 764 char *cp = NULL, *cp1 = NULL; 765 766 assert(dyntp->devlink != NULL); 767 768 dyntp->l_errno = 0; 769 770 if (dyntp->dyncomp != NULL) { 771 goto lib_err; 772 } 773 774 /* Check if a disk devlink */ 775 if (strncmp(dyntp->devlink, DEV_DSK SLASH, strlen(DEV_DSK SLASH)) && 776 strncmp(dyntp->devlink, DEV_RDSK SLASH, strlen(DEV_RDSK SLASH))) { 777 return (SCFGA_CONTINUE); 778 } 779 780 cp = dyntp->devlink + strlen(DEV_DIR SLASH); 781 782 if ((dyntp->dyncomp = strdup(cp)) == NULL) { 783 dyntp->l_errno = errno; 784 goto lib_err; 785 } 786 787 /* Get the leaf component from dsk/cXtYdZsN */ 788 cp1 = strrchr(dyntp->dyncomp, '/'); 789 790 /* Blank out partition information */ 791 dyntp->ret = SCFGA_OK; 792 if ((cp = strchr(cp1 + 1, 's')) != NULL) { 793 *cp = '\0'; 794 } else if ((cp = strchr(cp1 + 1, 'p')) != NULL) { 795 *cp = '\0'; 796 } else { 797 S_FREE(dyntp->dyncomp); 798 dyntp->ret = SCFGA_ERR; 799 } 800 801 return (SCFGA_TERMINATE); 802 803 lib_err: 804 dyntp->ret = SCFGA_LIB_ERR; 805 return (SCFGA_TERMINATE); 806 } 807 808 809 static scfga_recur_t 810 disk_dyncomp_to_devlink(dyn_t *dyntp) 811 { 812 char buf[MAXPATHLEN], *cp = NULL; 813 int i, j; 814 size_t len; 815 struct stat sbuf; 816 817 assert(dyntp->dyncomp != NULL); 818 819 dyntp->l_errno = 0; 820 821 if (dyntp->devlink != NULL) { 822 dyntp->ret = SCFGA_LIB_ERR; 823 return (SCFGA_TERMINATE); 824 } 825 826 /* A disk link can only be from DEV_DSK (ignore /dev/rdsk) */ 827 if (strncmp(dyntp->dyncomp, DSK_DIR SLASH, strlen(DSK_DIR SLASH)) != 0) 828 return (SCFGA_CONTINUE); /* not a disk link */ 829 830 (void) snprintf(buf, sizeof (buf), "%s%s", DEV_DIR SLASH, 831 dyntp->dyncomp); 832 833 len = strlen(buf); 834 cp = buf + len; 835 len = sizeof (buf) - len; 836 837 for (i = 0; i < N_SLICE_TYPES; i++) { 838 for (j = 0; j < disk_slices[i].nslices; j++) { 839 if (snprintf(cp, len, "%s%d", disk_slices[i].prefix, j) 840 >= len) { 841 continue; 842 } 843 844 if (lstat(buf, &sbuf) != -1 && S_ISLNK(sbuf.st_mode)) { 845 if ((dyntp->devlink = strdup(buf)) == NULL) { 846 dyntp->l_errno = errno; 847 dyntp->ret = SCFGA_LIB_ERR; 848 return (SCFGA_TERMINATE); 849 } 850 dyntp->ret = SCFGA_OK; 851 return (SCFGA_TERMINATE); 852 } 853 } 854 } 855 856 dyntp->ret = SCFGA_APID_NOEXIST; 857 return (SCFGA_TERMINATE); 858 } 859 860 /* For tapes, remove mode(minor) information from link */ 861 static scfga_recur_t 862 tape_devlink_to_dyncomp(dyn_t *dyntp) 863 { 864 char *cp = NULL; 865 866 assert(dyntp->devlink != NULL); 867 868 dyntp->l_errno = 0; 869 870 if (dyntp->dyncomp != NULL) { 871 goto lib_err; 872 } 873 874 if (strncmp(dyntp->devlink, DEV_RMT SLASH, strlen(DEV_RMT SLASH))) { 875 return (SCFGA_CONTINUE); /* not a tape */ 876 } 877 878 cp = dyntp->devlink + strlen(DEV_DIR SLASH); 879 if ((dyntp->dyncomp = strdup(cp)) == NULL) { 880 dyntp->l_errno = errno; 881 goto lib_err; 882 } 883 884 /* Get the leaf component from rmt/xyz */ 885 cp = strrchr(dyntp->dyncomp, '/'); 886 887 /* Remove the mode part */ 888 while (isdigit(*(++cp))) { 889 }; 890 *cp = '\0'; 891 892 893 dyntp->ret = SCFGA_OK; 894 return (SCFGA_TERMINATE); 895 896 lib_err: 897 dyntp->ret = SCFGA_LIB_ERR; 898 return (SCFGA_TERMINATE); 899 } 900 901 static scfga_recur_t 902 tape_dyncomp_to_devlink(dyn_t *dyntp) 903 { 904 char buf[MAXPATHLEN], *cp = NULL; 905 int i; 906 size_t len = 0; 907 struct stat sbuf; 908 909 assert(dyntp->dyncomp != NULL); 910 911 dyntp->l_errno = 0; 912 913 if (dyntp->devlink != NULL) { 914 goto lib_err; 915 } 916 917 if (strncmp(dyntp->dyncomp, RMT_DIR SLASH, strlen(RMT_DIR SLASH))) { 918 return (SCFGA_CONTINUE); /* not a tape */ 919 } 920 921 /* A tape device */ 922 (void) snprintf(buf, sizeof (buf), "%s%s", DEV_DIR SLASH, 923 dyntp->dyncomp); 924 925 len = strlen(buf); 926 cp = buf + len; 927 len = sizeof (buf) - len; 928 929 for (i = 0; i < N_TAPE_MODES; i++) { 930 (void) snprintf(cp, len, "%s", tape_modes[i]); 931 932 if (lstat(buf, &sbuf) != -1 && S_ISLNK(sbuf.st_mode)) { 933 if ((dyntp->devlink = strdup(buf)) == NULL) { 934 dyntp->l_errno = errno; 935 goto lib_err; 936 } 937 dyntp->ret = SCFGA_OK; 938 return (SCFGA_TERMINATE); 939 } 940 } 941 942 dyntp->ret = SCFGA_APID_NOEXIST; 943 return (SCFGA_TERMINATE); 944 945 lib_err: 946 dyntp->ret = SCFGA_LIB_ERR; 947 return (SCFGA_TERMINATE); 948 949 } 950 951 /* 952 * Default rules 953 */ 954 static scfga_recur_t 955 def_devlink_to_dyncomp(dyn_t *dyntp) 956 { 957 size_t len = 0; 958 char *cp = NULL; 959 960 assert(dyntp->devlink != NULL); 961 962 dyntp->l_errno = 0; 963 964 if (dyntp->dyncomp != NULL) { 965 dyntp->ret = SCFGA_LIB_ERR; 966 return (SCFGA_TERMINATE); 967 } 968 969 /* Is it a link in DEV_DIR directory ? */ 970 len = strlen(DEV_DIR SLASH); 971 if (strncmp(dyntp->devlink, DEV_DIR SLASH, len)) { 972 return (SCFGA_CONTINUE); 973 } 974 975 /* Check if this is a top level devlink */ 976 if (strchr(dyntp->devlink + len, '/') != NULL) { 977 /* not top level - Remove DEV_DIR SLASH prefix */ 978 cp = dyntp->devlink + len; 979 } else { 980 /* top level, leave DEV_DIR SLASH part in */ 981 cp = dyntp->devlink; 982 } 983 984 if ((dyntp->dyncomp = strdup(cp)) == NULL) { 985 dyntp->l_errno = errno; 986 dyntp->ret = SCFGA_LIB_ERR; 987 } else { 988 dyntp->ret = SCFGA_OK; 989 } 990 991 return (SCFGA_TERMINATE); 992 993 } 994 995 static scfga_recur_t 996 def_dyncomp_to_devlink(dyn_t *dyntp) 997 { 998 struct stat sbuf; 999 int top; 1000 size_t prelen, linklen; 1001 1002 assert(dyntp->dyncomp != NULL); 1003 1004 dyntp->l_errno = 0; 1005 1006 if (dyntp->devlink != NULL) { 1007 goto lib_err; 1008 } 1009 1010 prelen = strlen(DEV_DIR SLASH); 1011 linklen = strlen(dyntp->dyncomp) + 1; 1012 1013 /* 1014 * Check if the dynamic component was derived from a top level entry 1015 * in "/dev" 1016 */ 1017 if (strncmp(dyntp->dyncomp, DEV_DIR SLASH, prelen) == 0) { 1018 top = 1; 1019 } else if (*dyntp->dyncomp != '/' && linklen > 1 && 1020 strchr(dyntp->dyncomp + 1, '/') != NULL) { 1021 top = 0; 1022 linklen += prelen; /* The "/dev/" needs to be prepended */ 1023 } else { 1024 /* Not a dynamic component we handle */ 1025 return (SCFGA_CONTINUE); 1026 } 1027 1028 if ((dyntp->devlink = calloc(1, linklen)) == NULL) { 1029 dyntp->l_errno = errno; 1030 goto lib_err; 1031 } 1032 1033 *dyntp->devlink = '\0'; 1034 if (!top) { 1035 (void) strcpy(dyntp->devlink, DEV_DIR SLASH); 1036 } 1037 (void) strcat(dyntp->devlink, dyntp->dyncomp); 1038 1039 if (lstat(dyntp->devlink, &sbuf) != -1 && S_ISLNK(sbuf.st_mode)) { 1040 dyntp->ret = SCFGA_OK; 1041 return (SCFGA_TERMINATE); 1042 } 1043 1044 1045 S_FREE(dyntp->devlink); 1046 return (SCFGA_CONTINUE); 1047 1048 lib_err: 1049 dyntp->ret = SCFGA_LIB_ERR; 1050 return (SCFGA_TERMINATE); 1051 } 1052