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 /* Portions Copyright 2005 Cyril Plisko */ 23 24 /* 25 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 26 * Use is subject to license terms. 27 */ 28 29 /* 30 * Copyright 2023 Oxide Computer Company 31 */ 32 33 #include <errno.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <locale.h> 38 #include <langinfo.h> 39 #include <time.h> 40 41 #if !defined(DEBUG) 42 #define NDEBUG 1 43 #else 44 #undef NDEBUG 45 #endif 46 47 #include <assert.h> 48 #include <sys/types.h> 49 #include <sys/stat.h> 50 #include <sys/param.h> 51 #include <dlfcn.h> 52 #include <synch.h> 53 #include <sys/systeminfo.h> 54 #include <sys/sunddi.h> 55 #include <libdevinfo.h> 56 #include <unistd.h> 57 #include <stdarg.h> 58 #include <limits.h> 59 #include <ftw.h> 60 #include <ctype.h> 61 62 #define CFGA_PLUGIN_LIB 63 #include <config_admin.h> 64 65 /* Limit size of sysinfo return */ 66 #define SYSINFO_LENGTH 256 67 68 /* 69 * Attachment point specifier types. 70 */ 71 typedef enum { 72 UNKNOWN_AP, 73 LOGICAL_LINK_AP, 74 LOGICAL_DRV_AP, 75 PHYSICAL_AP, 76 AP_TYPE 77 } cfga_ap_types_t; 78 79 static char *listopt_array[] = { 80 81 #define LISTOPT_CLASS 0 82 "class", 83 NULL 84 }; 85 86 typedef struct { 87 int v_min; /* Min acceptable version */ 88 int v_max; /* Max acceptable version */ 89 } vers_req_t; 90 91 #define INVALID_VERSION -1 92 #define VALID_HSL_VERS(v) (((v) >= CFGA_HSL_V1) && \ 93 ((v) <= CFGA_HSL_VERS)) 94 95 /* 96 * Incomplete definition 97 */ 98 struct cfga_vers_ops; 99 100 /* 101 * Structure that contains plugin library information. 102 */ 103 typedef struct plugin_lib { 104 struct plugin_lib *next; /* pointer to next */ 105 mutex_t lock; /* protects refcnt */ 106 int refcnt; /* reference count */ 107 void *handle; /* handle from dlopen */ 108 cfga_err_t (*cfga_change_state_p)(); 109 cfga_err_t (*cfga_private_func_p)(); 110 cfga_err_t (*cfga_test_p)(); 111 cfga_err_t (*cfga_stat_p)(); 112 cfga_err_t (*cfga_list_p)(); 113 cfga_err_t (*cfga_help_p)(); 114 int (*cfga_ap_id_cmp_p)(); 115 cfga_err_t (*cfga_list_ext_p)(); /* For V2 plug-ins only */ 116 117 int plugin_vers; /* actual plugin version */ 118 struct cfga_vers_ops *vers_ops; /* version dependant routines */ 119 char libpath[MAXPATHLEN]; /* full pathname to lib */ 120 } plugin_lib_t; 121 122 static plugin_lib_t plugin_list; 123 124 typedef struct lib_cache { 125 struct lib_cache *lc_next; 126 plugin_lib_t *lc_libp; 127 char *lc_ap_id; 128 char *lc_ap_physical; /* physical ap_id */ 129 char *lc_ap_logical; /* logical ap_id */ 130 } lib_cache_t; 131 132 static lib_cache_t *lib_cache; 133 static mutex_t lib_cache_lock; 134 135 /* 136 * Library locator data struct - used to pass down through the device 137 * tree walking code. 138 */ 139 typedef struct lib_locator { 140 char ap_base[MAXPATHLEN]; 141 char ap_logical[CFGA_LOG_EXT_LEN]; 142 char ap_physical[CFGA_PHYS_EXT_LEN]; 143 char ap_class[CFGA_CLASS_LEN]; 144 char pathname[MAXPATHLEN]; 145 plugin_lib_t *libp; 146 cfga_err_t status; 147 vers_req_t vers_req; /* plug-in version required */ 148 } lib_loc_t; 149 150 /* 151 * linked list of cfga_stat_data structs - used for 152 * config_list 153 */ 154 typedef struct stat_data_list { 155 struct stat_data_list *next; 156 cfga_stat_data_t stat_data; 157 } stat_data_list_t; 158 159 /* 160 * linked list of arrays. Each array represents a bunch 161 * of list_data_t structures returned by a single call 162 * to a plugin's cfga_list_ext() routine. 163 */ 164 typedef struct array_list { 165 struct array_list *next; 166 cfga_list_data_t *array; 167 int nelem; 168 } array_list_t; 169 170 /* 171 * encapsulate config_list args to get them through the tree 172 * walking code 173 */ 174 typedef struct list_stat { 175 const char *opts; /* Hardware specific options */ 176 char **errstr; 177 cfga_flags_t flags; 178 int *countp; /* Total number of list and stat structures */ 179 stat_data_list_t *sdl; /* Linked list of stat structures */ 180 array_list_t *al; /* Linked list of arrays of list structures */ 181 vers_req_t use_vers; /* plugin versions to be stat'ed */ 182 char *shp_errstr; /* only for shp plugin */ 183 } list_stat_t; 184 185 /* 186 * Internal operations for libcfgadm which are version dependant 187 */ 188 struct cfga_vers_ops { 189 cfga_err_t (*resolve_lib)(plugin_lib_t *libp); 190 cfga_err_t (*stat_plugin)(list_stat_t *, lib_loc_t *, char **errstring); 191 cfga_err_t (*mklog)(di_node_t, di_minor_t, plugin_lib_t *, 192 lib_loc_t *liblocp); 193 cfga_err_t (*get_cond)(lib_loc_t *, cfga_cond_t *, char **); 194 }; 195 196 197 /* 198 * Lock to protect list of libraries 199 */ 200 static mutex_t plugin_list_lock; 201 202 /* 203 * Forward declarations 204 */ 205 206 static const char *__config_strerror(cfga_err_t); 207 static void *config_calloc_check(size_t, size_t, char **); 208 static cfga_err_t resolve_lib_ref(plugin_lib_t *, lib_loc_t *); 209 static cfga_err_t config_get_lib(const char *, lib_loc_t *, char **); 210 static int check_ap(di_node_t, di_minor_t, void *); 211 static int check_ap_hp(di_node_t, di_hp_t, void *); 212 static int check_ap_impl(di_node_t, di_minor_t, di_hp_t, void *); 213 static int check_ap_phys(di_node_t, di_minor_t, void *); 214 static int check_ap_phys_hp(di_node_t, di_hp_t, void *); 215 static int check_ap_phys_impl(di_node_t, di_minor_t, di_hp_t, void *); 216 217 static cfga_err_t find_ap_common(lib_loc_t *libloc_p, const char *rootpath, 218 int (*fcn)(di_node_t node, di_minor_t minor, void *arg), 219 int (*fcn_hp)(di_node_t node, di_hp_t hp, void *arg), 220 char **errstring); 221 222 static plugin_lib_t *lib_in_list(char *); 223 static cfga_err_t find_lib(di_node_t, di_minor_t, lib_loc_t *); 224 static cfga_err_t find_lib_hp(di_node_t, di_hp_t, lib_loc_t *); 225 static cfga_err_t find_lib_impl(char *, lib_loc_t *); 226 static cfga_err_t load_lib(di_node_t, di_minor_t, lib_loc_t *); 227 static cfga_err_t load_lib_hp(di_node_t, di_hp_t, lib_loc_t *); 228 static cfga_err_t load_lib_impl(di_node_t, di_minor_t, di_hp_t, lib_loc_t *); 229 static void config_err(int, int, char **); 230 static void hold_lib(plugin_lib_t *); 231 static void rele_lib(plugin_lib_t *); 232 233 static cfga_err_t parse_listopt(char *listopts, char **classpp, 234 char **errstring); 235 236 static cfga_err_t list_common(list_stat_t *lstatp, const char *class); 237 static int do_list_common(di_node_t node, di_minor_t minor, void *arg); 238 static int do_list_common_hp(di_node_t node, di_hp_t hp, void *arg); 239 static int do_list_common_impl(di_node_t node, di_minor_t minor, 240 di_hp_t hp, void *arg); 241 static cfga_err_t stat_common(int num_ap_ids, char *const *ap_ids, 242 const char *class, list_stat_t *lstatp); 243 244 static cfga_err_t null_resolve(plugin_lib_t *libp); 245 static cfga_err_t resolve_v1(plugin_lib_t *libp); 246 static cfga_err_t resolve_v2(plugin_lib_t *libp); 247 248 static cfga_err_t mklog_common(di_node_t node, di_minor_t minor, 249 lib_loc_t *liblocp, size_t len); 250 251 static cfga_err_t null_mklog(di_node_t node, di_minor_t minor, 252 plugin_lib_t *libp, lib_loc_t *liblocp); 253 static cfga_err_t mklog_v1(di_node_t node, di_minor_t minor, 254 plugin_lib_t *libp, lib_loc_t *liblocp); 255 static cfga_err_t mklog_v2(di_node_t node, di_minor_t minor, 256 plugin_lib_t *libp, lib_loc_t *liblocp); 257 258 static cfga_err_t null_stat_plugin(list_stat_t *lstatp, lib_loc_t *libloc_p, 259 char **errstring); 260 static cfga_err_t stat_plugin_v2(list_stat_t *lstat, lib_loc_t *libloc_p, 261 char **errstring); 262 static cfga_err_t stat_plugin_v1(list_stat_t *lstat, lib_loc_t *libloc_p, 263 char **errstring); 264 265 static cfga_err_t null_get_cond(lib_loc_t *liblocp, cfga_cond_t *condp, 266 char **errstring); 267 static cfga_err_t get_cond_v1(lib_loc_t *liblocp, cfga_cond_t *condp, 268 char **errstring); 269 static cfga_err_t get_cond_v2(lib_loc_t *liblocp, cfga_cond_t *condp, 270 char **errstring); 271 272 static cfga_err_t realloc_data(cfga_stat_data_t **ap_id_list, 273 int *nlistp, list_stat_t *lstatp); 274 static cfga_err_t realloc_data_ext(cfga_list_data_t **ap_id_list, 275 int *nlistp, list_stat_t *lstatp); 276 277 static void stat_to_list(cfga_list_data_t *lp, cfga_stat_data_t *statp); 278 static void lstat_free(list_stat_t *lstatp); 279 static cfga_ap_types_t find_arg_type(const char *ap_id); 280 static int compat_plugin(vers_req_t *reqp, int plugin_vers); 281 282 static cfga_err_t check_flags(cfga_flags_t flags, cfga_flags_t mask, 283 char **errstring); 284 static cfga_err_t check_apids(int num_ap_ids, char *const *ap_ids, 285 char **errstring); 286 287 static char *get_class(di_minor_t minor); 288 static cfga_err_t split_apid(char *ap_id, char **dyncompp, char **errstring); 289 static void append_dyn(char *buf, const char *dyncomp, size_t blen); 290 static int default_ap_id_cmp(const char *ap_id1, const char *ap_id2); 291 static void destroy_cache(); 292 293 /* 294 * Plugin library search path helpers 295 */ 296 #define LIB_PATH_BASE1 "/usr/platform/" 297 #define LIB_PATH_BASE2 "/usr" 298 #if defined(__sparcv9) 299 #define LIB_PATH_MIDDLE "/lib/cfgadm/sparcv9/" 300 #elif defined(__amd64) 301 #define LIB_PATH_MIDDLE "/lib/cfgadm/amd64/" 302 #else 303 #define LIB_PATH_MIDDLE "/lib/cfgadm/" 304 #endif 305 #define LIB_PATH_TAIL ".so.1" 306 307 308 #if !defined(TEXT_DOMAIN) 309 #define TEXT_DOMAIN "SYS_TEST" 310 #endif 311 312 /* 313 * Defined constants 314 */ 315 #define DEVICES_DIR "/devices" 316 #define DOT_DOT_DEVICES "../devices" 317 #define CFGA_DEV_DIR "/dev/cfg" 318 #define SLASH "/" 319 #define S_FREE(x) (((x) != NULL) ? (free(x), (x) = NULL) : (void *)0) 320 #define GET_DYN(a) (strstr((a), CFGA_DYN_SEP)) 321 322 #define CFGA_NO_CLASS "none" 323 324 /* 325 * Error strings 326 */ 327 #define DI_INIT_FAILED 1 328 #define ALLOC_FAILED 2 329 #define INVALID_ARGS 3 330 331 static char * 332 err_strings[] = { 333 NULL, 334 "Device library initialize failed", 335 "Memory allocation failed", 336 "Invalid argument(s)" 337 }; 338 339 static const char err_sep[] = ": "; 340 341 342 /* 343 * Table of version dependant routines 344 */ 345 static struct cfga_vers_ops cfga_vers_ops[CFGA_HSL_VERS + 1] = { 346 347 {null_resolve, null_stat_plugin, null_mklog, null_get_cond }, 348 {resolve_v1, stat_plugin_v1, mklog_v1, get_cond_v1 }, 349 {resolve_v2, stat_plugin_v2, mklog_v2, get_cond_v2 } 350 351 }; 352 #define VERS_ARRAY_SZ (sizeof (cfga_vers_ops)/sizeof (cfga_vers_ops[0])) 353 354 355 /* 356 * Public interfaces for libcfgadm, as documented in config_admin.3x 357 */ 358 359 /* 360 * config_change_state 361 */ 362 363 cfga_err_t 364 config_change_state( 365 cfga_cmd_t state_change_cmd, 366 int num_ap_ids, 367 char *const *ap_id, 368 const char *options, 369 struct cfga_confirm *confp, 370 struct cfga_msg *msgp, 371 char **errstring, 372 cfga_flags_t flags) 373 { 374 /* 375 * for each arg - 376 * load hs library, 377 * if force 378 * call cfga_state_change_func 379 * return status 380 * else 381 * call it's cfga_stat 382 * check condition 383 * call cfga_state_change_func 384 * return status 385 */ 386 int i; 387 lib_loc_t libloc; 388 plugin_lib_t *libp; 389 cfga_cond_t cond; 390 391 cfga_err_t retval = CFGA_OK; 392 393 if (errstring != NULL) { 394 *errstring = NULL; 395 } 396 397 /* Sanity checks */ 398 if (state_change_cmd == CFGA_CMD_NONE) 399 return (retval); 400 401 if ((state_change_cmd < CFGA_CMD_NONE) || 402 (state_change_cmd > CFGA_CMD_UNCONFIGURE)) 403 return (CFGA_INVAL); 404 405 if (check_flags(flags, CFGA_FLAG_FORCE | CFGA_FLAG_VERBOSE, errstring) 406 != CFGA_OK) { 407 return (CFGA_ERROR); 408 } 409 410 if (check_apids(num_ap_ids, ap_id, errstring) != CFGA_OK) { 411 return (CFGA_ERROR); 412 } 413 414 /* 415 * operate on each ap_id 416 */ 417 for (i = 0; (i < num_ap_ids) && (retval == CFGA_OK); i++) { 418 libloc.libp = NULL; 419 if ((retval = config_get_lib(ap_id[i], &libloc, errstring)) != 420 CFGA_OK) { 421 break; 422 } 423 424 libp = libloc.libp; 425 if ((flags & CFGA_FLAG_FORCE) || 426 (state_change_cmd == CFGA_CMD_UNLOAD) || 427 (state_change_cmd == CFGA_CMD_DISCONNECT) || 428 (state_change_cmd == CFGA_CMD_UNCONFIGURE)) { 429 errno = 0; 430 retval = (*libp->cfga_change_state_p) 431 (state_change_cmd, libloc.ap_physical, options, 432 confp, msgp, errstring, flags); 433 } else { 434 /* 435 * Need to check condition before proceeding in 436 * the "configure direction" 437 */ 438 if ((retval = libp->vers_ops->get_cond(&libloc, &cond, 439 errstring)) != CFGA_OK) { 440 break; 441 } 442 443 if (cond == CFGA_COND_OK || cond == CFGA_COND_UNKNOWN) { 444 errno = 0; 445 retval = 446 (*libp->cfga_change_state_p)( 447 state_change_cmd, 448 libloc.ap_physical, options, 449 confp, msgp, errstring, 450 flags); 451 } else { 452 retval = CFGA_INSUFFICENT_CONDITION; 453 } 454 } 455 rele_lib(libp); 456 } 457 458 return (retval); 459 } 460 461 /* 462 * config_private_func 463 */ 464 465 cfga_err_t 466 config_private_func( 467 const char *function, 468 int num_ap_ids, 469 char *const *ap_ids, 470 const char *options, 471 struct cfga_confirm *confp, 472 struct cfga_msg *msgp, 473 char **errstring, 474 cfga_flags_t flags) 475 { 476 int i; 477 lib_loc_t libloc; 478 cfga_err_t retval = CFGA_OK; 479 480 if (errstring != NULL) { 481 *errstring = NULL; 482 } 483 484 if (check_flags(flags, CFGA_FLAG_FORCE | CFGA_FLAG_VERBOSE, errstring) 485 != CFGA_OK) { 486 return (CFGA_ERROR); 487 } 488 489 if (check_apids(num_ap_ids, ap_ids, errstring) != CFGA_OK) { 490 return (CFGA_ERROR); 491 } 492 493 /* 494 * operate on each ap_id 495 */ 496 for (i = 0; (i < num_ap_ids) && (retval == CFGA_OK); i++) { 497 libloc.libp = NULL; 498 if ((retval = config_get_lib(ap_ids[i], &libloc, errstring)) != 499 CFGA_OK) { 500 return (retval); 501 } 502 503 errno = 0; 504 retval = (*libloc.libp->cfga_private_func_p)(function, 505 libloc.ap_physical, options, confp, msgp, errstring, 506 flags); 507 rele_lib(libloc.libp); 508 } 509 510 return (retval); 511 } 512 513 514 /* 515 * config_test 516 */ 517 518 cfga_err_t 519 config_test( 520 int num_ap_ids, 521 char *const *ap_ids, 522 const char *options, 523 struct cfga_msg *msgp, 524 char **errstring, 525 cfga_flags_t flags) 526 { 527 int i; 528 lib_loc_t libloc; 529 cfga_err_t retval = CFGA_OK; 530 531 if (errstring != NULL) { 532 *errstring = NULL; 533 } 534 535 if (check_flags(flags, CFGA_FLAG_FORCE | CFGA_FLAG_VERBOSE, errstring) 536 != CFGA_OK) { 537 return (CFGA_ERROR); 538 } 539 540 if (check_apids(num_ap_ids, ap_ids, errstring) != CFGA_OK) { 541 return (CFGA_ERROR); 542 } 543 544 /* 545 * operate on each ap_id 546 */ 547 for (i = 0; (i < num_ap_ids) && (retval == CFGA_OK); i++) { 548 libloc.libp = NULL; 549 if ((retval = config_get_lib(ap_ids[i], &libloc, errstring)) != 550 CFGA_OK) { 551 return (retval); 552 } 553 554 errno = 0; 555 retval = (*libloc.libp->cfga_test_p)(libloc.ap_physical, 556 options, msgp, errstring, flags); 557 rele_lib(libloc.libp); 558 } 559 560 return (retval); 561 } 562 563 cfga_err_t 564 config_stat( 565 int num_ap_ids, 566 char *const *ap_ids, 567 struct cfga_stat_data *buf, 568 const char *options, 569 char **errstring) 570 { 571 int nstat, n, i; 572 list_stat_t lstat = {NULL}; 573 cfga_err_t rc = CFGA_OK; 574 575 if (errstring != NULL) { 576 *errstring = NULL; 577 } 578 579 if (check_apids(num_ap_ids, ap_ids, errstring) != CFGA_OK) { 580 return (CFGA_ERROR); 581 } 582 583 /* 584 * V1 entry points don't support dynamic attachment points 585 */ 586 for (i = 0; i < num_ap_ids; i++) { 587 if (GET_DYN(ap_ids[i]) != NULL) { 588 return (CFGA_APID_NOEXIST); 589 } 590 } 591 592 593 nstat = n = 0; 594 lstat.countp = &nstat; 595 lstat.opts = options; 596 lstat.errstr = errstring; 597 lstat.shp_errstr = NULL; 598 /* 599 * This is a V1 interface which can use only V1 plugins 600 */ 601 lstat.use_vers.v_max = lstat.use_vers.v_min = CFGA_HSL_V1; 602 603 rc = stat_common(num_ap_ids, ap_ids, NULL, &lstat); 604 if (rc == CFGA_OK) { 605 assert(*lstat.countp == num_ap_ids); 606 rc = realloc_data(&buf, &n, &lstat); 607 } 608 609 return (rc); 610 } 611 612 /* 613 * config_list 614 */ 615 cfga_err_t 616 config_list( 617 struct cfga_stat_data **ap_id_list, 618 int *nlistp, 619 const char *options, 620 char **errstring) 621 { 622 int nstat; 623 list_stat_t lstat = {NULL}; 624 cfga_err_t retval = CFGA_ERROR; 625 626 if (errstring != NULL) { 627 *errstring = NULL; 628 } 629 630 nstat = 0; 631 lstat.countp = &nstat; 632 lstat.opts = options; 633 lstat.errstr = errstring; 634 lstat.shp_errstr = NULL; 635 /* 636 * This is a V1 interface which can use only V1 plugins 637 */ 638 lstat.use_vers.v_max = lstat.use_vers.v_min = CFGA_HSL_V1; 639 640 641 *ap_id_list = NULL; 642 *nlistp = 0; 643 644 /* 645 * V1 interfaces don't support prefiltering, no class 646 * specified. 647 */ 648 retval = list_common(&lstat, NULL); 649 if (retval == CFGA_OK) { 650 retval = realloc_data(ap_id_list, nlistp, &lstat); 651 } 652 653 assert((ap_id_list != NULL && *nlistp != 0) || 654 (ap_id_list == NULL && *nlistp == 0)); 655 656 if (retval == CFGA_OK && *nlistp == 0) { 657 return (CFGA_NOTSUPP); 658 } else { 659 return (retval); 660 } 661 } 662 663 664 /* 665 * config_list_ext 666 */ 667 cfga_err_t 668 config_list_ext( 669 int num_ap_ids, 670 char *const *ap_ids, 671 struct cfga_list_data **ap_id_list, 672 int *nlistp, 673 const char *options, 674 const char *listopts, 675 char **errstring, 676 cfga_flags_t flags) 677 { 678 int nstat, list, prefilter; 679 list_stat_t lstat = {NULL}; 680 char *class; 681 682 cfga_err_t rc = CFGA_ERROR; 683 684 *nlistp = 0; 685 *ap_id_list = NULL; 686 687 if (errstring != NULL) { 688 *errstring = NULL; 689 } 690 691 if (check_flags(flags, CFGA_FLAG_LIST_ALL, errstring) != CFGA_OK) { 692 return (CFGA_ERROR); 693 } 694 695 class = NULL; 696 if ((rc = parse_listopt((char *)listopts, &class, errstring)) 697 != CFGA_OK) { 698 return (rc); 699 } 700 701 prefilter = (class == NULL) ? 0 : 1; 702 703 nstat = 0; 704 lstat.countp = &nstat; 705 lstat.opts = options; 706 lstat.errstr = errstring; 707 lstat.shp_errstr = NULL; 708 lstat.flags = flags; 709 /* 710 * We support both V1 and V2 plugins through this entry 711 * point. 712 */ 713 lstat.use_vers.v_min = CFGA_HSL_V1; 714 lstat.use_vers.v_max = CFGA_HSL_V2; 715 716 list = 0; 717 if (num_ap_ids == 0 && ap_ids == NULL) { 718 /* 719 * discover and stat all attachment points 720 */ 721 list = 1; 722 rc = list_common(&lstat, class); 723 } else if (num_ap_ids > 0 && ap_ids != NULL) { 724 /* 725 * Stat specified attachment points. With dynamic expansion 726 * more data may be returned than was specified by user. 727 */ 728 rc = stat_common(num_ap_ids, ap_ids, class, &lstat); 729 } else { 730 rc = CFGA_ERROR; 731 } 732 733 S_FREE(class); 734 735 if (rc != CFGA_OK) { 736 return (rc); 737 } 738 739 rc = realloc_data_ext(ap_id_list, nlistp, &lstat); 740 741 assert((ap_id_list != NULL && *nlistp != 0) || 742 (ap_id_list == NULL && *nlistp == 0)); 743 744 /* 745 * For the list command notify user if no attachment 746 * point is found in the system. 747 * 748 */ 749 if (list && rc == CFGA_OK && *nlistp == 0) { 750 /* 751 * If attachment points are being prefiltered, absence of data 752 * does not imply that config. admin. is not 753 * supported by the system. 754 */ 755 if (prefilter) { 756 /* 757 * Prefiltering: requested class is absent 758 */ 759 return (CFGA_APID_NOEXIST); 760 } else { 761 /* 762 * No attachment points in system 763 */ 764 return (CFGA_NOTSUPP); 765 } 766 } else { 767 return (rc); 768 } 769 } 770 771 772 /* 773 * config_unload_libs 774 * 775 * Attempts to remove all libs on the plugin list. 776 */ 777 void 778 config_unload_libs() 779 { 780 plugin_lib_t *libp, *prev = &plugin_list, *next = NULL; 781 782 /* destroy cache entries to remove refcnt agains plugins */ 783 destroy_cache(); 784 785 (void) mutex_lock(&plugin_list_lock); 786 for (libp = plugin_list.next; libp != NULL; libp = next) { 787 next = libp->next; 788 (void) mutex_lock(&libp->lock); 789 if (libp->refcnt) { 790 (void) mutex_unlock(&libp->lock); 791 prev = libp; 792 continue; 793 } 794 (void) mutex_unlock(&libp->lock); 795 prev->next = next; 796 (void) dlclose(libp->handle); 797 (void) mutex_destroy(&libp->lock); 798 free(libp); 799 } 800 (void) mutex_unlock(&plugin_list_lock); 801 } 802 803 /* 804 * config_ap_id_cmp 805 */ 806 int 807 config_ap_id_cmp( 808 const cfga_ap_log_id_t ap1, 809 const cfga_ap_log_id_t ap2) 810 { 811 int ret; 812 lib_loc_t libloc; 813 char apstat1[CFGA_PHYS_EXT_LEN]; 814 char apstat2[CFGA_PHYS_EXT_LEN]; 815 char *sep1, *sep2; 816 817 /* 818 * Extract static ap_ids 819 */ 820 (void) strlcpy(apstat1, ap1, sizeof (apstat1)); 821 (void) strlcpy(apstat2, ap2, sizeof (apstat2)); 822 823 sep1 = GET_DYN(apstat1); 824 sep2 = GET_DYN(apstat2); 825 826 if (sep1) 827 *sep1 = '\0'; 828 if (sep2) 829 *sep2 = '\0'; 830 831 /* 832 * Use the default comparator for static ap_ids 833 */ 834 ret = default_ap_id_cmp(apstat1, apstat2); 835 if (ret) 836 return (ret); 837 838 /* 839 * static components match. They belong to 840 * the same static ap_id. Check if both are dynamic 841 * If not, static < dynamic. 842 */ 843 if ((sep1 == NULL) ^ (sep2 == NULL)) 844 return (sep1 ? 1 : -1); 845 846 /* 847 * If both are static, then ap1 = ap2 848 */ 849 if (sep1 == NULL) 850 return (0); 851 852 /* 853 * Both are dynamic and belong to same static ap_id. 854 * Use the plugin comparator 855 */ 856 libloc.libp = NULL; 857 if (config_get_lib(ap1, &libloc, NULL) != CFGA_OK) { 858 return (strncmp(sep1, sep2, CFGA_PHYS_EXT_LEN)); 859 } 860 861 ret = (*libloc.libp->cfga_ap_id_cmp_p)(ap1, ap2); 862 863 rele_lib(libloc.libp); 864 865 return (ret); 866 } 867 868 /* 869 * config_strerror 870 */ 871 872 const char * 873 config_strerror(cfga_err_t cfgerrnum) 874 { 875 const char *ep = NULL; 876 877 if ((cfgerrnum < CFGA_OK) || (cfgerrnum > CFGA_ATTR_INVAL)) 878 return (NULL); 879 880 ep = __config_strerror(cfgerrnum); 881 882 return ((ep != NULL) ? dgettext(TEXT_DOMAIN, ep) : NULL); 883 } 884 885 /* 886 * config_help 887 */ 888 cfga_err_t 889 config_help( 890 int num_ap_ids, 891 char *const *ap_ids, 892 struct cfga_msg *msgp, 893 const char *options, 894 cfga_flags_t flags) 895 { 896 int i; 897 lib_loc_t libloc; 898 cfga_err_t retval = CFGA_OK; 899 900 if (check_flags(flags, CFGA_FLAG_FORCE | CFGA_FLAG_VERBOSE, NULL) 901 != CFGA_OK) { 902 return (CFGA_ERROR); 903 } 904 905 if (num_ap_ids < 0) { 906 return (CFGA_ERROR); 907 } 908 909 if (num_ap_ids > 0 && ap_ids == NULL) { 910 return (CFGA_ERROR); 911 } 912 913 /* 914 * operate on each ap_id 915 */ 916 for (i = 0; (i < num_ap_ids) && (retval == CFGA_OK); i++) { 917 libloc.libp = NULL; 918 if ((retval = config_get_lib(ap_ids[i], &libloc, 919 NULL)) != CFGA_OK) { 920 return (retval); 921 } 922 923 errno = 0; 924 retval = (*libloc.libp->cfga_help_p)(msgp, options, flags); 925 rele_lib(libloc.libp); 926 } 927 return (retval); 928 } 929 930 /* 931 * Private support routines for the public interfaces 932 */ 933 934 static const char * 935 __config_strerror(cfga_err_t cfgerrnum) 936 { 937 const char *ep = NULL; 938 939 switch (cfgerrnum) { 940 case CFGA_OK: 941 ep = "Configuration operation succeeded"; 942 break; 943 case CFGA_NACK: 944 ep = "Configuration operation cancelled"; 945 break; 946 case CFGA_INVAL: 947 ep = "Configuration operation invalid"; 948 break; 949 case CFGA_NOTSUPP: 950 ep = "Configuration administration not supported"; 951 break; 952 case CFGA_OPNOTSUPP: 953 ep = "Configuration operation not supported"; 954 break; 955 case CFGA_PRIV: 956 ep = "Insufficient privileges"; 957 break; 958 case CFGA_BUSY: 959 ep = "Component system is busy, try again"; 960 break; 961 case CFGA_SYSTEM_BUSY: 962 ep = "System is busy, try again"; 963 break; 964 case CFGA_DATA_ERROR: 965 ep = "Data error"; 966 break; 967 case CFGA_LIB_ERROR: 968 ep = "Library error"; 969 break; 970 case CFGA_NO_LIB: 971 ep = "No Library found"; 972 break; 973 case CFGA_INSUFFICENT_CONDITION: 974 ep = "Insufficient condition"; 975 break; 976 case CFGA_ERROR: 977 ep = "Hardware specific failure"; 978 break; 979 case CFGA_APID_NOEXIST: 980 ep = "Attachment point not found"; 981 break; 982 case CFGA_ATTR_INVAL: 983 ep = "No attachment point with specified attributes found"; 984 break; 985 default: 986 ep = NULL; 987 break; 988 } 989 return (ep); 990 } 991 992 /* 993 * listopts is a string in the getsubopt(3C) style: 994 * name1=value1,name2=value2, 995 */ 996 static cfga_err_t 997 parse_listopt(char *listopts, char **classpp, char **errstring) 998 { 999 char *bufp, *optp, *val = NULL; 1000 cfga_err_t rc = CFGA_ERROR; 1001 1002 *classpp = NULL; 1003 1004 /* 1005 * NULL is a legal value for listopts 1006 */ 1007 if (listopts == NULL) { 1008 return (CFGA_OK); 1009 } 1010 1011 if ((bufp = config_calloc_check(1, strlen(listopts) + 1, errstring)) 1012 == NULL) { 1013 return (CFGA_LIB_ERROR); 1014 } 1015 (void) strcpy(bufp, listopts); 1016 1017 optp = bufp; /* getsubopt() modifies its argument */ 1018 while (*optp != '\0') { 1019 switch (getsubopt(&optp, listopt_array, &val)) { 1020 case LISTOPT_CLASS: 1021 if (val == NULL || *classpp != NULL) { 1022 rc = CFGA_ERROR; 1023 goto out; 1024 } 1025 if ((*classpp = config_calloc_check(1, strlen(val) + 1, 1026 errstring)) == NULL) { 1027 rc = CFGA_LIB_ERROR; 1028 goto out; 1029 } 1030 (void) strcpy(*classpp, val); 1031 break; 1032 default: 1033 rc = CFGA_ERROR; 1034 goto out; 1035 } 1036 } 1037 1038 rc = CFGA_OK; 1039 /*FALLTHRU*/ 1040 out: 1041 S_FREE(bufp); 1042 if (rc != CFGA_OK) { 1043 S_FREE(*classpp); 1044 } 1045 return (rc); 1046 } 1047 1048 /*ARGSUSED*/ 1049 static cfga_err_t 1050 null_mklog( 1051 di_node_t node, 1052 di_minor_t minor, 1053 plugin_lib_t *libp, 1054 lib_loc_t *liblocp) 1055 { 1056 return (CFGA_OK); 1057 } 1058 1059 static cfga_err_t 1060 mklog_v1( 1061 di_node_t node, 1062 di_minor_t minor, 1063 plugin_lib_t *libp, 1064 lib_loc_t *liblocp) 1065 { 1066 const size_t len = CFGA_AP_LOG_ID_LEN; 1067 1068 assert(len <= sizeof (liblocp->ap_logical)); 1069 1070 if (libp->plugin_vers != CFGA_HSL_V1) { 1071 return (CFGA_LIB_ERROR); 1072 } 1073 1074 return (mklog_common(node, minor, liblocp, len)); 1075 } 1076 1077 1078 /* 1079 * Obtain the devlink from a /devices path 1080 */ 1081 static int 1082 get_link(di_devlink_t devlink, void *arg) 1083 { 1084 char *linkp = (char *)arg; 1085 1086 (void) snprintf(linkp, CFGA_LOG_EXT_LEN, "%s", 1087 di_devlink_path(devlink)); 1088 return (DI_WALK_TERMINATE); 1089 } 1090 1091 static cfga_err_t 1092 mklog_v2( 1093 di_node_t node, 1094 di_minor_t minor, 1095 plugin_lib_t *libp, 1096 lib_loc_t *liblocp) 1097 { 1098 const size_t len = CFGA_LOG_EXT_LEN; 1099 di_devlink_handle_t hdl; 1100 1101 assert(len <= sizeof (liblocp->ap_logical)); 1102 1103 if (libp->plugin_vers != CFGA_HSL_V2) { 1104 return (CFGA_LIB_ERROR); 1105 } 1106 1107 /* open devlink database */ 1108 if ((hdl = di_devlink_init(NULL, 0)) == NULL) { 1109 return (CFGA_LIB_ERROR); 1110 } 1111 1112 liblocp->ap_logical[0] = '\0'; 1113 (void) di_devlink_walk(hdl, NULL, 1114 liblocp->ap_physical + strlen(DEVICES_DIR), 1115 DI_PRIMARY_LINK, (void *)liblocp->ap_logical, get_link); 1116 1117 (void) di_devlink_fini(&hdl); 1118 1119 if (liblocp->ap_logical[0] != '\0') 1120 return (CFGA_OK); 1121 return (mklog_common(node, minor, liblocp, len)); 1122 } 1123 1124 /* 1125 * mklog_common - make a logical name from the driver and instance 1126 */ 1127 static cfga_err_t 1128 mklog_common( 1129 di_node_t node, 1130 di_minor_t minor, 1131 lib_loc_t *libloc_p, 1132 size_t len) 1133 { 1134 int inst; 1135 char *drv, *minor_name; 1136 1137 drv = di_driver_name(node); 1138 inst = di_instance(node); 1139 minor_name = di_minor_name(minor); 1140 1141 errno = 0; 1142 if (drv != NULL && inst != -1 && minor_name != NULL && 1143 snprintf(libloc_p->ap_logical, len, "%s%d:%s", drv, inst, 1144 minor_name) < len) { /* snprintf returns strlen */ 1145 return (CFGA_OK); 1146 } 1147 1148 return (CFGA_LIB_ERROR); 1149 } 1150 1151 /* 1152 * mklog_common - make a logical name from the driver and instance 1153 */ 1154 /*ARGSUSED*/ 1155 static cfga_err_t 1156 mklog_hp( 1157 di_node_t node, 1158 di_hp_t hp, 1159 plugin_lib_t *libp, 1160 lib_loc_t *liblocp) 1161 { 1162 const size_t len = CFGA_LOG_EXT_LEN; 1163 int inst; 1164 char *drv, *hp_name; 1165 1166 drv = di_driver_name(node); 1167 inst = di_instance(node); 1168 hp_name = di_hp_name(hp); 1169 1170 errno = 0; 1171 if (drv != NULL && inst != -1 && hp_name != NULL && 1172 snprintf(liblocp->ap_logical, len, "%s%d:%s", drv, inst, 1173 hp_name) < len) { /* snprintf returns strlen */ 1174 return (CFGA_OK); 1175 } 1176 1177 return (CFGA_LIB_ERROR); 1178 } 1179 1180 /* 1181 * resolve_lib_ref - relocate to use plugin lib 1182 */ 1183 static cfga_err_t 1184 resolve_lib_ref( 1185 plugin_lib_t *libp, 1186 lib_loc_t *libloc_p) 1187 { 1188 void *sym; 1189 void *libhdlp = libp->handle; 1190 int plug_vers; 1191 1192 if ((sym = dlsym(libhdlp, "cfga_version")) == NULL) { 1193 /* 1194 * Version symbol not defined, must be the first version 1195 */ 1196 plug_vers = CFGA_HSL_V1; 1197 } else { 1198 plug_vers = *((int *)sym); 1199 } 1200 1201 /* 1202 * Check if plugin version matches request. 1203 */ 1204 if (!compat_plugin(&libloc_p->vers_req, plug_vers)) { 1205 return (CFGA_NO_LIB); 1206 } 1207 1208 /* 1209 * Record the plugin version and setup version dependant routines 1210 */ 1211 assert(plug_vers < VERS_ARRAY_SZ); 1212 libp->plugin_vers = plug_vers; 1213 libp->vers_ops = &cfga_vers_ops[plug_vers]; 1214 1215 /* resolve symbols common to all versions */ 1216 if ((sym = dlsym(libhdlp, "cfga_change_state")) == NULL) { 1217 perror("dlsym: cfga_change_state"); 1218 return (CFGA_LIB_ERROR); 1219 } else 1220 libp->cfga_change_state_p = (cfga_err_t (*)(cfga_cmd_t, 1221 const char *, const char *, struct cfga_confirm *, 1222 struct cfga_msg *, char **, cfga_flags_t)) sym; 1223 1224 if ((sym = dlsym(libhdlp, "cfga_private_func")) == NULL) { 1225 perror("dlsym: cfga_private_func"); 1226 return (CFGA_LIB_ERROR); 1227 } else 1228 libp->cfga_private_func_p = (cfga_err_t (*)(const char *, 1229 const char *, const char *, struct cfga_confirm *, 1230 struct cfga_msg *, char **, cfga_flags_t))sym; 1231 1232 if ((sym = dlsym(libhdlp, "cfga_test")) == NULL) { 1233 perror("dlsym: cfga_test"); 1234 return (CFGA_LIB_ERROR); 1235 } else 1236 libp->cfga_test_p = (cfga_err_t (*)(const char *, const char *, 1237 struct cfga_msg *, char **, cfga_flags_t))sym; 1238 1239 if ((sym = dlsym(libhdlp, "cfga_help")) == NULL) { 1240 perror("dlsym: cfga_help"); 1241 return (CFGA_LIB_ERROR); 1242 } else 1243 libp->cfga_help_p = (cfga_err_t (*)(struct cfga_msg *, 1244 const char *, cfga_flags_t))sym; 1245 1246 if ((sym = dlsym(libhdlp, "cfga_ap_id_cmp")) == NULL) { 1247 libp->cfga_ap_id_cmp_p = default_ap_id_cmp; 1248 } else 1249 libp->cfga_ap_id_cmp_p = (int (*)(const 1250 cfga_ap_log_id_t, const cfga_ap_log_id_t))sym; 1251 1252 /* Resolve version specific symbols */ 1253 return (libp->vers_ops->resolve_lib(libp)); 1254 } 1255 1256 /*ARGSUSED*/ 1257 static cfga_err_t 1258 null_resolve(plugin_lib_t *libp) 1259 { 1260 return (CFGA_OK); 1261 } 1262 1263 static cfga_err_t 1264 resolve_v1(plugin_lib_t *libp) 1265 { 1266 void *sym, *libhdlp = libp->handle; 1267 1268 1269 if (libp->plugin_vers != CFGA_HSL_V1) { 1270 return (CFGA_NO_LIB); 1271 } 1272 1273 if ((sym = dlsym(libhdlp, "cfga_stat")) == NULL) { 1274 perror("dlsym: cfga_stat"); 1275 return (CFGA_LIB_ERROR); 1276 } else 1277 libp->cfga_stat_p = (cfga_err_t (*)(const char *, 1278 struct cfga_stat_data *, const char *, 1279 char **))sym; 1280 1281 if ((sym = dlsym(libhdlp, "cfga_list")) == NULL) { 1282 perror("dlsym: cfga_list"); 1283 return (CFGA_LIB_ERROR); 1284 } else 1285 libp->cfga_list_p = (cfga_err_t (*)(struct cfga_stat_data **, 1286 int *, const char *, char **))sym; 1287 1288 return (CFGA_OK); 1289 } 1290 1291 static cfga_err_t 1292 resolve_v2(plugin_lib_t *libp) 1293 { 1294 void *sym; 1295 1296 1297 if (libp->plugin_vers != CFGA_HSL_V2) { 1298 return (CFGA_NO_LIB); 1299 } 1300 1301 if ((sym = dlsym(libp->handle, "cfga_list_ext")) == NULL) { 1302 perror("dlsym: cfga_list_ext"); 1303 return (CFGA_LIB_ERROR); 1304 } else { 1305 libp->cfga_list_ext_p = (cfga_err_t (*)(const char *, 1306 struct cfga_list_data **, int *, const char *, 1307 const char *, char **, cfga_flags_t))sym; 1308 return (CFGA_OK); 1309 } 1310 } 1311 1312 /* 1313 * config_calloc_check - perform allocation, check result and 1314 * set error string 1315 */ 1316 static void * 1317 config_calloc_check( 1318 size_t nelem, 1319 size_t elsize, 1320 char **errstring) 1321 { 1322 void *p; 1323 1324 p = calloc(nelem, elsize); 1325 if (p == NULL) { 1326 config_err(0, ALLOC_FAILED, errstring); 1327 } 1328 1329 return (p); 1330 } 1331 1332 1333 /* 1334 * config_get_lib - given an ap_id find the library name 1335 * If successful, the plugin library is held. 1336 */ 1337 static cfga_err_t 1338 config_get_lib( 1339 const char *ap_id, 1340 lib_loc_t *lib_loc_p, 1341 char **errstring) 1342 { 1343 char *dyncomp, path[PATH_MAX]; 1344 char *apdup; 1345 cfga_ap_types_t type = UNKNOWN_AP; 1346 cfga_err_t ret = CFGA_ERROR; 1347 1348 if (ap_id == NULL) { 1349 config_err(0, INVALID_ARGS, errstring); 1350 return (ret); 1351 } 1352 1353 lib_loc_p->libp = NULL; 1354 1355 if ((apdup = config_calloc_check(1, strlen(ap_id) + 1, errstring)) 1356 == NULL) { 1357 return (CFGA_LIB_ERROR); 1358 } 1359 (void) strcpy(apdup, ap_id); 1360 1361 /* 1362 * Separate into base and dynamic components 1363 */ 1364 if ((ret = split_apid(apdup, &dyncomp, errstring)) != CFGA_OK) { 1365 goto out; 1366 } 1367 1368 /* 1369 * No upper limit on version 1370 */ 1371 lib_loc_p->vers_req.v_max = CFGA_HSL_VERS; 1372 if (dyncomp != NULL) { 1373 /* 1374 * We need atleast version 2 of the plug-in library 1375 * interface since the ap_id has a dynamic component. 1376 */ 1377 1378 lib_loc_p->vers_req.v_min = CFGA_HSL_V2; 1379 } else { 1380 lib_loc_p->vers_req.v_min = CFGA_HSL_V1; 1381 } 1382 1383 /* 1384 * If the ap_id is a devlink in CFGA_DEV_DIR, follow link 1385 * to get the physical ap_id. 1386 */ 1387 if ((type = find_arg_type(apdup)) == LOGICAL_LINK_AP) { 1388 (void) snprintf(lib_loc_p->ap_base, sizeof (lib_loc_p->ap_base), 1389 "%s%s", CFGA_DEV_DIR SLASH, apdup); 1390 } 1391 1392 path[sizeof (path) - 1] = '\0'; 1393 if (type == LOGICAL_LINK_AP && realpath(lib_loc_p->ap_base, path) 1394 != NULL) { 1395 (void) snprintf(lib_loc_p->ap_base, sizeof (lib_loc_p->ap_base), 1396 "%s", path); 1397 } else { 1398 (void) snprintf(lib_loc_p->ap_base, sizeof (lib_loc_p->ap_base), 1399 "%s", apdup); 1400 } 1401 1402 1403 /* 1404 * find and load the library 1405 * The base component of the ap_id is used to locate the plug-in 1406 * 1407 * NOTE that PCIE/PCISHPC connectors also have minor nodes & 1408 * dev links created for now. 1409 */ 1410 if ((type = find_arg_type(lib_loc_p->ap_base)) == PHYSICAL_AP) { 1411 /* 1412 * physical ap_id: Use ap_base as root for tree walk 1413 * A link based apid (logical) will resolve to a physical 1414 * ap_id. 1415 */ 1416 ret = find_ap_common(lib_loc_p, lib_loc_p->ap_base, 1417 check_ap_phys, check_ap_phys_hp, errstring); 1418 } else if ((type == LOGICAL_DRV_AP) || 1419 (type == AP_TYPE && dyncomp == NULL)) { 1420 /* 1421 * logical ap_id or ap_type: Use "/" as root for tree walk 1422 * Note: an aptype cannot have a dynamic component 1423 */ 1424 ret = find_ap_common(lib_loc_p, "/", check_ap, 1425 check_ap_hp, errstring); 1426 } else { 1427 ret = CFGA_APID_NOEXIST; 1428 } 1429 1430 if (ret == CFGA_OK) { 1431 #ifndef NDEBUG 1432 /* 1433 * variables used by assert() only which is disabled 1434 * by defining NDEBUG (see top of this file) 1435 */ 1436 plugin_lib_t *libp; 1437 1438 libp = lib_loc_p->libp; 1439 #endif /* NDEBUG */ 1440 1441 assert(strcmp(libp->libpath, lib_loc_p->pathname) == 0); 1442 assert(VALID_HSL_VERS(libp->plugin_vers)); 1443 1444 /* 1445 * If a dynamic component was present, v1 plug-ins are not 1446 * acceptable. 1447 */ 1448 assert(dyncomp == NULL || libp->plugin_vers >= CFGA_HSL_V2); 1449 1450 /* 1451 * ap_physical is passed to plugins as their ap_id argument. 1452 * Append dynamic component if any. 1453 */ 1454 append_dyn(lib_loc_p->ap_physical, dyncomp, 1455 sizeof (lib_loc_p->ap_physical)); 1456 } 1457 1458 /* cleanup */ 1459 lib_loc_p->vers_req.v_min = INVALID_VERSION; 1460 lib_loc_p->vers_req.v_max = INVALID_VERSION; 1461 *lib_loc_p->ap_base = '\0'; 1462 1463 /*FALLTHRU*/ 1464 out: 1465 S_FREE(apdup); 1466 S_FREE(dyncomp); 1467 if (ret != CFGA_OK) { 1468 lib_loc_p->libp = NULL; 1469 } 1470 1471 assert(ret != CFGA_OK || lib_loc_p->libp != NULL); 1472 1473 return (ret); 1474 } 1475 1476 /* load_lib - load library for non-SHP attachment point node */ 1477 static cfga_err_t 1478 load_lib( 1479 di_node_t node, 1480 di_minor_t minor, 1481 lib_loc_t *libloc_p) 1482 { 1483 return (load_lib_impl(node, minor, NULL, libloc_p)); 1484 } 1485 1486 /* load_lib_hp - load library for SHP attachment point node */ 1487 static cfga_err_t 1488 load_lib_hp( 1489 di_node_t node, 1490 di_hp_t hp, 1491 lib_loc_t *libloc_p) 1492 { 1493 return (load_lib_impl(node, NULL, hp, libloc_p)); 1494 } 1495 1496 /* 1497 * load_lib_impl - Given a library pathname, create a entry for it 1498 * in the library list, * if one does not already exist, and read 1499 * lock it to keep it there. 1500 */ 1501 static cfga_err_t 1502 load_lib_impl( 1503 di_node_t node, 1504 di_minor_t minor, 1505 di_hp_t hp, 1506 lib_loc_t *libloc_p) 1507 { 1508 plugin_lib_t *libp, *list_libp; 1509 char *devfs_path; 1510 char *name; 1511 1512 if (minor != DI_MINOR_NIL && hp != DI_HP_NIL) 1513 return (CFGA_LIB_ERROR); 1514 1515 if (minor != DI_MINOR_NIL) 1516 name = di_minor_name(minor); 1517 else 1518 name = di_hp_name(hp); 1519 1520 /* 1521 * lock the library list 1522 */ 1523 (void) mutex_lock(&plugin_list_lock); 1524 1525 /* 1526 * see if lib exist in list, if not, allocate a new one 1527 */ 1528 list_libp = lib_in_list(libloc_p->pathname); 1529 if (list_libp != NULL) { 1530 hold_lib(list_libp); 1531 (void) mutex_unlock(&plugin_list_lock); 1532 1533 /* fill in logical and physical name in libloc_p */ 1534 libloc_p->libp = libp = list_libp; 1535 if (minor != DI_MINOR_NIL) { 1536 if (libp->vers_ops->mklog(node, minor, libp, libloc_p) 1537 != CFGA_OK) { 1538 rele_lib(list_libp); 1539 return (CFGA_LIB_ERROR); 1540 } 1541 } else { 1542 if (mklog_hp(node, hp, libp, libloc_p) != CFGA_OK) { 1543 rele_lib(list_libp); 1544 return (CFGA_LIB_ERROR); 1545 } 1546 } 1547 1548 devfs_path = di_devfs_path(node); 1549 (void) snprintf(libloc_p->ap_physical, MAXPATHLEN, "%s%s:%s", 1550 DEVICES_DIR, devfs_path, name); 1551 di_devfs_path_free(devfs_path); 1552 1553 return (CFGA_OK); 1554 } 1555 1556 /* allocate a new plugin_lib_t structure */ 1557 libp = config_calloc_check(1, sizeof (plugin_lib_t), NULL); 1558 if (libp == NULL) { 1559 (void) mutex_unlock(&plugin_list_lock); 1560 return (CFGA_LIB_ERROR); 1561 } 1562 1563 (void) snprintf(libp->libpath, sizeof (libp->libpath), "%s", 1564 libloc_p->pathname); 1565 1566 /* 1567 * ensure that the lib is open and linked in 1568 */ 1569 libp->handle = dlopen(libp->libpath, RTLD_NOW); 1570 if (libp->handle == NULL) { 1571 (void) mutex_unlock(&plugin_list_lock); 1572 free(libp); 1573 return (CFGA_NO_LIB); 1574 } 1575 1576 if (minor != DI_MINOR_NIL) { 1577 if (resolve_lib_ref(libp, libloc_p) != CFGA_OK || 1578 libp->vers_ops->mklog(node, minor, libp, libloc_p) 1579 != CFGA_OK) { 1580 (void) mutex_unlock(&plugin_list_lock); 1581 (void) dlclose(libp->handle); 1582 free(libp); 1583 return (CFGA_NO_LIB); 1584 } 1585 } else { 1586 if (resolve_lib_ref(libp, libloc_p) != CFGA_OK || 1587 mklog_hp(node, hp, libp, libloc_p) != CFGA_OK) { 1588 (void) mutex_unlock(&plugin_list_lock); 1589 (void) dlclose(libp->handle); 1590 free(libp); 1591 return (CFGA_NO_LIB); 1592 } 1593 } 1594 1595 /* 1596 * link in new entry to the end of list 1597 */ 1598 list_libp = &plugin_list; 1599 while (list_libp->next != NULL) 1600 list_libp = list_libp->next; 1601 libp->next = list_libp->next; 1602 list_libp->next = libp; 1603 1604 /* Initialize refcnt to 1 */ 1605 libp->refcnt = 1; 1606 (void) mutex_init(&libp->lock, USYNC_THREAD, NULL); 1607 1608 (void) mutex_unlock(&plugin_list_lock); 1609 1610 /* 1611 * record libp and physical node name in the libloc struct 1612 */ 1613 libloc_p->libp = libp; 1614 devfs_path = di_devfs_path(node); 1615 (void) snprintf(libloc_p->ap_physical, MAXPATHLEN, "%s%s:%s", 1616 DEVICES_DIR, devfs_path, name); 1617 di_devfs_path_free(devfs_path); 1618 1619 return (CFGA_OK); 1620 } 1621 1622 1623 #define NUM_LIB_NAMES 2 1624 1625 /* 1626 * find_lib - find library for non-SHP attachment point node 1627 */ 1628 static cfga_err_t 1629 find_lib( 1630 di_node_t node, 1631 di_minor_t minor, 1632 lib_loc_t *libloc_p) 1633 { 1634 char name[NUM_LIB_NAMES][MAXPATHLEN]; 1635 char *class = NULL, *drv = NULL; 1636 int i; 1637 1638 1639 /* Make sure pathname and class is null if we fail */ 1640 *libloc_p->ap_class = *libloc_p->pathname = '\0'; 1641 1642 /* 1643 * Initialize possible library tags. 1644 */ 1645 1646 drv = di_driver_name(node); 1647 class = get_class(minor); 1648 1649 if (drv == NULL || class == NULL) { 1650 return (CFGA_LIB_ERROR); 1651 } 1652 1653 i = 0; 1654 (void) snprintf(&name[i++][0], sizeof (name[0]), "%s", drv); 1655 (void) snprintf(&name[i++][0], sizeof (name[0]), "%s", class); 1656 1657 /* 1658 * Cycle through the array of names to find the library. 1659 */ 1660 for (i = 0; i < NUM_LIB_NAMES; i++) { 1661 1662 /* Attachment points may not have a class (i.e. are generic) */ 1663 if (name[i][0] == '\0') { 1664 continue; 1665 } 1666 1667 if (find_lib_impl(name[i], libloc_p) == CFGA_OK) 1668 goto found; 1669 } 1670 1671 return (CFGA_NO_LIB); 1672 1673 found: 1674 1675 /* Record class name (if any) */ 1676 (void) snprintf(libloc_p->ap_class, sizeof (libloc_p->ap_class), "%s", 1677 class); 1678 1679 return (CFGA_OK); 1680 } 1681 1682 /* 1683 * find_lib_hp - find library for SHP attachment point 1684 */ 1685 /*ARGSUSED*/ 1686 static cfga_err_t 1687 find_lib_hp( 1688 di_node_t node, 1689 di_hp_t hp, 1690 lib_loc_t *libloc_p) 1691 { 1692 char name[MAXPATHLEN]; 1693 char *class = NULL; 1694 1695 1696 /* Make sure pathname and class is null if we fail */ 1697 *libloc_p->ap_class = *libloc_p->pathname = '\0'; 1698 1699 /* 1700 * Initialize possible library tags. 1701 * 1702 * Only support PCI class for now, this will need to be 1703 * changed as other plugins are migrated to SHP plugin. 1704 */ 1705 class = "pci"; 1706 #if 0 1707 /* 1708 * No type check for now as PCI is the only class SHP plugin 1709 * supports. In the future we'll need to enable the type check 1710 * and set class accordingly, when non PCI plugins are migrated 1711 * to SHP. In that case we'll probably need to add an additional 1712 * interface between libcfgadm and the plugins, and SHP plugin will 1713 * implement this interface which will translate the bus specific 1714 * strings to standard classes that libcfgadm can recognize, for 1715 * all the buses it supports, e.g. for pci/pcie it will translate 1716 * PCIE_NATIVE_HP_TYPE to string "pci". We'll also need to bump up 1717 * SHP plugin version to 3 to use the new interface. 1718 */ 1719 class = di_hp_type(hp); 1720 if ((strcmp(class, PCIE_NATIVE_HP_TYPE) == 0) || 1721 (strcmp(class, PCIE_ACPI_HP_TYPE) == 0) || 1722 (strcmp(class, PCIE_PCI_HP_TYPE) == 0)) { 1723 class = "pci"; 1724 } else { 1725 goto fail; 1726 } 1727 #endif 1728 (void) snprintf(&name[0], sizeof (name), "%s", "shp"); 1729 1730 if (find_lib_impl(name, libloc_p) == CFGA_OK) 1731 goto found; 1732 fail: 1733 return (CFGA_NO_LIB); 1734 1735 found: 1736 1737 /* Record class name (if any) */ 1738 (void) snprintf(libloc_p->ap_class, sizeof (libloc_p->ap_class), "%s", 1739 class); 1740 1741 return (CFGA_OK); 1742 } 1743 1744 /* 1745 * find_lib_impl - Given an attachment point node find it's library 1746 */ 1747 static cfga_err_t 1748 find_lib_impl( 1749 char *name, 1750 lib_loc_t *libloc_p) 1751 { 1752 char lib[MAXPATHLEN]; 1753 struct stat lib_stat; 1754 void *dlhandle = NULL; 1755 static char plat_name[SYSINFO_LENGTH]; 1756 static char machine_name[SYSINFO_LENGTH]; 1757 static char arch_name[SYSINFO_LENGTH]; 1758 1759 /* 1760 * Initialize machine name and arch name 1761 */ 1762 if (strncmp("", machine_name, MAXPATHLEN) == 0) { 1763 if (sysinfo(SI_PLATFORM, plat_name, SYSINFO_LENGTH) == -1) { 1764 return (CFGA_ERROR); 1765 } 1766 if (sysinfo(SI_ARCHITECTURE, arch_name, SYSINFO_LENGTH) == -1) { 1767 return (CFGA_ERROR); 1768 } 1769 if (sysinfo(SI_MACHINE, machine_name, SYSINFO_LENGTH) == -1) { 1770 return (CFGA_ERROR); 1771 } 1772 } 1773 1774 /* 1775 * Try path based upon platform name 1776 */ 1777 (void) snprintf(lib, sizeof (lib), "%s%s%s%s%s", 1778 LIB_PATH_BASE1, plat_name, LIB_PATH_MIDDLE, 1779 name, LIB_PATH_TAIL); 1780 1781 if (stat(lib, &lib_stat) == 0) { 1782 /* file exists, is it a lib */ 1783 dlhandle = dlopen(lib, RTLD_LAZY); 1784 if (dlhandle != NULL) { 1785 goto found; 1786 } 1787 } 1788 1789 /* 1790 * Try path based upon machine name 1791 */ 1792 (void) snprintf(lib, sizeof (lib), "%s%s%s%s%s", 1793 LIB_PATH_BASE1, machine_name, LIB_PATH_MIDDLE, 1794 name, LIB_PATH_TAIL); 1795 1796 1797 if (stat(lib, &lib_stat) == 0) { 1798 /* file exists, is it a lib */ 1799 dlhandle = dlopen(lib, RTLD_LAZY); 1800 if (dlhandle != NULL) { 1801 goto found; 1802 } 1803 } 1804 1805 /* 1806 * Try path based upon arch name 1807 */ 1808 (void) snprintf(lib, sizeof (lib), "%s%s%s%s%s", 1809 LIB_PATH_BASE1, arch_name, LIB_PATH_MIDDLE, 1810 name, LIB_PATH_TAIL); 1811 1812 if (stat(lib, &lib_stat) == 0) { 1813 /* file exists, is it a lib */ 1814 dlhandle = dlopen(lib, RTLD_LAZY); 1815 if (dlhandle != NULL) { 1816 goto found; 1817 } 1818 1819 } 1820 1821 /* 1822 * Try generic location 1823 */ 1824 (void) snprintf(lib, sizeof (lib), "%s%s%s%s", 1825 LIB_PATH_BASE2, LIB_PATH_MIDDLE, name, LIB_PATH_TAIL); 1826 1827 if (stat(lib, &lib_stat) == 0) { 1828 /* file exists, is it a lib */ 1829 dlhandle = dlopen(lib, RTLD_LAZY); 1830 if (dlhandle != NULL) { 1831 goto found; 1832 } 1833 1834 } 1835 return (CFGA_NO_LIB); 1836 1837 found: 1838 /* we got one! */ 1839 (void) snprintf(libloc_p->pathname, sizeof (libloc_p->pathname), "%s", 1840 lib); 1841 1842 (void) dlclose(dlhandle); 1843 1844 return (CFGA_OK); 1845 } 1846 1847 static cfga_err_t 1848 lookup_cache(lib_loc_t *libloc_p) 1849 { 1850 lib_cache_t *entry; 1851 (void) mutex_lock(&lib_cache_lock); 1852 entry = lib_cache; 1853 while (entry) { 1854 if (strcmp(entry->lc_ap_id, libloc_p->ap_base) == 0) { 1855 plugin_lib_t *libp = entry->lc_libp; 1856 libloc_p->libp = libp; 1857 hold_lib(libp); 1858 (void) strcpy(libloc_p->pathname, libp->libpath); 1859 (void) strcpy(libloc_p->ap_physical, 1860 entry->lc_ap_physical); 1861 (void) strcpy(libloc_p->ap_logical, 1862 entry->lc_ap_logical); 1863 (void) mutex_unlock(&lib_cache_lock); 1864 return (CFGA_OK); 1865 } 1866 entry = entry->lc_next; 1867 } 1868 (void) mutex_unlock(&lib_cache_lock); 1869 1870 return (CFGA_ERROR); 1871 } 1872 1873 static void 1874 update_cache(lib_loc_t *libloc_p) 1875 { 1876 lib_cache_t *entry; 1877 entry = config_calloc_check(1, sizeof (lib_cache_t), NULL); 1878 if (entry == NULL) 1879 return; 1880 1881 entry->lc_ap_id = strdup(libloc_p->ap_base); 1882 entry->lc_ap_physical = strdup(libloc_p->ap_physical); 1883 entry->lc_ap_logical = strdup(libloc_p->ap_logical); 1884 if ((entry->lc_ap_id == NULL) || (entry->lc_ap_physical == NULL) || 1885 (entry->lc_ap_logical == NULL)) { 1886 free(entry->lc_ap_id); 1887 free(entry->lc_ap_physical); 1888 free(entry->lc_ap_logical); 1889 free(entry); 1890 return; 1891 } 1892 1893 (void) mutex_lock(&lib_cache_lock); 1894 entry->lc_libp = libloc_p->libp; 1895 entry->lc_next = lib_cache; 1896 lib_cache = entry; 1897 hold_lib(entry->lc_libp); /* prevent stale cache */ 1898 (void) mutex_unlock(&lib_cache_lock); 1899 } 1900 1901 static void 1902 destroy_cache() 1903 { 1904 lib_cache_t *entry, *next; 1905 (void) mutex_lock(&lib_cache_lock); 1906 entry = lib_cache; 1907 while (entry) { 1908 next = entry->lc_next; 1909 rele_lib(entry->lc_libp); 1910 free(entry->lc_ap_id); 1911 free(entry->lc_ap_physical); 1912 free(entry->lc_ap_logical); 1913 free(entry); 1914 entry = next; 1915 } 1916 (void) mutex_unlock(&lib_cache_lock); 1917 } 1918 1919 /* 1920 * find_ap_common - locate a particular attachment point 1921 */ 1922 static cfga_err_t 1923 find_ap_common( 1924 lib_loc_t *libloc_p, 1925 const char *physpath, 1926 int (*fcn)(di_node_t node, di_minor_t minor, void *arg), 1927 int (*fcn_hp)(di_node_t node, di_hp_t hp, void *arg), 1928 char **errstring) 1929 { 1930 di_node_t rnode, wnode; 1931 char *cp, *rpath; 1932 size_t len; 1933 1934 if (lookup_cache(libloc_p) == CFGA_OK) 1935 return (CFGA_OK); 1936 1937 if ((rpath = config_calloc_check(1, strlen(physpath) + 1, 1938 errstring)) == NULL) { 1939 return (CFGA_LIB_ERROR); 1940 } 1941 1942 (void) strcpy(rpath, physpath); 1943 1944 /* Remove devices prefix (if any) */ 1945 len = strlen(DEVICES_DIR); 1946 if (strncmp(rpath, DEVICES_DIR SLASH, len + strlen(SLASH)) == 0) { 1947 (void) memmove(rpath, rpath + len, 1948 strlen(rpath + len) + 1); 1949 } 1950 1951 /* Remove dynamic component if any */ 1952 if ((cp = GET_DYN(rpath)) != NULL) { 1953 *cp = '\0'; 1954 } 1955 1956 /* Remove minor name (if any) */ 1957 if ((cp = strrchr(rpath, ':')) != NULL) { 1958 *cp = '\0'; 1959 } 1960 1961 /* 1962 * begin walk of device tree 1963 * 1964 * Since we create minor nodes & dev links for both all PCI/PCIE 1965 * connectors, but only create hp nodes for PCIE/PCISHPC connectors 1966 * of the new framework, we should first match with hp nodes. If 1967 * the ap_id refers to a PCIE/PCISHPC connector, we'll be able to 1968 * find it here. 1969 */ 1970 rnode = di_init("/", DINFOSUBTREE | DINFOHP); 1971 if (rnode) 1972 wnode = di_lookup_node(rnode, rpath); 1973 else 1974 wnode = DI_NODE_NIL; 1975 1976 if (wnode == DI_NODE_NIL) { 1977 if (rnode == DI_NODE_NIL) { 1978 S_FREE(rpath); 1979 config_err(errno, DI_INIT_FAILED, errstring); 1980 return (CFGA_LIB_ERROR); 1981 } else { 1982 /* 1983 * di_lookup_node() may fail, either because the 1984 * ap_id does not exist, or because the ap_id refers 1985 * to a legacy PCI slot, thus we'll not able to 1986 * find node using DINFOHP, try to see if we can 1987 * find one using DINFOCACHE. 1988 */ 1989 di_fini(rnode); 1990 goto find_minor; 1991 } 1992 } 1993 1994 libloc_p->libp = NULL; 1995 libloc_p->status = CFGA_APID_NOEXIST; 1996 1997 (void) di_walk_hp(wnode, NULL, DI_HP_CONNECTOR, 1998 libloc_p, fcn_hp); 1999 2000 di_fini(rnode); 2001 2002 /* 2003 * Failed to find a matching hp node, try minor node. 2004 */ 2005 if (libloc_p->libp == NULL) { 2006 find_minor: 2007 rnode = di_init("/", DINFOCACHE); 2008 if (rnode) 2009 wnode = di_lookup_node(rnode, rpath); 2010 else 2011 wnode = DI_NODE_NIL; 2012 2013 if (wnode == DI_NODE_NIL) { 2014 if (rnode == DI_NODE_NIL) { 2015 S_FREE(rpath); 2016 config_err(errno, DI_INIT_FAILED, errstring); 2017 return (CFGA_LIB_ERROR); 2018 } else { 2019 /* 2020 * di_lookup_node() may fail, because the 2021 * ap_id does not exist. 2022 */ 2023 S_FREE(rpath); 2024 di_fini(rnode); 2025 return (CFGA_APID_NOEXIST); 2026 } 2027 } 2028 2029 libloc_p->libp = NULL; 2030 libloc_p->status = CFGA_APID_NOEXIST; 2031 2032 (void) di_walk_minor(wnode, "ddi_ctl:attachment_point", 2033 DI_CHECK_ALIAS|DI_CHECK_INTERNAL_PATH, 2034 libloc_p, fcn); 2035 2036 di_fini(rnode); 2037 } 2038 2039 S_FREE(rpath); 2040 2041 if (libloc_p->libp != NULL) { 2042 update_cache(libloc_p); 2043 return (CFGA_OK); 2044 } else { 2045 return (libloc_p->status); 2046 } 2047 } 2048 2049 /* 2050 * check_ap - called for each non-SHP attachment point found 2051 */ 2052 static int 2053 check_ap( 2054 di_node_t node, 2055 di_minor_t minor, 2056 void *arg) 2057 { 2058 return (check_ap_impl(node, minor, NULL, arg)); 2059 } 2060 2061 /* 2062 * check_ap_hp - called for each SHP attachment point found 2063 */ 2064 static int 2065 check_ap_hp( 2066 di_node_t node, 2067 di_hp_t hp, 2068 void *arg) 2069 { 2070 return (check_ap_impl(node, NULL, hp, arg)); 2071 } 2072 2073 /* 2074 * check_ap_impl - called for each attachment point found 2075 * 2076 * This is used in cases where a particular attachment point 2077 * or type of attachment point is specified via a logical name or ap_type. 2078 * Not used for physical names or in the list case with no 2079 * ap's specified. 2080 */ 2081 static int 2082 check_ap_impl( 2083 di_node_t node, 2084 di_minor_t minor, 2085 di_hp_t hp, 2086 void *arg) 2087 { 2088 char *cp = NULL; 2089 char aptype[MAXPATHLEN]; 2090 char *recep_id = NULL; 2091 char *node_minor; 2092 char *drv_name; 2093 char inst[MAXPATHLEN]; 2094 char inst2[MAXPATHLEN]; 2095 lib_loc_t *libloc_p; 2096 int comparison_test; 2097 int instance; 2098 cfga_ap_types_t type; 2099 2100 if (minor != DI_MINOR_NIL && hp != DI_HP_NIL) 2101 return (DI_WALK_CONTINUE); 2102 2103 libloc_p = (lib_loc_t *)arg; 2104 2105 (void) snprintf(aptype, sizeof (aptype), "%s", libloc_p->ap_base); 2106 2107 /* 2108 * This routime handles only aptypes and driver based logical apids. 2109 */ 2110 type = find_arg_type(aptype); 2111 if (type == LOGICAL_DRV_AP) { 2112 cp = strchr(aptype, ':'); 2113 *cp = '\0'; 2114 recep_id = cp+1; 2115 cp--; 2116 while (isdigit(*cp) && cp != aptype) 2117 cp--; 2118 cp++; 2119 2120 (void) snprintf(inst, sizeof (inst), "%s", cp); 2121 2122 *cp = '\0'; 2123 } else if (type != AP_TYPE) { 2124 libloc_p->status = CFGA_APID_NOEXIST; 2125 return (DI_WALK_CONTINUE); 2126 } 2127 2128 if (minor != DI_MINOR_NIL) 2129 node_minor = di_minor_name(minor); 2130 else 2131 node_minor = di_hp_name(hp); 2132 2133 drv_name = di_driver_name(node); 2134 instance = di_instance(node); 2135 2136 if (node_minor == NULL || drv_name == NULL || instance == -1) { 2137 libloc_p->status = CFGA_APID_NOEXIST; 2138 return (DI_WALK_CONTINUE); 2139 } 2140 2141 (void) sprintf(inst2, "%d", instance); 2142 2143 /* 2144 * If the base matches driver and instance try and find a lib for it, 2145 * then load it. On any failure we continue the walk. 2146 * 2147 * driver based logical ap_ids are derived from driver name + instance. 2148 * Ap_types are just partial driver names. 2149 * 2150 */ 2151 2152 comparison_test = 0; 2153 if (type == AP_TYPE) { 2154 if (strncmp(aptype, drv_name, strlen(aptype)) == 0) { 2155 comparison_test = 1; 2156 } 2157 } else { 2158 if (strcmp(aptype, drv_name) == 0 && 2159 strcmp(recep_id, node_minor) == 0 && 2160 strcmp(inst, inst2) == 0) { 2161 comparison_test = 1; 2162 } 2163 } 2164 2165 if (comparison_test) { 2166 /* 2167 * save the correct type of error so user does not get confused 2168 */ 2169 if (minor != DI_MINOR_NIL) { 2170 if (find_lib(node, minor, libloc_p) != CFGA_OK) { 2171 libloc_p->status = CFGA_NO_LIB; 2172 return (DI_WALK_CONTINUE); 2173 } 2174 if (load_lib(node, minor, libloc_p) != CFGA_OK) { 2175 libloc_p->status = CFGA_LIB_ERROR; 2176 return (DI_WALK_CONTINUE); 2177 } 2178 } else { 2179 if (find_lib_hp(node, hp, libloc_p) != CFGA_OK) { 2180 libloc_p->status = CFGA_NO_LIB; 2181 return (DI_WALK_CONTINUE); 2182 } 2183 if (load_lib_hp(node, hp, libloc_p) != CFGA_OK) { 2184 libloc_p->status = CFGA_LIB_ERROR; 2185 return (DI_WALK_CONTINUE); 2186 } 2187 } 2188 libloc_p->status = CFGA_OK; 2189 return (DI_WALK_TERMINATE); 2190 } else { 2191 libloc_p->status = CFGA_APID_NOEXIST; 2192 return (DI_WALK_CONTINUE); 2193 } 2194 } 2195 2196 2197 /* 2198 * check_ap_phys - called for each non-SHP attachment point found 2199 */ 2200 static int 2201 check_ap_phys( 2202 di_node_t node, 2203 di_minor_t minor, 2204 void *arg) 2205 { 2206 return (check_ap_phys_impl(node, minor, DI_HP_NIL, arg)); 2207 } 2208 2209 /* 2210 * check_ap_phys_hp - called for each SHP attachment point found 2211 */ 2212 static int 2213 check_ap_phys_hp( 2214 di_node_t node, 2215 di_hp_t hp, 2216 void *arg) 2217 { 2218 return (check_ap_phys_impl(node, DI_HP_NIL, hp, arg)); 2219 } 2220 2221 /* 2222 * check_ap_phys_impl - called for each attachment point found 2223 * 2224 * This is used in cases where a particular attachment point 2225 * is specified via a physical name. If the name matches then 2226 * we try and find and load the library for it. 2227 */ 2228 static int 2229 check_ap_phys_impl( 2230 di_node_t node, 2231 di_minor_t minor, 2232 di_hp_t hp, 2233 void *arg) 2234 { 2235 lib_loc_t *libloc_p; 2236 char phys_name[MAXPATHLEN]; 2237 char *devfs_path; 2238 char *minor_name; 2239 2240 if (minor != DI_MINOR_NIL && hp != DI_HP_NIL) 2241 return (DI_WALK_CONTINUE); 2242 2243 libloc_p = (lib_loc_t *)arg; 2244 devfs_path = di_devfs_path(node); 2245 if (minor != DI_MINOR_NIL) 2246 minor_name = di_minor_name(minor); 2247 else 2248 minor_name = di_hp_name(hp); 2249 2250 if (devfs_path == NULL || minor_name == NULL) { 2251 libloc_p->status = CFGA_APID_NOEXIST; 2252 return (DI_WALK_CONTINUE); 2253 } 2254 2255 (void) snprintf(phys_name, sizeof (phys_name), "%s%s:%s", 2256 DEVICES_DIR, devfs_path, minor_name); 2257 2258 di_devfs_path_free(devfs_path); 2259 2260 if (strcmp(phys_name, libloc_p->ap_base) == 0) { 2261 if (minor != DI_MINOR_NIL) { 2262 if (find_lib(node, minor, libloc_p) != CFGA_OK) { 2263 libloc_p->status = CFGA_NO_LIB; 2264 return (DI_WALK_CONTINUE); 2265 } 2266 if (load_lib(node, minor, libloc_p) != CFGA_OK) { 2267 libloc_p->status = CFGA_LIB_ERROR; 2268 return (DI_WALK_CONTINUE); 2269 } 2270 } else { 2271 if (find_lib_hp(node, hp, libloc_p) != CFGA_OK) { 2272 libloc_p->status = CFGA_NO_LIB; 2273 return (DI_WALK_CONTINUE); 2274 } 2275 if (load_lib_hp(node, hp, libloc_p) != CFGA_OK) { 2276 libloc_p->status = CFGA_LIB_ERROR; 2277 return (DI_WALK_CONTINUE); 2278 } 2279 } 2280 2281 libloc_p->status = CFGA_OK; 2282 return (DI_WALK_TERMINATE); 2283 } else { 2284 libloc_p->status = CFGA_APID_NOEXIST; 2285 return (DI_WALK_CONTINUE); 2286 } 2287 } 2288 2289 /* 2290 * lib_in_list 2291 * 2292 * See if library, as specified by the full pathname and controller 2293 * instance number is already represented in the plugin library list. 2294 * If the instance number is -1 it is ignored. 2295 */ 2296 static plugin_lib_t * 2297 lib_in_list(char *libpath) 2298 { 2299 plugin_lib_t *libp = NULL; 2300 2301 for (libp = plugin_list.next; libp != NULL; libp = libp->next) { 2302 if (strncmp(libpath, libp->libpath, MAXPATHLEN) == 0) { 2303 return (libp); 2304 } 2305 } 2306 return (NULL); 2307 } 2308 2309 2310 2311 2312 /* 2313 * Coalesce stat and list data into single array 2314 */ 2315 static cfga_err_t 2316 realloc_data_ext( 2317 cfga_list_data_t **ap_id_list, 2318 int *nlistp, 2319 list_stat_t *lstatp) 2320 { 2321 int i, j; 2322 stat_data_list_t *slp; 2323 cfga_list_data_t *cldp; 2324 array_list_t *alp; 2325 cfga_err_t rc = CFGA_OK; 2326 2327 2328 assert(*lstatp->countp >= 0); 2329 2330 if (*lstatp->countp == 0) { 2331 *ap_id_list = NULL; 2332 *nlistp = 0; 2333 return (CFGA_OK); 2334 } 2335 2336 /* 2337 * allocate the array 2338 */ 2339 if ((cldp = config_calloc_check(*lstatp->countp, 2340 sizeof (cfga_list_data_t), lstatp->errstr)) == NULL) { 2341 rc = CFGA_LIB_ERROR; 2342 goto out; 2343 } 2344 2345 /* 2346 * copy all the stat elements (if any) into the array 2347 */ 2348 slp = lstatp->sdl; 2349 for (i = 0; slp != NULL; i++) { 2350 if (i >= *lstatp->countp) { 2351 rc = CFGA_LIB_ERROR; 2352 goto out; 2353 } 2354 stat_to_list(&cldp[i], &slp->stat_data); 2355 slp = slp->next; 2356 } 2357 2358 /* 2359 * copy all the list elements (if any) into the array 2360 */ 2361 alp = lstatp->al; 2362 for (; alp != NULL; ) { 2363 if (i + alp->nelem > *lstatp->countp) { 2364 rc = CFGA_LIB_ERROR; 2365 goto out; 2366 } 2367 2368 for (j = 0; j < alp->nelem; i++, j++) { 2369 cldp[i] = alp->array[j]; 2370 } 2371 alp = alp->next; 2372 } 2373 2374 if (i != *lstatp->countp) { 2375 rc = CFGA_LIB_ERROR; 2376 } else { 2377 rc = CFGA_OK; 2378 } 2379 2380 /*FALLTHRU*/ 2381 2382 out: 2383 /* clean up */ 2384 lstat_free(lstatp); 2385 2386 if (rc == CFGA_OK) { 2387 *ap_id_list = cldp; 2388 *nlistp = *lstatp->countp; 2389 } else { 2390 S_FREE(cldp); 2391 *ap_id_list = NULL; 2392 *nlistp = 0; 2393 } 2394 return (rc); 2395 } 2396 2397 /* 2398 * The caller of this routine may supply a buffer through 2399 * ap_id_list for returning data. Otherwise, this routine allocates the 2400 * buffer. 2401 */ 2402 static cfga_err_t 2403 realloc_data(cfga_stat_data_t **ap_id_list, int *nlistp, list_stat_t *lstatp) 2404 { 2405 int i; 2406 stat_data_list_t *slp; 2407 cfga_stat_data_t *csdp, *buf; 2408 cfga_err_t rc; 2409 2410 2411 assert(*lstatp->countp >= 0); 2412 2413 if (*lstatp->countp == 0) { 2414 *nlistp = 0; 2415 return (CFGA_OK); 2416 } 2417 2418 2419 /* 2420 * allocate the array if caller does not supply one. 2421 */ 2422 if (*ap_id_list == NULL) { 2423 if ((buf = config_calloc_check(*lstatp->countp, 2424 sizeof (cfga_stat_data_t), lstatp->errstr)) == NULL) { 2425 rc = CFGA_LIB_ERROR; 2426 goto out; 2427 } 2428 } else { 2429 buf = *ap_id_list; 2430 } 2431 2432 /* 2433 * copy the stat elements into the array 2434 */ 2435 csdp = buf; 2436 slp = lstatp->sdl; 2437 for (i = 0; slp != NULL; i++) { 2438 if (i >= *lstatp->countp) { 2439 rc = CFGA_LIB_ERROR; 2440 goto out; 2441 } 2442 *csdp++ = slp->stat_data; 2443 slp = slp->next; 2444 } 2445 2446 rc = CFGA_OK; 2447 2448 out: 2449 if (rc == CFGA_OK) { 2450 *nlistp = *lstatp->countp; 2451 *ap_id_list = buf; 2452 } else { 2453 /* 2454 * Free buffer only if we allocated it. 2455 */ 2456 if (*ap_id_list == NULL) { 2457 free(buf); 2458 } 2459 *nlistp = 0; 2460 } 2461 2462 assert(lstatp->al == NULL); 2463 lstat_free(lstatp); 2464 2465 return (rc); 2466 } 2467 2468 2469 /* 2470 * list_common - walk the device tree and stat all attachment points. 2471 */ 2472 static cfga_err_t 2473 list_common(list_stat_t *lstatp, const char *class) 2474 { 2475 di_node_t rnode; 2476 char nodetype[MAXPATHLEN]; 2477 const char *l_class, *l_sep; 2478 2479 /* 2480 * May walk a subset of all attachment points in the device tree if 2481 * a class is specified 2482 */ 2483 if (class != NULL) { 2484 l_sep = ":"; 2485 l_class = class; 2486 } else { 2487 l_sep = l_class = ""; 2488 } 2489 2490 (void) snprintf(nodetype, sizeof (nodetype), "%s%s%s", 2491 DDI_NT_ATTACHMENT_POINT, l_sep, l_class); 2492 2493 /* 2494 * Walk all hp nodes 2495 */ 2496 if ((rnode = di_init("/", DINFOSUBTREE | DINFOHP)) == DI_NODE_NIL) { 2497 config_err(errno, DI_INIT_FAILED, lstatp->errstr); 2498 return (CFGA_LIB_ERROR); 2499 } 2500 /* No need to filter on class for now */ 2501 (void) di_walk_hp(rnode, NULL, DI_HP_CONNECTOR, 2502 lstatp, do_list_common_hp); 2503 2504 di_fini(rnode); 2505 2506 /* 2507 * Walk all minor nodes 2508 * but exclude PCIE/PCIESHPC connectors which have been walked above. 2509 */ 2510 if ((rnode = di_init("/", DINFOCACHE)) == DI_NODE_NIL) { 2511 config_err(errno, DI_INIT_FAILED, lstatp->errstr); 2512 return (CFGA_LIB_ERROR); 2513 } 2514 (void) di_walk_minor(rnode, nodetype, 2515 DI_CHECK_ALIAS|DI_CHECK_INTERNAL_PATH, lstatp, do_list_common); 2516 2517 di_fini(rnode); 2518 2519 if (lstatp->shp_errstr != NULL) { 2520 *(lstatp->errstr) = strdup(lstatp->shp_errstr); 2521 free(lstatp->shp_errstr); 2522 lstatp->shp_errstr = NULL; 2523 } 2524 2525 return (CFGA_OK); 2526 } 2527 2528 static void 2529 config_err(int errnum, int err_type, char **errstring) 2530 { 2531 const char *err; 2532 const char *syserr = ""; 2533 const char *sep = ""; 2534 char syserr_num[20]; 2535 2536 /* 2537 * If errstring is null the user in not interested in getting 2538 * error status text. 2539 */ 2540 if (errstring == NULL) { 2541 return; 2542 } 2543 *errstring = NULL; 2544 2545 if (errnum != 0) { 2546 syserr = strerror(errnum); 2547 if (syserr == NULL) { 2548 (void) sprintf(syserr_num, "errno=%d", errnum); 2549 syserr = syserr_num; 2550 } 2551 sep = err_sep; 2552 } 2553 2554 err = dgettext(TEXT_DOMAIN, err_strings[err_type]); 2555 /* Note: `asprintf` sets `*errstring` to `NULL` if it fails. */ 2556 (void) asprintf(errstring, "%s%s%s", err, sep, syserr); 2557 } 2558 2559 /* 2560 * do_list_common - list non-SHP attachment point 2561 */ 2562 static int 2563 do_list_common(di_node_t node, di_minor_t minor, void *arg) 2564 { 2565 di_node_t rnode; 2566 di_hp_t hp; 2567 char *minor_name; 2568 char *phys_path; 2569 2570 if ((minor_name = di_minor_name(minor)) == NULL) 2571 return (DI_WALK_CONTINUE); 2572 2573 /* 2574 * since PCIE/PCIHSHPC connectors have both hp nodes and minor nodes 2575 * created for now, we need to specifically exclude these connectors 2576 * during walking minor nodes. 2577 */ 2578 if ((phys_path = di_devfs_path(node)) == NULL) 2579 return (DI_WALK_CONTINUE); 2580 rnode = di_init(phys_path, DINFOSUBTREE | DINFOHP); 2581 di_devfs_path_free(phys_path); 2582 if (rnode == DI_NODE_NIL) 2583 return (DI_WALK_CONTINUE); 2584 2585 for (hp = DI_HP_NIL; (hp = di_hp_next(rnode, hp)) != DI_HP_NIL; ) { 2586 if (strcmp(di_hp_name(hp), minor_name) == 0) { 2587 di_fini(rnode); 2588 return (DI_WALK_CONTINUE); 2589 } 2590 } 2591 2592 di_fini(rnode); 2593 2594 return (do_list_common_impl(node, minor, NULL, arg)); 2595 } 2596 2597 /* 2598 * do_list_common_hp - list SHP attachment point 2599 */ 2600 static int 2601 do_list_common_hp( 2602 di_node_t node, 2603 di_hp_t hp, 2604 void *arg) 2605 { 2606 return (do_list_common_impl(node, NULL, hp, arg)); 2607 } 2608 2609 /* 2610 * do_list_common_impl - Routine to list attachment point as part of 2611 * a config_list opertion. Used by both v1 and v2 interfaces. 2612 * This is somewhat similar to config_get_lib() and its helper routines 2613 * except that the ap_ids are always physical and don't have dynamic 2614 * components. 2615 */ 2616 static int 2617 do_list_common_impl( 2618 di_node_t node, 2619 di_minor_t minor, 2620 di_hp_t hp, 2621 void *arg) 2622 { 2623 lib_loc_t lib_loc; 2624 plugin_lib_t *libp; 2625 list_stat_t *lstatp = NULL; 2626 cfga_err_t ret = CFGA_ERROR; 2627 2628 if (minor != DI_MINOR_NIL && hp != DI_HP_NIL) 2629 return (DI_WALK_CONTINUE); 2630 2631 lstatp = (list_stat_t *)arg; 2632 2633 lib_loc.libp = NULL; 2634 /* 2635 * try and find a lib for this node 2636 */ 2637 if (minor != DI_MINOR_NIL) { 2638 ret = find_lib(node, minor, &lib_loc); 2639 } else { 2640 ret = find_lib_hp(node, hp, &lib_loc); 2641 } 2642 if (ret != CFGA_OK) { 2643 return (DI_WALK_CONTINUE); 2644 } 2645 2646 /* 2647 * Load all plugins. We will check compatibility later in this 2648 * routine. 2649 */ 2650 lib_loc.vers_req.v_min = CFGA_HSL_V1; 2651 lib_loc.vers_req.v_max = CFGA_HSL_VERS; 2652 2653 if (minor != DI_MINOR_NIL) { 2654 ret = load_lib(node, minor, &lib_loc); 2655 } else { 2656 ret = load_lib_hp(node, hp, &lib_loc); 2657 } 2658 if (ret != CFGA_OK) { 2659 return (DI_WALK_CONTINUE); 2660 } 2661 2662 libp = lib_loc.libp; 2663 assert(libp != NULL); 2664 2665 /* 2666 * Note: For list type routines (list all attachment points in 2667 * device tree) we don't pass errstring to the plugin, nor do we 2668 * stop the walk if an error occurs in the plugin. 2669 */ 2670 if (compat_plugin(&lstatp->use_vers, libp->plugin_vers)) { 2671 if (minor != DI_MINOR_NIL) { 2672 (void) libp->vers_ops->stat_plugin(lstatp, 2673 &lib_loc, NULL); 2674 } else { 2675 /* 2676 * If the underlying hotplug daemon is not enabled, 2677 * the SHP attach points will not be shown, this 2678 * could confuse the uesrs. We specifically pass the 2679 * errstring to SHP plugin so that it can set the 2680 * errstring accordingly in this case, giving users 2681 * a hint. 2682 */ 2683 ret = libp->vers_ops->stat_plugin(lstatp, 2684 &lib_loc, lstatp->errstr); 2685 if (ret == CFGA_NOTSUPP && *(lstatp->errstr) != NULL) { 2686 if (lstatp->shp_errstr == NULL) { 2687 lstatp->shp_errstr = 2688 strdup(*(lstatp->errstr)); 2689 } 2690 } 2691 2692 if (*(lstatp->errstr) != NULL) { 2693 free(*(lstatp->errstr)); 2694 *(lstatp->errstr) = NULL; 2695 } 2696 } 2697 } 2698 rele_lib(libp); 2699 2700 return (DI_WALK_CONTINUE); 2701 } 2702 2703 /* 2704 * stat_common - stat a user specified set of attachment points. 2705 */ 2706 static cfga_err_t 2707 stat_common( 2708 int num_ap_ids, 2709 char *const *ap_ids, 2710 const char *class, 2711 list_stat_t *lstatp) 2712 { 2713 int i; 2714 lib_loc_t libloc; 2715 plugin_lib_t *libp; 2716 cfga_err_t rc = CFGA_OK; 2717 2718 2719 /* 2720 * operate on each ap_id 2721 */ 2722 for (i = 0; i < num_ap_ids; i++) { 2723 libloc.libp = NULL; 2724 if ((rc = config_get_lib(ap_ids[i], &libloc, 2725 lstatp->errstr)) != CFGA_OK) { 2726 break; 2727 } 2728 assert(libloc.libp != NULL); 2729 libp = libloc.libp; 2730 2731 /* 2732 * do pre-filtering if requested 2733 */ 2734 if (class != NULL && strcmp(libloc.ap_class, class)) { 2735 rele_lib(libp); 2736 continue; 2737 } 2738 2739 /* 2740 * Unlike list type routines, while stat'ing specific 2741 * attachment points we pass errstring to the plugins 2742 * and halt if an error occurs in the plugin. 2743 */ 2744 rc = libp->vers_ops->stat_plugin(lstatp, &libloc, 2745 lstatp->errstr); 2746 rele_lib(libp); 2747 if (rc != CFGA_OK) { 2748 break; 2749 } 2750 } 2751 2752 if (rc != CFGA_OK) { 2753 lstat_free(lstatp); 2754 } 2755 return (rc); 2756 } 2757 2758 /*ARGSUSED*/ 2759 static cfga_err_t 2760 null_stat_plugin(list_stat_t *lstatp, lib_loc_t *libloc_p, char **errstring) 2761 { 2762 return (CFGA_OK); 2763 } 2764 2765 /* 2766 * Pass errstring as a separate argument. Some higher level routines need 2767 * it to be NULL. 2768 */ 2769 static cfga_err_t 2770 stat_plugin_v1(list_stat_t *lstatp, lib_loc_t *libloc_p, char **errstring) 2771 { 2772 stat_data_list_t *slp, *slp2 = NULL; 2773 cfga_err_t rc; 2774 2775 /* 2776 * allocate stat data buffer and list element 2777 */ 2778 if ((slp = config_calloc_check(1, sizeof (stat_data_list_t), 2779 errstring)) == NULL) { 2780 return (CFGA_LIB_ERROR); 2781 } 2782 2783 /* 2784 * Do the stat 2785 */ 2786 errno = 0; 2787 if ((rc = (*(libloc_p->libp->cfga_stat_p))(libloc_p->ap_physical, 2788 &slp->stat_data, lstatp->opts, errstring)) != CFGA_OK) { 2789 S_FREE(slp); 2790 return (rc); 2791 } 2792 slp->next = NULL; 2793 2794 /* 2795 * Set up the logical and physical id's. 2796 * For v1 interfaces, the generic library (libcfgadm) creates the 2797 * ap_ids. mklog() is assumed to have been called in 2798 * the caller of this routine. 2799 */ 2800 (void) snprintf(slp->stat_data.ap_log_id, CFGA_AP_LOG_ID_LEN, "%s", 2801 libloc_p->ap_logical); 2802 2803 (void) snprintf(slp->stat_data.ap_phys_id, CFGA_AP_PHYS_ID_LEN, "%s", 2804 libloc_p->ap_physical); 2805 2806 /* 2807 * link it in 2808 */ 2809 if ((slp2 = lstatp->sdl) == NULL) { 2810 lstatp->sdl = slp; 2811 } else { 2812 while (slp2->next != NULL) 2813 slp2 = slp2->next; 2814 slp2->next = slp; 2815 } 2816 2817 /* keep count */ 2818 (*lstatp->countp)++; 2819 2820 return (CFGA_OK); 2821 } 2822 2823 static cfga_err_t 2824 stat_plugin_v2(list_stat_t *lstatp, lib_loc_t *libloc_p, char **errstring) 2825 { 2826 int i; 2827 array_list_t *alp, *alp2 = NULL; 2828 cfga_err_t rc; 2829 char *class; 2830 2831 /* 2832 * allocate array list 2833 */ 2834 if ((alp = config_calloc_check(1, sizeof (array_list_t), 2835 errstring)) == NULL) { 2836 return (CFGA_LIB_ERROR); 2837 } 2838 2839 alp->array = NULL; 2840 alp->nelem = 0; 2841 2842 /* 2843 * The listopts argument is currently unused. Use NULL 2844 */ 2845 errno = 0; 2846 if ((rc = (*(libloc_p->libp->cfga_list_ext_p))( 2847 libloc_p->ap_physical, &alp->array, &alp->nelem, lstatp->opts, NULL, 2848 errstring, lstatp->flags)) != CFGA_OK || alp->nelem <= 0) { 2849 S_FREE(alp); 2850 return (rc); 2851 } 2852 alp->next = NULL; 2853 2854 /* 2855 * Set up the logical and physical id's if necessary. 2856 * For v2 interfaces, the generic library (libcfgadm) creates the 2857 * ap_ids only if there are no dynamic attachment points and the 2858 * plug-in does not create the name itself. mklog() is 2859 * assumed to have been called in the caller of this routine. 2860 */ 2861 if (alp->nelem == 1) { 2862 char cphys, clog; 2863 2864 clog = (alp->array[0]).ap_log_id[0]; 2865 cphys = (alp->array[0]).ap_phys_id[0]; 2866 2867 if (clog == '\0') { 2868 (void) snprintf((alp->array[0]).ap_log_id, 2869 sizeof ((alp->array[0]).ap_log_id), "%s", 2870 libloc_p->ap_logical); 2871 } 2872 2873 if (cphys == '\0') { 2874 (void) snprintf((alp->array[0]).ap_phys_id, 2875 sizeof ((alp->array[0]).ap_phys_id), "%s", 2876 libloc_p->ap_physical); 2877 } 2878 } 2879 2880 if (libloc_p->ap_class[0] == '\0') { 2881 class = CFGA_NO_CLASS; 2882 } else { 2883 class = libloc_p->ap_class; 2884 } 2885 2886 /* Fill in the class information for all list elements */ 2887 for (i = 0; i < alp->nelem; i++) { 2888 (void) snprintf((alp->array[i]).ap_class, 2889 sizeof ((alp->array[i]).ap_class), "%s", class); 2890 } 2891 2892 /* 2893 * link it in 2894 */ 2895 if ((alp2 = lstatp->al) == NULL) { 2896 lstatp->al = alp; 2897 } else { 2898 while (alp2->next != NULL) 2899 alp2 = alp2->next; 2900 alp2->next = alp; 2901 } 2902 2903 /* keep count */ 2904 (*lstatp->countp) += alp->nelem; 2905 2906 return (CFGA_OK); 2907 } 2908 2909 /* 2910 * Check if a plugin version is within requested limits. 2911 */ 2912 static int 2913 compat_plugin(vers_req_t *reqp, int plugin_vers) 2914 { 2915 2916 if (!VALID_HSL_VERS(reqp->v_min) || !VALID_HSL_VERS(reqp->v_max) || 2917 !VALID_HSL_VERS(plugin_vers)) { 2918 return (0); 2919 } 2920 2921 if (plugin_vers < reqp->v_min || plugin_vers > reqp->v_max) { 2922 return (0); 2923 } 2924 2925 2926 return (1); 2927 } 2928 2929 /* 2930 * find_arg_type - determine if an argument is an ap_id or an ap_type. 2931 * Adapted from cfgadm.c 2932 */ 2933 static cfga_ap_types_t 2934 find_arg_type(const char *ap_id) 2935 { 2936 struct stat sbuf; 2937 cfga_ap_types_t type = UNKNOWN_AP; 2938 char *mkr = NULL; 2939 size_t len; 2940 int size_ap = 0, size_mkr = 0, digit = 0, i = 0; 2941 char *cp, path[MAXPATHLEN], ap_base[MAXPATHLEN]; 2942 2943 2944 /* 2945 * sanity checks 2946 */ 2947 if (ap_id == NULL || *ap_id == '\0') { 2948 2949 return (UNKNOWN_AP); 2950 } 2951 2952 /* 2953 * Extract the base component 2954 */ 2955 if ((cp = GET_DYN(ap_id)) != NULL) { 2956 len = cp - ap_id; 2957 } else { 2958 len = strlen(ap_id); 2959 } 2960 2961 if (len >= sizeof (ap_base)) { 2962 return (UNKNOWN_AP); 2963 } 2964 2965 /* Copy only the first "len" chars */ 2966 (void) strncpy(ap_base, ap_id, len); 2967 ap_base[len] = '\0'; 2968 2969 /* 2970 * If it starts with a slash and is stat-able its a physical. 2971 */ 2972 if (*ap_base == '/' && stat(ap_base, &sbuf) == 0) { 2973 return (PHYSICAL_AP); 2974 } 2975 2976 /* 2977 * Is this a symlink in CFGA_DEV_DIR ? 2978 */ 2979 (void) snprintf(path, sizeof (path), "%s%s", 2980 CFGA_DEV_DIR SLASH, ap_base); 2981 2982 if (lstat(path, &sbuf) == 0 && S_ISLNK(sbuf.st_mode) && 2983 stat(path, &sbuf) == 0) { 2984 return (LOGICAL_LINK_AP); 2985 } 2986 2987 /* 2988 * Check for ":" which is always present in an ap_id 2989 * but not in an ap_type. 2990 * we need to check that the characters right before the : are digits 2991 * since an ap_id is of the form <name><instance>:<specific ap name> 2992 */ 2993 if ((mkr = strchr(ap_base, ':')) == NULL) { 2994 type = AP_TYPE; 2995 } else { 2996 size_ap = strlen(ap_base); 2997 size_mkr = strlen(mkr); 2998 mkr = ap_base; 2999 3000 digit = 0; 3001 for (i = size_ap - size_mkr - 1; i > 0; i--) { 3002 if ((int)isdigit(mkr[i])) { 3003 digit++; 3004 break; 3005 } 3006 } 3007 if (digit == 0) { 3008 type = AP_TYPE; 3009 } else { 3010 type = LOGICAL_DRV_AP; 3011 } 3012 } 3013 3014 return (type); 3015 } 3016 3017 /*ARGSUSED*/ 3018 static cfga_err_t 3019 null_get_cond(lib_loc_t *liblocp, cfga_cond_t *condp, char **errstring) 3020 { 3021 return (CFGA_OK); 3022 } 3023 3024 static cfga_err_t 3025 get_cond_v1(lib_loc_t *liblocp, cfga_cond_t *condp, char **errstring) 3026 { 3027 plugin_lib_t *libp; 3028 cfga_stat_data_t sdbuf; 3029 cfga_err_t rc; 3030 3031 3032 libp = liblocp->libp; 3033 if (libp->plugin_vers != CFGA_HSL_V1) { 3034 return (CFGA_LIB_ERROR); 3035 } 3036 3037 errno = 0; 3038 if ((rc = (*liblocp->libp->cfga_stat_p)( 3039 liblocp->ap_physical, &sdbuf, NULL, errstring)) 3040 == CFGA_OK) { 3041 *condp = sdbuf.ap_cond; 3042 } else { 3043 *condp = CFGA_COND_UNKNOWN; 3044 } 3045 3046 return (rc); 3047 } 3048 3049 static cfga_err_t 3050 get_cond_v2(lib_loc_t *liblocp, cfga_cond_t *condp, char **errstring) 3051 { 3052 int nelem; 3053 plugin_lib_t *libp; 3054 cfga_list_data_t *ldbufp; 3055 cfga_err_t rc; 3056 3057 3058 libp = liblocp->libp; 3059 if (libp->plugin_vers != CFGA_HSL_V2) { 3060 return (CFGA_LIB_ERROR); 3061 } 3062 3063 errno = 0; 3064 nelem = 0; 3065 ldbufp = NULL; 3066 if ((rc = (*liblocp->libp->cfga_list_ext_p)( 3067 liblocp->ap_physical, &ldbufp, &nelem, NULL, NULL, 3068 errstring, 0)) == CFGA_OK) { 3069 assert(nelem == 1 && ldbufp != NULL); 3070 3071 *condp = ldbufp->ap_cond; 3072 S_FREE(ldbufp); 3073 } else { 3074 *condp = CFGA_COND_UNKNOWN; 3075 } 3076 3077 return (rc); 3078 } 3079 3080 /* mask represents the flags accepted */ 3081 static cfga_err_t 3082 check_flags(cfga_flags_t flags, cfga_flags_t mask, char **errstring) 3083 { 3084 if ((flags & ~mask) != 0) { 3085 config_err(0, INVALID_ARGS, errstring); 3086 return (CFGA_ERROR); 3087 } else { 3088 return (CFGA_OK); 3089 } 3090 } 3091 3092 static cfga_err_t 3093 check_apids(int num_ap_ids, char *const *ap_ids, char **errstring) 3094 { 3095 if (num_ap_ids <= 0 || ap_ids == NULL) { 3096 config_err(0, INVALID_ARGS, errstring); 3097 return (CFGA_ERROR); 3098 } else { 3099 return (CFGA_OK); 3100 } 3101 } 3102 3103 /* 3104 * Returns the class or the empty string if attacment point has 3105 * no class. 3106 */ 3107 static char * 3108 get_class(di_minor_t minor) 3109 { 3110 char *cp, c; 3111 size_t len; 3112 3113 3114 if (minor == DI_MINOR_NIL) { 3115 return (NULL); 3116 } 3117 3118 cp = di_minor_nodetype(minor); 3119 if (cp == NULL) { 3120 return (NULL); 3121 } 3122 3123 len = strlen(DDI_NT_ATTACHMENT_POINT); 3124 if (strncmp(cp, DDI_NT_ATTACHMENT_POINT, len)) { 3125 return (NULL); 3126 } 3127 3128 cp += len; 3129 3130 c = *cp; 3131 if (c != '\0' && c != ':') { 3132 return (NULL); 3133 } 3134 3135 if (c == ':') { 3136 cp++; 3137 } 3138 3139 return (cp); 3140 3141 } 3142 3143 /* 3144 * Transform stat data to list data 3145 */ 3146 static void 3147 stat_to_list(cfga_list_data_t *lp, cfga_stat_data_t *statp) 3148 { 3149 3150 (void) snprintf(lp->ap_log_id, sizeof (lp->ap_log_id), "%s", 3151 statp->ap_log_id); 3152 3153 (void) snprintf(lp->ap_phys_id, sizeof (lp->ap_phys_id), "%s", 3154 statp->ap_phys_id); 3155 3156 (void) snprintf(lp->ap_class, sizeof (lp->ap_class), "%s", 3157 CFGA_NO_CLASS); 3158 3159 lp->ap_r_state = statp->ap_r_state; 3160 lp->ap_o_state = statp->ap_o_state; 3161 lp->ap_cond = statp->ap_cond; 3162 lp->ap_busy = statp->ap_busy; 3163 lp->ap_status_time = statp->ap_status_time; 3164 3165 (void) snprintf(lp->ap_info, sizeof (lp->ap_info), "%s", 3166 statp->ap_info); 3167 (void) snprintf(lp->ap_type, sizeof (lp->ap_type), "%s", 3168 statp->ap_type); 3169 } 3170 3171 static void 3172 lstat_free(list_stat_t *lstatp) 3173 { 3174 stat_data_list_t *slp, *slp2; 3175 array_list_t *ap, *ap2; 3176 3177 slp = lstatp->sdl; 3178 while (slp != NULL) { 3179 slp2 = slp->next; 3180 S_FREE(slp); 3181 slp = slp2; 3182 } 3183 3184 lstatp->sdl = NULL; 3185 3186 ap = lstatp->al; 3187 while (ap != NULL) { 3188 ap2 = ap->next; 3189 S_FREE(ap->array); 3190 S_FREE(ap); 3191 ap = ap2; 3192 } 3193 3194 lstatp->al = NULL; 3195 } 3196 3197 static cfga_err_t 3198 split_apid(char *ap_id, char **dyncompp, char **errstring) 3199 { 3200 char *cp; 3201 3202 *dyncompp = NULL; 3203 3204 if (ap_id == NULL) { 3205 return (CFGA_ERROR); 3206 } 3207 3208 if ((cp = strstr(ap_id, CFGA_DYN_SEP)) == NULL) { 3209 return (CFGA_OK); 3210 } 3211 3212 *cp = '\0'; 3213 cp += strlen(CFGA_DYN_SEP); 3214 if ((*dyncompp = config_calloc_check(1, strlen(cp) + 1, 3215 errstring)) == NULL) { 3216 return (CFGA_LIB_ERROR); 3217 } 3218 (void) strcpy(*dyncompp, cp); 3219 3220 return (CFGA_OK); 3221 } 3222 3223 static void 3224 append_dyn(char *buf, const char *dyncomp, size_t blen) 3225 { 3226 if (dyncomp != NULL) { 3227 char *cp = buf + strlen(buf); 3228 size_t len = blen - strlen(buf); 3229 3230 (void) snprintf(cp, len, "%s%s", CFGA_DYN_SEP, 3231 dyncomp); 3232 } 3233 } 3234 3235 /* 3236 * Default implementation of cfga_ap_id_cmp. Works for most cases 3237 * except for long hex number sequences like world-wide-name. 3238 * 3239 * This function compares the ap's in a generic way. It does so by 3240 * determining the place of difference between the 2 aps. If the first 3241 * difference is a digit, it attempts to obtain the numbers and compare them 3242 * Otherwise it just compares the aps as strings 3243 */ 3244 static int 3245 default_ap_id_cmp(const char *ap_id1, const char *ap_id2) 3246 { 3247 int i = 0; 3248 3249 /* 3250 * Search for first different char 3251 */ 3252 while (ap_id1[i] == ap_id2[i] && ap_id1[i] != '\0') 3253 i++; 3254 3255 /* 3256 * If one of the char is a digit, back up to where the 3257 * number started, compare the number. 3258 */ 3259 if (isdigit(ap_id1[i]) || isdigit(ap_id2[i])) { 3260 while ((i > 0) && isdigit(ap_id1[i - 1])) 3261 i--; 3262 3263 if (isdigit(ap_id1[i]) && isdigit(ap_id2[i])) 3264 return (atoi(ap_id1 + i) - atoi(ap_id2 + i)); 3265 } 3266 3267 /* One of them isn't a number, compare the char */ 3268 return (ap_id1[i] - ap_id2[i]); 3269 } 3270 3271 static void 3272 hold_lib(plugin_lib_t *libp) 3273 { 3274 assert(libp->refcnt >= 0); 3275 (void) mutex_lock(&libp->lock); 3276 libp->refcnt++; 3277 (void) mutex_unlock(&libp->lock); 3278 } 3279 3280 static void 3281 rele_lib(plugin_lib_t *libp) 3282 { 3283 assert(libp->refcnt > 0); 3284 (void) mutex_lock(&libp->lock); 3285 libp->refcnt--; 3286 (void) mutex_unlock(&libp->lock); 3287 } 3288