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