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 1999, 2001-2002 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 "cfga_scsi.h" 30 31 typedef struct { 32 char *dyncomp; 33 char *devlink; 34 int l_errno; 35 scfga_ret_t ret; 36 } dyn_t; 37 38 typedef struct { 39 scfga_recur_t (*devlink_to_dyncomp_p)(dyn_t *dyntp); 40 scfga_recur_t (*dyncomp_to_devlink_p)(dyn_t *dyntp); 41 } dynrules_t; 42 43 typedef struct { 44 dyn_t *dynp; 45 dynrules_t *rule_array; 46 int nrules; 47 } dyncvt_t; 48 49 typedef struct { 50 const char *hba_phys; 51 const char *dyncomp; 52 char *path; 53 int l_errno; 54 scfga_ret_t ret; 55 } devpath_t; 56 57 58 59 /* Function prototypes */ 60 61 static int drv_to_hba_logid(di_node_t node, di_minor_t minor, void *arg); 62 static scfga_ret_t drv_dyn_to_devpath(const char *hba_phys, 63 const char *dyncomp, char **pathpp, int *l_errnop); 64 static int do_drv_dyn_to_devpath(di_node_t node, void *arg); 65 static scfga_ret_t devlink_dyn_to_devpath(const char *hba_phys, 66 const char *dyncomp, char **pathpp, int *l_errnop); 67 68 static scfga_recur_t disk_dyncomp_to_devlink(dyn_t *dyntp); 69 static scfga_recur_t tape_dyncomp_to_devlink(dyn_t *dyntp); 70 static scfga_recur_t def_dyncomp_to_devlink(dyn_t *dyntp); 71 72 static scfga_ret_t devlink_to_dyncomp(char *devlink, 73 char **dyncompp, int *l_errnop); 74 static scfga_recur_t disk_devlink_to_dyncomp(dyn_t *dyntp); 75 static scfga_recur_t tape_devlink_to_dyncomp(dyn_t *dyntp); 76 static scfga_recur_t def_devlink_to_dyncomp(dyn_t *dyntp); 77 static scfga_ret_t drv_to_dyncomp(di_node_t node, const char *phys, 78 char **dyncompp, int *l_errnop); 79 static scfga_ret_t get_hba_devlink(const char *hba_phys, 80 char **hba_logpp, int *l_errnop); 81 82 83 /* Globals */ 84 85 /* 86 * Rules for converting between a devlink and logical ap_id and vice-versa 87 * The default rules must be the last entry. 88 */ 89 static dynrules_t dyncvt_rules[] = { 90 {disk_devlink_to_dyncomp, disk_dyncomp_to_devlink}, 91 {tape_devlink_to_dyncomp, tape_dyncomp_to_devlink}, 92 {def_devlink_to_dyncomp, def_dyncomp_to_devlink} 93 }; 94 95 #define N_DYNRULES (sizeof (dyncvt_rules)/sizeof (dyncvt_rules[0])) 96 97 /* 98 * Numbering of disk slices is assumed to be 0 through n - 1 99 */ 100 typedef struct { 101 char *prefix; 102 int nslices; 103 } slice_t; 104 105 static slice_t disk_slices[] = { 106 {"s", 16}, 107 {"p", 5}, 108 }; 109 110 #define N_SLICE_TYPES (sizeof (disk_slices) / sizeof (disk_slices[0])) 111 112 static const char *tape_modes[] = { 113 "", 114 "b", "bn", 115 "c", "cb", "cbn", "cn", 116 "h", "hb", "hbn", "hn", 117 "l", "lb", "lbn", "ln", 118 "m", "mb", "mbn", "mn", 119 "n", 120 "u", "ub", "ubn", "un" 121 }; 122 123 #define N_TAPE_MODES (sizeof (tape_modes) / sizeof (tape_modes[0])) 124 125 126 /* Various conversions routines */ 127 128 /* 129 * Generates the HBA logical ap_id from physical ap_id. 130 */ 131 scfga_ret_t 132 make_hba_logid(const char *hba_phys, char **hba_logpp, int *l_errnop) 133 { 134 walkarg_t u; 135 pathm_t pmt = {NULL}; 136 scfga_ret_t ret; 137 138 139 if (*hba_logpp != NULL) { 140 return (SCFGA_ERR); 141 } 142 143 /* A devlink for the HBA may or may not exist */ 144 if (get_hba_devlink(hba_phys, hba_logpp, l_errnop) == SCFGA_OK) { 145 assert(*hba_logpp != NULL); 146 return (SCFGA_OK); 147 } 148 149 /* 150 * No devlink based logical ap_id. 151 * Try driver name and instance number. 152 */ 153 u.minor_args.nodetype = DDI_NT_SCSI_ATTACHMENT_POINT; 154 u.minor_args.fcn = drv_to_hba_logid; 155 156 pmt.phys = (char *)hba_phys; 157 pmt.ret = SCFGA_APID_NOEXIST; 158 159 errno = 0; 160 ret = walk_tree(pmt.phys, &pmt, DINFOMINOR | DINFOPROP, &u, 161 SCFGA_WALK_MINOR, &pmt.l_errno); 162 if (ret == SCFGA_OK && (ret = pmt.ret) == SCFGA_OK) { 163 assert(pmt.log != NULL); 164 *hba_logpp = pmt.log; 165 return (SCFGA_OK); 166 } 167 168 /* failed to create logical ap_id */ 169 if (pmt.log != NULL) { 170 S_FREE(pmt.log); 171 } 172 173 174 *l_errnop = pmt.l_errno; 175 return (ret); 176 } 177 178 static scfga_ret_t 179 get_hba_devlink(const char *hba_phys, char **hba_logpp, int *l_errnop) 180 { 181 size_t len; 182 scfga_ret_t ret; 183 int match_minor = 1; 184 185 ret = physpath_to_devlink((char *)hba_phys, hba_logpp, 186 l_errnop, match_minor); 187 if (ret != SCFGA_OK) { 188 return (ret); 189 } 190 191 assert(*hba_logpp != NULL); 192 193 /* Remove the "/dev/cfg/" prefix */ 194 len = strlen(CFGA_DEV_DIR SLASH); 195 196 (void) memmove(*hba_logpp, *hba_logpp + len, 197 strlen(*hba_logpp + len) + 1); 198 199 return (SCFGA_OK); 200 } 201 202 /* Make logical name for HBA based on driver and instance */ 203 static int 204 drv_to_hba_logid(di_node_t node, di_minor_t minor, void *arg) 205 { 206 int inst; 207 char *drv, *mn, *log; 208 pathm_t *ptp; 209 const size_t loglen = MAXPATHLEN; 210 211 ptp = (pathm_t *)arg; 212 213 errno = 0; 214 215 mn = di_minor_name(minor); 216 drv = di_driver_name(node); 217 inst = di_instance(node); 218 log = calloc(1, loglen); 219 220 if (mn != NULL && drv != NULL && inst != -1 && log != NULL) { 221 /* Count does not include terminating NULL */ 222 if (snprintf(log, loglen, "%s%d:%s", drv, inst, mn) < loglen) { 223 ptp->ret = SCFGA_OK; 224 ptp->log = log; 225 return (DI_WALK_TERMINATE); 226 } 227 } 228 229 S_FREE(log); 230 return (DI_WALK_CONTINUE); 231 } 232 233 /* 234 * Given a bus or device ap_id <hba_phys, dyncomp>, returns the physical 235 * path in pathpp. 236 * Returns: SCFGA_APID_NOEXIST if the path does not exist. 237 */ 238 239 scfga_ret_t 240 apid_to_path( 241 const char *hba_phys, 242 const char *dyncomp, 243 char **pathpp, 244 int *l_errnop) 245 { 246 scfga_ret_t ret; 247 248 if (*pathpp != NULL) { 249 return (SCFGA_LIB_ERR); 250 } 251 252 /* If a bus, the physical ap_id is the physical path */ 253 if (dyncomp == NULL) { 254 if ((*pathpp = strdup(hba_phys)) == NULL) { 255 *l_errnop = errno; 256 return (SCFGA_LIB_ERR); 257 } 258 return (SCFGA_OK); 259 } 260 261 /* Dynamic component exists, we have a device */ 262 263 /* 264 * If the dynamic component has a '/', it was derived from a devlink 265 * Else it was derived from driver name and instance number. 266 */ 267 if (strchr(dyncomp, '/') != NULL) { 268 ret = devlink_dyn_to_devpath(hba_phys, dyncomp, pathpp, 269 l_errnop); 270 } else { 271 ret = drv_dyn_to_devpath(hba_phys, dyncomp, pathpp, l_errnop); 272 } 273 274 assert(ret != SCFGA_OK || *pathpp != NULL); 275 276 return (ret); 277 } 278 279 static scfga_ret_t 280 drv_dyn_to_devpath( 281 const char *hba_phys, 282 const char *dyncomp, 283 char **pathpp, 284 int *l_errnop) 285 { 286 walkarg_t u; 287 devpath_t dpt = {NULL}; 288 scfga_ret_t ret; 289 290 /* A device MUST have a dynamic component */ 291 if (dyncomp == NULL || *pathpp != NULL) { 292 return (SCFGA_LIB_ERR); 293 } 294 295 u.node_args.flags = DI_WALK_CLDFIRST; 296 u.node_args.fcn = do_drv_dyn_to_devpath; 297 298 dpt.hba_phys = hba_phys; 299 dpt.dyncomp = dyncomp; 300 dpt.ret = SCFGA_APID_NOEXIST; 301 302 ret = walk_tree(hba_phys, &dpt, DINFOCPYALL, &u, 303 SCFGA_WALK_NODE, &dpt.l_errno); 304 305 if (ret == SCFGA_OK && (ret = dpt.ret) == SCFGA_OK) { 306 assert(dpt.path != NULL); 307 *pathpp = dpt.path; 308 return (SCFGA_OK); 309 } 310 311 if (dpt.path != NULL) { 312 S_FREE(dpt.path); 313 } 314 315 316 *l_errnop = dpt.l_errno; 317 return (ret); 318 } 319 320 /* Converts a driver and instance number based logid into a physical path */ 321 static int 322 do_drv_dyn_to_devpath(di_node_t node, void *arg) 323 { 324 int inst, rv, match_minor; 325 devpath_t *dptp; 326 char *physpath, *drv; 327 char *drvinst, *devpath; 328 const size_t drvlen = MAXPATHLEN; 329 size_t devlen; 330 331 dptp = (devpath_t *)arg; 332 333 assert(dptp->hba_phys != NULL && dptp->dyncomp != NULL); 334 assert(dptp->path == NULL); 335 336 /* 337 * Skip stub nodes 338 */ 339 if (IS_STUB_NODE(node)) { 340 return (DI_WALK_CONTINUE); 341 } 342 343 errno = 0; 344 345 drv = di_driver_name(node); 346 inst = di_instance(node); 347 physpath = di_devfs_path(node); 348 if (drv == NULL || inst == -1 || physpath == NULL) { 349 rv = DI_WALK_CONTINUE; 350 goto out; 351 } 352 353 devlen = strlen(DEVICES_DIR) + strlen(physpath) + 1; 354 355 devpath = calloc(1, devlen); 356 drvinst = calloc(1, drvlen); 357 if (devpath == NULL || drvinst == NULL) { 358 dptp->l_errno = errno; 359 dptp->ret = SCFGA_LIB_ERR; 360 rv = DI_WALK_TERMINATE; 361 goto out; 362 } 363 364 (void) snprintf(drvinst, drvlen, "%s%d", drv, inst); 365 366 /* Create the physical path */ 367 (void) snprintf(devpath, devlen, "%s%s", DEVICES_DIR, physpath); 368 369 /* Skip node if it is the HBA */ 370 match_minor = 0; 371 if (!dev_cmp(dptp->hba_phys, devpath, match_minor)) { 372 rv = DI_WALK_CONTINUE; 373 goto out; 374 } 375 376 /* Compare the base and dynamic components */ 377 if (!hba_dev_cmp(dptp->hba_phys, devpath) && 378 strcmp(dptp->dyncomp, drvinst) == 0) { 379 dptp->ret = SCFGA_OK; 380 dptp->path = devpath; 381 rv = DI_WALK_TERMINATE; 382 } else { 383 rv = DI_WALK_CONTINUE; 384 } 385 386 /*FALLTHRU*/ 387 out: 388 S_FREE(drvinst); 389 if (physpath != NULL) di_devfs_path_free(physpath); 390 if (dptp->ret != SCFGA_OK) S_FREE(devpath); 391 return (rv); 392 } 393 394 /* readlink wrapper to ensure proper null termination of the results */ 395 static int 396 s_readlink(char *link, char *buf, int len) 397 { 398 int count; 399 400 count = readlink(link, buf, len - 1); 401 if (count != -1) 402 buf[count] = '\0'; 403 return (count); 404 } 405 406 /* Converts a devlink based dynamic component to a path */ 407 static scfga_ret_t 408 devlink_dyn_to_devpath( 409 const char *hba_phys, 410 const char *dyncomp, 411 char **pathpp, 412 int *l_errnop) 413 { 414 dyn_t dynt = {NULL}; 415 int i; 416 scfga_ret_t ret; 417 char buf[PATH_MAX], *path; 418 419 if (*pathpp != NULL) { 420 return (SCFGA_LIB_ERR); 421 } 422 423 /* Convert the dynamic component to the corresponding devlink */ 424 dynt.dyncomp = (char *)dyncomp; 425 dynt.ret = SCFGA_APID_NOEXIST; 426 427 for (i = 0; i < N_DYNRULES; i++) { 428 if (dyncvt_rules[i].dyncomp_to_devlink_p(&dynt) 429 != SCFGA_CONTINUE) { 430 break; 431 } 432 } 433 434 if (i >= N_DYNRULES) { 435 dynt.ret = SCFGA_APID_NOEXIST; 436 } 437 438 if (dynt.ret != SCFGA_OK) { 439 /* No symlink or error */ 440 return (dynt.ret); 441 } 442 443 assert(dynt.devlink != NULL); 444 445 /* 446 * Follow devlink to get the physical path 447 * Note: Do not use realpath(). It will stat() device 448 * and stat() fails under devfs if device is offline. 449 */ 450 errno = 0; 451 if ((s_readlink(dynt.devlink, buf, PATH_MAX) == -1) || 452 ((path = strstr(buf, "/devices/")) == NULL) || 453 ((*pathpp = strdup(path)) == NULL)) { 454 *l_errnop = errno; 455 ret = SCFGA_LIB_ERR; 456 goto out; 457 } 458 459 /* Compare base components as well */ 460 if (!hba_dev_cmp(hba_phys, path)) { 461 ret = SCFGA_OK; 462 } else { 463 /* Mismatched base and dynamic component */ 464 *l_errnop = 0; 465 ret = SCFGA_APID_NOEXIST; 466 } 467 468 /*FALLTHRU*/ 469 out: 470 S_FREE(dynt.devlink); 471 if (ret != SCFGA_OK) S_FREE(*pathpp); 472 return (ret); 473 } 474 475 scfga_ret_t 476 make_dyncomp( 477 di_node_t node, 478 const char *physpath, 479 char **dyncompp, 480 int *l_errnop) 481 { 482 char *devlink = NULL; 483 scfga_ret_t ret; 484 di_minor_t minor; 485 char *path; 486 char pathbuf[MAXPATHLEN]; 487 int match_minor; 488 489 if (*dyncompp != NULL) { 490 return (SCFGA_LIB_ERR); 491 } 492 493 /* tag on minor name */ 494 minor = di_minor_next(node, DI_MINOR_NIL); 495 if (minor == DI_MINOR_NIL) { 496 match_minor = 0; 497 path = (char *)physpath; 498 } else { 499 match_minor = 1; 500 snprintf(pathbuf, MAXPATHLEN, "%s:%s", physpath, 501 di_minor_name(minor)); 502 path = pathbuf; 503 } 504 505 /* Get the corresponding devlink from the physical path */ 506 ret = physpath_to_devlink(path, &devlink, l_errnop, match_minor); 507 if (ret == SCFGA_OK) { 508 assert(devlink != NULL); 509 510 /* Create dynamic component. */ 511 ret = devlink_to_dyncomp(devlink, dyncompp, l_errnop); 512 S_FREE(devlink); 513 if (ret == SCFGA_OK) { 514 assert(*dyncompp != NULL); 515 return (SCFGA_OK); 516 } 517 518 /* 519 * Failed to get devlink based dynamic component. 520 * Try driver and instance 521 */ 522 } 523 524 ret = drv_to_dyncomp(node, physpath, dyncompp, l_errnop); 525 assert(ret != SCFGA_OK || *dyncompp != NULL); 526 527 return (ret); 528 } 529 530 /*ARGSUSED*/ 531 static scfga_ret_t 532 drv_to_dyncomp(di_node_t node, const char *phys, char **dyncompp, int *l_errnop) 533 { 534 char *drv; 535 int inst; 536 const int dynlen = MAXPATHLEN; 537 scfga_ret_t ret; 538 539 *l_errnop = 0; 540 541 if ((*dyncompp = calloc(1, dynlen)) == NULL) { 542 *l_errnop = errno; 543 return (SCFGA_LIB_ERR); 544 } 545 546 drv = di_driver_name(node); 547 inst = di_instance(node); 548 if (drv != NULL && inst != -1) { 549 if (snprintf(*dyncompp, dynlen, "%s%d", drv, inst) < dynlen) { 550 return (SCFGA_OK); 551 } else { 552 ret = SCFGA_LIB_ERR; 553 } 554 } else { 555 ret = SCFGA_APID_NOEXIST; 556 } 557 558 S_FREE(*dyncompp); 559 return (ret); 560 } 561 562 /* Get a dynamic component from a physical path if possible */ 563 static scfga_ret_t 564 devlink_to_dyncomp(char *devlink, char **dyncompp, int *l_errnop) 565 { 566 int i; 567 dyn_t dynt = {NULL}; 568 569 *l_errnop = 0; 570 571 if (*dyncompp != NULL) { 572 return (SCFGA_LIB_ERR); 573 } 574 575 /* Convert devlink to dynamic component */ 576 dynt.devlink = devlink; 577 dynt.ret = SCFGA_APID_NOEXIST; 578 579 for (i = 0; i < N_DYNRULES; i++) { 580 if (dyncvt_rules[i].devlink_to_dyncomp_p(&dynt) 581 != SCFGA_CONTINUE) { 582 break; 583 } 584 } 585 586 if (i >= N_DYNRULES) { 587 dynt.ret = SCFGA_APID_NOEXIST; 588 } 589 590 if (dynt.ret == SCFGA_OK) { 591 assert(dynt.dyncomp != NULL); 592 *dyncompp = dynt.dyncomp; 593 } 594 595 return (dynt.ret); 596 } 597 598 /* For disks remove partition information, (s or p) */ 599 static scfga_recur_t 600 disk_devlink_to_dyncomp(dyn_t *dyntp) 601 { 602 char *cp = NULL, *cp1 = NULL; 603 604 assert(dyntp->devlink != NULL); 605 606 dyntp->l_errno = 0; 607 608 if (dyntp->dyncomp != NULL) { 609 goto lib_err; 610 } 611 612 /* Check if a disk devlink */ 613 if (strncmp(dyntp->devlink, DEV_DSK SLASH, strlen(DEV_DSK SLASH)) && 614 strncmp(dyntp->devlink, DEV_RDSK SLASH, strlen(DEV_RDSK SLASH))) { 615 return (SCFGA_CONTINUE); 616 } 617 618 cp = dyntp->devlink + strlen(DEV_DIR SLASH); 619 620 if ((dyntp->dyncomp = strdup(cp)) == NULL) { 621 dyntp->l_errno = errno; 622 goto lib_err; 623 } 624 625 /* Get the leaf component from dsk/cXtYdZsN */ 626 cp1 = strrchr(dyntp->dyncomp, '/'); 627 628 /* Blank out partition information */ 629 dyntp->ret = SCFGA_OK; 630 if ((cp = strchr(cp1 + 1, 's')) != NULL) { 631 *cp = '\0'; 632 } else if ((cp = strchr(cp1 + 1, 'p')) != NULL) { 633 *cp = '\0'; 634 } else { 635 S_FREE(dyntp->dyncomp); 636 dyntp->ret = SCFGA_ERR; 637 } 638 639 return (SCFGA_TERMINATE); 640 641 lib_err: 642 dyntp->ret = SCFGA_LIB_ERR; 643 return (SCFGA_TERMINATE); 644 } 645 646 647 static scfga_recur_t 648 disk_dyncomp_to_devlink(dyn_t *dyntp) 649 { 650 char buf[MAXPATHLEN], *cp = NULL; 651 int i, j; 652 size_t len; 653 struct stat sbuf; 654 655 assert(dyntp->dyncomp != NULL); 656 657 dyntp->l_errno = 0; 658 659 if (dyntp->devlink != NULL) { 660 dyntp->ret = SCFGA_LIB_ERR; 661 return (SCFGA_TERMINATE); 662 } 663 664 /* A disk link can only be from DEV_DSK (ignore /dev/rdsk) */ 665 if (strncmp(dyntp->dyncomp, DSK_DIR SLASH, strlen(DSK_DIR SLASH)) != 0) 666 return (SCFGA_CONTINUE); /* not a disk link */ 667 668 (void) snprintf(buf, sizeof (buf), "%s%s", DEV_DIR SLASH, 669 dyntp->dyncomp); 670 671 len = strlen(buf); 672 cp = buf + len; 673 len = sizeof (buf) - len; 674 675 for (i = 0; i < N_SLICE_TYPES; i++) { 676 for (j = 0; j < disk_slices[i].nslices; j++) { 677 if (snprintf(cp, len, "%s%d", disk_slices[i].prefix, j) 678 >= len) { 679 continue; 680 } 681 682 if (lstat(buf, &sbuf) != -1 && S_ISLNK(sbuf.st_mode)) { 683 if ((dyntp->devlink = strdup(buf)) == NULL) { 684 dyntp->l_errno = errno; 685 dyntp->ret = SCFGA_LIB_ERR; 686 return (SCFGA_TERMINATE); 687 } 688 dyntp->ret = SCFGA_OK; 689 return (SCFGA_TERMINATE); 690 } 691 } 692 } 693 694 dyntp->ret = SCFGA_APID_NOEXIST; 695 return (SCFGA_TERMINATE); 696 } 697 698 /* For tapes, remove mode(minor) information from link */ 699 static scfga_recur_t 700 tape_devlink_to_dyncomp(dyn_t *dyntp) 701 { 702 char *cp = NULL; 703 704 assert(dyntp->devlink != NULL); 705 706 dyntp->l_errno = 0; 707 708 if (dyntp->dyncomp != NULL) { 709 goto lib_err; 710 } 711 712 if (strncmp(dyntp->devlink, DEV_RMT SLASH, strlen(DEV_RMT SLASH))) { 713 return (SCFGA_CONTINUE); /* not a tape */ 714 } 715 716 cp = dyntp->devlink + strlen(DEV_DIR SLASH); 717 if ((dyntp->dyncomp = strdup(cp)) == NULL) { 718 dyntp->l_errno = errno; 719 goto lib_err; 720 } 721 722 /* Get the leaf component from rmt/xyz */ 723 cp = strrchr(dyntp->dyncomp, '/'); 724 725 /* Remove the mode part */ 726 while (isdigit(*(++cp))); 727 *cp = '\0'; 728 729 730 dyntp->ret = SCFGA_OK; 731 return (SCFGA_TERMINATE); 732 733 lib_err: 734 dyntp->ret = SCFGA_LIB_ERR; 735 return (SCFGA_TERMINATE); 736 } 737 738 static scfga_recur_t 739 tape_dyncomp_to_devlink(dyn_t *dyntp) 740 { 741 char buf[MAXPATHLEN], *cp = NULL; 742 int i; 743 size_t len = 0; 744 struct stat sbuf; 745 746 assert(dyntp->dyncomp != NULL); 747 748 dyntp->l_errno = 0; 749 750 if (dyntp->devlink != NULL) { 751 goto lib_err; 752 } 753 754 if (strncmp(dyntp->dyncomp, RMT_DIR SLASH, strlen(RMT_DIR SLASH))) { 755 return (SCFGA_CONTINUE); /* not a tape */ 756 } 757 758 /* A tape device */ 759 (void) snprintf(buf, sizeof (buf), "%s%s", DEV_DIR SLASH, 760 dyntp->dyncomp); 761 762 len = strlen(buf); 763 cp = buf + len; 764 len = sizeof (buf) - len; 765 766 for (i = 0; i < N_TAPE_MODES; i++) { 767 (void) snprintf(cp, len, "%s", tape_modes[i]); 768 769 if (lstat(buf, &sbuf) != -1 && S_ISLNK(sbuf.st_mode)) { 770 if ((dyntp->devlink = strdup(buf)) == NULL) { 771 dyntp->l_errno = errno; 772 goto lib_err; 773 } 774 dyntp->ret = SCFGA_OK; 775 return (SCFGA_TERMINATE); 776 } 777 } 778 779 dyntp->ret = SCFGA_APID_NOEXIST; 780 return (SCFGA_TERMINATE); 781 782 lib_err: 783 dyntp->ret = SCFGA_LIB_ERR; 784 return (SCFGA_TERMINATE); 785 786 } 787 788 /* 789 * Default rules 790 */ 791 static scfga_recur_t 792 def_devlink_to_dyncomp(dyn_t *dyntp) 793 { 794 size_t len = 0; 795 char *cp = NULL; 796 797 assert(dyntp->devlink != NULL); 798 799 dyntp->l_errno = 0; 800 801 if (dyntp->dyncomp != NULL) { 802 dyntp->ret = SCFGA_LIB_ERR; 803 return (SCFGA_TERMINATE); 804 } 805 806 /* Is it a link in DEV_DIR directory ? */ 807 len = strlen(DEV_DIR SLASH); 808 if (strncmp(dyntp->devlink, DEV_DIR SLASH, len)) { 809 return (SCFGA_CONTINUE); 810 } 811 812 /* Check if this is a top level devlink */ 813 if (strchr(dyntp->devlink + len, '/') != NULL) { 814 /* not top level - Remove DEV_DIR SLASH prefix */ 815 cp = dyntp->devlink + len; 816 } else { 817 /* top level, leave DEV_DIR SLASH part in */ 818 cp = dyntp->devlink; 819 } 820 821 if ((dyntp->dyncomp = strdup(cp)) == NULL) { 822 dyntp->l_errno = errno; 823 dyntp->ret = SCFGA_LIB_ERR; 824 } else { 825 dyntp->ret = SCFGA_OK; 826 } 827 828 return (SCFGA_TERMINATE); 829 830 } 831 832 static scfga_recur_t 833 def_dyncomp_to_devlink(dyn_t *dyntp) 834 { 835 struct stat sbuf; 836 int top; 837 size_t prelen, linklen; 838 839 assert(dyntp->dyncomp != NULL); 840 841 dyntp->l_errno = 0; 842 843 if (dyntp->devlink != NULL) { 844 goto lib_err; 845 } 846 847 prelen = strlen(DEV_DIR SLASH); 848 linklen = strlen(dyntp->dyncomp) + 1; 849 850 /* 851 * Check if the dynamic component was derived from a top level entry 852 * in "/dev" 853 */ 854 if (strncmp(dyntp->dyncomp, DEV_DIR SLASH, prelen) == 0) { 855 top = 1; 856 } else if (*dyntp->dyncomp != '/' && linklen > 1 && 857 strchr(dyntp->dyncomp + 1, '/') != NULL) { 858 top = 0; 859 linklen += prelen; /* The "/dev/" needs to be prepended */ 860 } else { 861 /* Not a dynamic component we handle */ 862 return (SCFGA_CONTINUE); 863 } 864 865 if ((dyntp->devlink = calloc(1, linklen)) == NULL) { 866 dyntp->l_errno = errno; 867 goto lib_err; 868 } 869 870 *dyntp->devlink = '\0'; 871 if (!top) { 872 (void) strcpy(dyntp->devlink, DEV_DIR SLASH); 873 } 874 (void) strcat(dyntp->devlink, dyntp->dyncomp); 875 876 if (lstat(dyntp->devlink, &sbuf) != -1 && S_ISLNK(sbuf.st_mode)) { 877 dyntp->ret = SCFGA_OK; 878 return (SCFGA_TERMINATE); 879 } 880 881 882 S_FREE(dyntp->devlink); 883 return (SCFGA_CONTINUE); 884 885 lib_err: 886 dyntp->ret = SCFGA_LIB_ERR; 887 return (SCFGA_TERMINATE); 888 } 889