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