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