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