4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 /* Portions Copyright 2005 Cyril Plisko */
25 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
44 #include <sys/types.h>
46 #include <sys/param.h>
49 #include <sys/systeminfo.h>
50 #include <sys/sunddi.h>
51 #include <libdevinfo.h>
58 #define CFGA_PLUGIN_LIB
59 #include <config_admin.h>
61 /* Limit size of sysinfo return */
62 #define SYSINFO_LENGTH 256
65 * Attachment point specifier types.
75 static char *listopt_array
[] = {
77 #define LISTOPT_CLASS 0
83 int v_min
; /* Min acceptable version */
84 int v_max
; /* Max acceptable version */
87 #define INVALID_VERSION -1
88 #define VALID_HSL_VERS(v) (((v) >= CFGA_HSL_V1) && \
89 ((v) <= CFGA_HSL_VERS))
92 * Incomplete definition
97 * Structure that contains plugin library information.
99 typedef struct plugin_lib
{
100 struct plugin_lib
*next
; /* pointer to next */
101 mutex_t lock
; /* protects refcnt */
102 int refcnt
; /* reference count */
103 void *handle
; /* handle from dlopen */
104 cfga_err_t (*cfga_change_state_p
)();
105 cfga_err_t (*cfga_private_func_p
)();
106 cfga_err_t (*cfga_test_p
)();
107 cfga_err_t (*cfga_stat_p
)();
108 cfga_err_t (*cfga_list_p
)();
109 cfga_err_t (*cfga_help_p
)();
110 int (*cfga_ap_id_cmp_p
)();
111 cfga_err_t (*cfga_list_ext_p
)(); /* For V2 plug-ins only */
113 int plugin_vers
; /* actual plugin version */
114 struct cfga_vers_ops
*vers_ops
; /* version dependant routines */
115 char libpath
[MAXPATHLEN
]; /* full pathname to lib */
118 static plugin_lib_t plugin_list
;
120 typedef struct lib_cache
{
121 struct lib_cache
*lc_next
;
122 plugin_lib_t
*lc_libp
;
124 char *lc_ap_physical
; /* physical ap_id */
125 char *lc_ap_logical
; /* logical ap_id */
128 static lib_cache_t
*lib_cache
;
129 static mutex_t lib_cache_lock
;
132 * Library locator data struct - used to pass down through the device
135 typedef struct lib_locator
{
136 char ap_base
[MAXPATHLEN
];
137 char ap_logical
[CFGA_LOG_EXT_LEN
];
138 char ap_physical
[CFGA_PHYS_EXT_LEN
];
139 char ap_class
[CFGA_CLASS_LEN
];
140 char pathname
[MAXPATHLEN
];
143 vers_req_t vers_req
; /* plug-in version required */
147 * linked list of cfga_stat_data structs - used for
150 typedef struct stat_data_list
{
151 struct stat_data_list
*next
;
152 cfga_stat_data_t stat_data
;
156 * linked list of arrays. Each array represents a bunch
157 * of list_data_t structures returned by a single call
158 * to a plugin's cfga_list_ext() routine.
160 typedef struct array_list
{
161 struct array_list
*next
;
162 cfga_list_data_t
*array
;
167 * encapsulate config_list args to get them through the tree
170 typedef struct list_stat
{
171 const char *opts
; /* Hardware specific options */
174 int *countp
; /* Total number of list and stat structures */
175 stat_data_list_t
*sdl
; /* Linked list of stat structures */
176 array_list_t
*al
; /* Linked list of arrays of list structures */
177 vers_req_t use_vers
; /* plugin versions to be stat'ed */
178 char *shp_errstr
; /* only for shp plugin */
182 * Internal operations for libcfgadm which are version dependant
184 struct cfga_vers_ops
{
185 cfga_err_t (*resolve_lib
)(plugin_lib_t
*libp
);
186 cfga_err_t (*stat_plugin
)(list_stat_t
*, lib_loc_t
*, char **errstring
);
187 cfga_err_t (*mklog
)(di_node_t
, di_minor_t
, plugin_lib_t
*,
189 cfga_err_t (*get_cond
)(lib_loc_t
*, cfga_cond_t
*, char **);
194 * Lock to protect list of libraries
196 static mutex_t plugin_list_lock
;
199 * Forward declarations
202 static const char *__config_strerror(cfga_err_t
);
203 static void *config_calloc_check(size_t, size_t, char **);
204 static cfga_err_t
resolve_lib_ref(plugin_lib_t
*, lib_loc_t
*);
205 static cfga_err_t
config_get_lib(const char *, lib_loc_t
*, char **);
206 static int check_ap(di_node_t
, di_minor_t
, void *);
207 static int check_ap_hp(di_node_t
, di_hp_t
, void *);
208 static int check_ap_impl(di_node_t
, di_minor_t
, di_hp_t
, void *);
209 static int check_ap_phys(di_node_t
, di_minor_t
, void *);
210 static int check_ap_phys_hp(di_node_t
, di_hp_t
, void *);
211 static int check_ap_phys_impl(di_node_t
, di_minor_t
, di_hp_t
, void *);
213 static cfga_err_t
find_ap_common(lib_loc_t
*libloc_p
, const char *rootpath
,
214 int (*fcn
)(di_node_t node
, di_minor_t minor
, void *arg
),
215 int (*fcn_hp
)(di_node_t node
, di_hp_t hp
, void *arg
),
218 static plugin_lib_t
*lib_in_list(char *);
219 static cfga_err_t
find_lib(di_node_t
, di_minor_t
, lib_loc_t
*);
220 static cfga_err_t
find_lib_hp(di_node_t
, di_hp_t
, lib_loc_t
*);
221 static cfga_err_t
find_lib_impl(char *, lib_loc_t
*);
222 static cfga_err_t
load_lib(di_node_t
, di_minor_t
, lib_loc_t
*);
223 static cfga_err_t
load_lib_hp(di_node_t
, di_hp_t
, lib_loc_t
*);
224 static cfga_err_t
load_lib_impl(di_node_t
, di_minor_t
, di_hp_t
, lib_loc_t
*);
225 extern void bcopy(const void *, void *, size_t);
226 static void config_err(int, int, char **);
227 static void hold_lib(plugin_lib_t
*);
228 static void rele_lib(plugin_lib_t
*);
230 static cfga_err_t
parse_listopt(char *listopts
, char **classpp
,
233 static cfga_err_t
list_common(list_stat_t
*lstatp
, const char *class);
234 static int do_list_common(di_node_t node
, di_minor_t minor
, void *arg
);
235 static int do_list_common_hp(di_node_t node
, di_hp_t hp
, void *arg
);
236 static int do_list_common_impl(di_node_t node
, di_minor_t minor
,
237 di_hp_t hp
, void *arg
);
238 static cfga_err_t
stat_common(int num_ap_ids
, char *const *ap_ids
,
239 const char *class, list_stat_t
*lstatp
);
241 static cfga_err_t
null_resolve(plugin_lib_t
*libp
);
242 static cfga_err_t
resolve_v1(plugin_lib_t
*libp
);
243 static cfga_err_t
resolve_v2(plugin_lib_t
*libp
);
245 static cfga_err_t
mklog_common(di_node_t node
, di_minor_t minor
,
246 lib_loc_t
*liblocp
, size_t len
);
248 static cfga_err_t
null_mklog(di_node_t node
, di_minor_t minor
,
249 plugin_lib_t
*libp
, lib_loc_t
*liblocp
);
250 static cfga_err_t
mklog_v1(di_node_t node
, di_minor_t minor
,
251 plugin_lib_t
*libp
, lib_loc_t
*liblocp
);
252 static cfga_err_t
mklog_v2(di_node_t node
, di_minor_t minor
,
253 plugin_lib_t
*libp
, lib_loc_t
*liblocp
);
255 static cfga_err_t
null_stat_plugin(list_stat_t
*lstatp
, lib_loc_t
*libloc_p
,
257 static cfga_err_t
stat_plugin_v2(list_stat_t
*lstat
, lib_loc_t
*libloc_p
,
259 static cfga_err_t
stat_plugin_v1(list_stat_t
*lstat
, lib_loc_t
*libloc_p
,
262 static cfga_err_t
null_get_cond(lib_loc_t
*liblocp
, cfga_cond_t
*condp
,
264 static cfga_err_t
get_cond_v1(lib_loc_t
*liblocp
, cfga_cond_t
*condp
,
266 static cfga_err_t
get_cond_v2(lib_loc_t
*liblocp
, cfga_cond_t
*condp
,
269 static cfga_err_t
realloc_data(cfga_stat_data_t
**ap_id_list
,
270 int *nlistp
, list_stat_t
*lstatp
);
271 static cfga_err_t
realloc_data_ext(cfga_list_data_t
**ap_id_list
,
272 int *nlistp
, list_stat_t
*lstatp
);
274 static void stat_to_list(cfga_list_data_t
*lp
, cfga_stat_data_t
*statp
);
275 static void lstat_free(list_stat_t
*lstatp
);
276 static cfga_ap_types_t
find_arg_type(const char *ap_id
);
277 static int compat_plugin(vers_req_t
*reqp
, int plugin_vers
);
279 static cfga_err_t
check_flags(cfga_flags_t flags
, cfga_flags_t mask
,
281 static cfga_err_t
check_apids(int num_ap_ids
, char *const *ap_ids
,
284 static char *get_class(di_minor_t minor
);
285 static cfga_err_t
split_apid(char *ap_id
, char **dyncompp
, char **errstring
);
286 static void append_dyn(char *buf
, const char *dyncomp
, size_t blen
);
287 static int default_ap_id_cmp(const char *ap_id1
, const char *ap_id2
);
288 static void destroy_cache();
291 * Plugin library search path helpers
293 #define LIB_PATH_BASE1 "/usr/platform/"
294 #define LIB_PATH_BASE2 "/usr"
295 #if defined(__sparcv9)
296 #define LIB_PATH_MIDDLE "/lib/cfgadm/sparcv9/"
297 #elif defined(__amd64)
298 #define LIB_PATH_MIDDLE "/lib/cfgadm/amd64/"
300 #define LIB_PATH_MIDDLE "/lib/cfgadm/"
302 #define LIB_PATH_TAIL ".so.1"
305 #if !defined(TEXT_DOMAIN)
306 #define TEXT_DOMAIN "SYS_TEST"
312 #define DEVICES_DIR "/devices"
313 #define DOT_DOT_DEVICES "../devices"
314 #define CFGA_DEV_DIR "/dev/cfg"
316 #define S_FREE(x) (((x) != NULL) ? (free(x), (x) = NULL) : (void *)0)
317 #define GET_DYN(a) (strstr((a), CFGA_DYN_SEP))
319 #define CFGA_NO_CLASS "none"
324 #define DI_INIT_FAILED 1
325 #define ALLOC_FAILED 2
326 #define INVALID_ARGS 3
331 "Device library initialize failed",
332 "Memory allocation failed",
333 "Invalid argument(s)"
336 static const char err_sep
[] = ": ";
340 * Table of version dependant routines
342 static struct cfga_vers_ops cfga_vers_ops
[CFGA_HSL_VERS
+ 1] = {
344 {null_resolve
, null_stat_plugin
, null_mklog
, null_get_cond
},
345 {resolve_v1
, stat_plugin_v1
, mklog_v1
, get_cond_v1
},
346 {resolve_v2
, stat_plugin_v2
, mklog_v2
, get_cond_v2
}
349 #define VERS_ARRAY_SZ (sizeof (cfga_vers_ops)/sizeof (cfga_vers_ops[0]))
353 * Public interfaces for libcfgadm, as documented in config_admin.3x
357 * config_change_state
362 cfga_cmd_t state_change_cmd
,
366 struct cfga_confirm
*confp
,
367 struct cfga_msg
*msgp
,
375 * call cfga_state_change_func
378 * call it's cfga_stat
380 * call cfga_state_change_func
388 cfga_err_t retval
= CFGA_OK
;
391 if (state_change_cmd
== CFGA_CMD_NONE
)
394 if ((state_change_cmd
< CFGA_CMD_NONE
) ||
395 (state_change_cmd
> CFGA_CMD_UNCONFIGURE
))
398 if (errstring
!= NULL
) {
402 if (check_flags(flags
, CFGA_FLAG_FORCE
| CFGA_FLAG_VERBOSE
, errstring
)
407 if (check_apids(num_ap_ids
, ap_id
, errstring
) != CFGA_OK
) {
412 * operate on each ap_id
414 for (i
= 0; (i
< num_ap_ids
) && (retval
== CFGA_OK
); i
++) {
416 if ((retval
= config_get_lib(ap_id
[i
], &libloc
, errstring
)) !=
422 if ((flags
& CFGA_FLAG_FORCE
) ||
423 (state_change_cmd
== CFGA_CMD_UNLOAD
) ||
424 (state_change_cmd
== CFGA_CMD_DISCONNECT
) ||
425 (state_change_cmd
== CFGA_CMD_UNCONFIGURE
)) {
427 retval
= (*libp
->cfga_change_state_p
)
428 (state_change_cmd
, libloc
.ap_physical
, options
,
429 confp
, msgp
, errstring
, flags
);
432 * Need to check condition before proceeding in
433 * the "configure direction"
435 if ((retval
= libp
->vers_ops
->get_cond(&libloc
, &cond
,
436 errstring
)) != CFGA_OK
) {
440 if (cond
== CFGA_COND_OK
|| cond
== CFGA_COND_UNKNOWN
) {
443 (*libp
->cfga_change_state_p
)(
445 libloc
.ap_physical
, options
,
446 confp
, msgp
, errstring
,
449 retval
= CFGA_INSUFFICENT_CONDITION
;
459 * config_private_func
464 const char *function
,
468 struct cfga_confirm
*confp
,
469 struct cfga_msg
*msgp
,
475 cfga_err_t retval
= CFGA_OK
;
478 if (errstring
!= NULL
) {
482 if (check_flags(flags
, CFGA_FLAG_FORCE
| CFGA_FLAG_VERBOSE
, errstring
)
487 if (check_apids(num_ap_ids
, ap_ids
, errstring
) != CFGA_OK
) {
492 * operate on each ap_id
494 for (i
= 0; (i
< num_ap_ids
) && (retval
== CFGA_OK
); i
++) {
496 if ((retval
= config_get_lib(ap_ids
[i
], &libloc
, errstring
)) !=
502 retval
= (*libloc
.libp
->cfga_private_func_p
)(function
,
503 libloc
.ap_physical
, options
, confp
, msgp
, errstring
,
505 rele_lib(libloc
.libp
);
521 struct cfga_msg
*msgp
,
527 cfga_err_t retval
= CFGA_OK
;
529 if (errstring
!= NULL
) {
533 if (check_flags(flags
, CFGA_FLAG_FORCE
| CFGA_FLAG_VERBOSE
, errstring
)
538 if (check_apids(num_ap_ids
, ap_ids
, errstring
) != CFGA_OK
) {
543 * operate on each ap_id
545 for (i
= 0; (i
< num_ap_ids
) && (retval
== CFGA_OK
); i
++) {
547 if ((retval
= config_get_lib(ap_ids
[i
], &libloc
, errstring
)) !=
553 retval
= (*libloc
.libp
->cfga_test_p
)(libloc
.ap_physical
,
554 options
, msgp
, errstring
, flags
);
555 rele_lib(libloc
.libp
);
565 struct cfga_stat_data
*buf
,
570 list_stat_t lstat
= {NULL
};
571 cfga_err_t rc
= CFGA_OK
;
573 if (check_apids(num_ap_ids
, ap_ids
, errstring
) != CFGA_OK
) {
578 * V1 entry points don't support dynamic attachment points
580 for (i
= 0; i
< num_ap_ids
; i
++) {
581 if (GET_DYN(ap_ids
[i
]) != NULL
) {
582 return (CFGA_APID_NOEXIST
);
588 lstat
.countp
= &nstat
;
589 lstat
.opts
= options
;
590 lstat
.errstr
= errstring
;
591 lstat
.shp_errstr
= NULL
;
593 * This is a V1 interface which can use only V1 plugins
595 lstat
.use_vers
.v_max
= lstat
.use_vers
.v_min
= CFGA_HSL_V1
;
597 rc
= stat_common(num_ap_ids
, ap_ids
, NULL
, &lstat
);
599 assert(*lstat
.countp
== num_ap_ids
);
600 rc
= realloc_data(&buf
, &n
, &lstat
);
611 struct cfga_stat_data
**ap_id_list
,
617 list_stat_t lstat
= {NULL
};
618 cfga_err_t retval
= CFGA_ERROR
;
620 if (errstring
!= NULL
) {
625 lstat
.countp
= &nstat
;
626 lstat
.opts
= options
;
627 lstat
.errstr
= errstring
;
628 lstat
.shp_errstr
= NULL
;
630 * This is a V1 interface which can use only V1 plugins
632 lstat
.use_vers
.v_max
= lstat
.use_vers
.v_min
= CFGA_HSL_V1
;
639 * V1 interfaces don't support prefiltering, no class
642 retval
= list_common(&lstat
, NULL
);
643 if (retval
== CFGA_OK
) {
644 retval
= realloc_data(ap_id_list
, nlistp
, &lstat
);
647 assert((ap_id_list
!= NULL
&& *nlistp
!= 0) ||
648 (ap_id_list
== NULL
&& *nlistp
== 0));
650 if (retval
== CFGA_OK
&& *nlistp
== 0) {
651 return (CFGA_NOTSUPP
);
665 struct cfga_list_data
**ap_id_list
,
668 const char *listopts
,
672 int nstat
, list
, prefilter
;
673 list_stat_t lstat
= {NULL
};
676 cfga_err_t rc
= CFGA_ERROR
;
681 if (errstring
!= NULL
) {
685 if (check_flags(flags
, CFGA_FLAG_LIST_ALL
, errstring
) != CFGA_OK
) {
690 if ((rc
= parse_listopt((char *)listopts
, &class, errstring
))
695 prefilter
= (class == NULL
) ? 0 : 1;
698 lstat
.countp
= &nstat
;
699 lstat
.opts
= options
;
700 lstat
.errstr
= errstring
;
701 lstat
.shp_errstr
= NULL
;
704 * We support both V1 and V2 plugins through this entry
707 lstat
.use_vers
.v_min
= CFGA_HSL_V1
;
708 lstat
.use_vers
.v_max
= CFGA_HSL_V2
;
711 if (num_ap_ids
== 0 && ap_ids
== NULL
) {
713 * discover and stat all attachment points
716 rc
= list_common(&lstat
, class);
717 } else if (num_ap_ids
> 0 && ap_ids
!= NULL
) {
719 * Stat specified attachment points. With dynamic expansion
720 * more data may be returned than was specified by user.
722 rc
= stat_common(num_ap_ids
, ap_ids
, class, &lstat
);
733 rc
= realloc_data_ext(ap_id_list
, nlistp
, &lstat
);
735 assert((ap_id_list
!= NULL
&& *nlistp
!= 0) ||
736 (ap_id_list
== NULL
&& *nlistp
== 0));
739 * For the list command notify user if no attachment
740 * point is found in the system.
743 if (list
&& rc
== CFGA_OK
&& *nlistp
== 0) {
745 * If attachment points are being prefiltered, absence of data
746 * does not imply that config. admin. is not
747 * supported by the system.
751 * Prefiltering: requested class is absent
753 return (CFGA_APID_NOEXIST
);
756 * No attachment points in system
758 return (CFGA_NOTSUPP
);
769 * Attempts to remove all libs on the plugin list.
774 plugin_lib_t
*libp
, *prev
= &plugin_list
, *next
= NULL
;
776 /* destroy cache entries to remove refcnt agains plugins */
779 (void) mutex_lock(&plugin_list_lock
);
780 for (libp
= plugin_list
.next
; libp
!= NULL
; libp
= next
) {
782 (void) mutex_lock(&libp
->lock
);
784 (void) mutex_unlock(&libp
->lock
);
788 (void) mutex_unlock(&libp
->lock
);
790 (void) dlclose(libp
->handle
);
791 (void) mutex_destroy(&libp
->lock
);
794 (void) mutex_unlock(&plugin_list_lock
);
802 const cfga_ap_log_id_t ap1
,
803 const cfga_ap_log_id_t ap2
)
807 char apstat1
[CFGA_PHYS_EXT_LEN
];
808 char apstat2
[CFGA_PHYS_EXT_LEN
];
812 * Extract static ap_ids
814 (void) strlcpy(apstat1
, ap1
, sizeof (apstat1
));
815 (void) strlcpy(apstat2
, ap2
, sizeof (apstat2
));
817 sep1
= GET_DYN(apstat1
);
818 sep2
= GET_DYN(apstat2
);
826 * Use the default comparator for static ap_ids
828 ret
= default_ap_id_cmp(apstat1
, apstat2
);
833 * static components match. They belong to
834 * the same static ap_id. Check if both are dynamic
835 * If not, static < dynamic.
837 if ((sep1
== NULL
) ^ (sep2
== NULL
))
838 return (sep1
? 1 : -1);
841 * If both are static, then ap1 = ap2
847 * Both are dynamic and belong to same static ap_id.
848 * Use the plugin comparator
851 if (config_get_lib(ap1
, &libloc
, NULL
) != CFGA_OK
) {
852 return (strncmp(sep1
, sep2
, CFGA_PHYS_EXT_LEN
));
855 ret
= (*libloc
.libp
->cfga_ap_id_cmp_p
)(ap1
, ap2
);
857 rele_lib(libloc
.libp
);
867 config_strerror(cfga_err_t cfgerrnum
)
869 const char *ep
= NULL
;
871 if ((cfgerrnum
< CFGA_OK
) || (cfgerrnum
> CFGA_ATTR_INVAL
))
874 ep
= __config_strerror(cfgerrnum
);
876 return ((ep
!= NULL
) ? dgettext(TEXT_DOMAIN
, ep
) : NULL
);
886 struct cfga_msg
*msgp
,
892 cfga_err_t retval
= CFGA_OK
;
894 if (check_flags(flags
, CFGA_FLAG_FORCE
| CFGA_FLAG_VERBOSE
, NULL
)
899 if (num_ap_ids
< 0) {
903 if (num_ap_ids
> 0 && ap_ids
== NULL
) {
908 * operate on each ap_id
910 for (i
= 0; (i
< num_ap_ids
) && (retval
== CFGA_OK
); i
++) {
912 if ((retval
= config_get_lib(ap_ids
[i
], &libloc
,
918 retval
= (*libloc
.libp
->cfga_help_p
)(msgp
, options
, flags
);
919 rele_lib(libloc
.libp
);
925 * Private support routines for the public interfaces
929 __config_strerror(cfga_err_t cfgerrnum
)
931 const char *ep
= NULL
;
935 ep
= "Configuration operation succeeded";
938 ep
= "Configuration operation cancelled";
941 ep
= "Configuration operation invalid";
944 ep
= "Configuration administration not supported";
947 ep
= "Configuration operation not supported";
950 ep
= "Insufficient privileges";
953 ep
= "Component system is busy, try again";
955 case CFGA_SYSTEM_BUSY
:
956 ep
= "System is busy, try again";
958 case CFGA_DATA_ERROR
:
962 ep
= "Library error";
965 ep
= "No Library found";
967 case CFGA_INSUFFICENT_CONDITION
:
968 ep
= "Insufficient condition";
971 ep
= "Hardware specific failure";
973 case CFGA_APID_NOEXIST
:
974 ep
= "Attachment point not found";
976 case CFGA_ATTR_INVAL
:
977 ep
= "No attachment point with specified attributes found";
987 * listopts is a string in the getsubopt(3C) style:
988 * name1=value1,name2=value2,
991 parse_listopt(char *listopts
, char **classpp
, char **errstring
)
993 char *bufp
, *optp
, *val
= NULL
;
994 cfga_err_t rc
= CFGA_ERROR
;
999 * NULL is a legal value for listopts
1001 if (listopts
== NULL
) {
1005 if ((bufp
= config_calloc_check(1, strlen(listopts
) + 1, errstring
))
1007 return (CFGA_LIB_ERROR
);
1009 (void) strcpy(bufp
, listopts
);
1011 optp
= bufp
; /* getsubopt() modifies its argument */
1012 while (*optp
!= '\0') {
1013 switch (getsubopt(&optp
, listopt_array
, &val
)) {
1015 if (val
== NULL
|| *classpp
!= NULL
) {
1019 if ((*classpp
= config_calloc_check(1, strlen(val
) + 1,
1020 errstring
)) == NULL
) {
1021 rc
= CFGA_LIB_ERROR
;
1024 (void) strcpy(*classpp
, val
);
1036 if (rc
!= CFGA_OK
) {
1060 const size_t len
= CFGA_AP_LOG_ID_LEN
;
1062 assert(len
<= sizeof (liblocp
->ap_logical
));
1064 if (libp
->plugin_vers
!= CFGA_HSL_V1
) {
1065 return (CFGA_LIB_ERROR
);
1068 return (mklog_common(node
, minor
, liblocp
, len
));
1073 * Obtain the devlink from a /devices path
1076 get_link(di_devlink_t devlink
, void *arg
)
1078 char *linkp
= (char *)arg
;
1080 (void) snprintf(linkp
, CFGA_LOG_EXT_LEN
, "%s",
1081 di_devlink_path(devlink
));
1082 return (DI_WALK_TERMINATE
);
1092 const size_t len
= CFGA_LOG_EXT_LEN
;
1093 di_devlink_handle_t hdl
;
1095 assert(len
<= sizeof (liblocp
->ap_logical
));
1097 if (libp
->plugin_vers
!= CFGA_HSL_V2
) {
1098 return (CFGA_LIB_ERROR
);
1101 /* open devlink database */
1102 if ((hdl
= di_devlink_init(NULL
, 0)) == NULL
) {
1103 return (CFGA_LIB_ERROR
);
1106 liblocp
->ap_logical
[0] = '\0';
1107 (void) di_devlink_walk(hdl
, NULL
,
1108 liblocp
->ap_physical
+ strlen(DEVICES_DIR
),
1109 DI_PRIMARY_LINK
, (void *)liblocp
->ap_logical
, get_link
);
1111 (void) di_devlink_fini(&hdl
);
1113 if (liblocp
->ap_logical
[0] != '\0')
1115 return (mklog_common(node
, minor
, liblocp
, len
));
1119 * mklog_common - make a logical name from the driver and instance
1125 lib_loc_t
*libloc_p
,
1129 char *drv
, *minor_name
;
1131 drv
= di_driver_name(node
);
1132 inst
= di_instance(node
);
1133 minor_name
= di_minor_name(minor
);
1136 if (drv
!= NULL
&& inst
!= -1 && minor_name
!= NULL
&&
1137 snprintf(libloc_p
->ap_logical
, len
, "%s%d:%s", drv
, inst
,
1138 minor_name
) < len
) { /* snprintf returns strlen */
1142 return (CFGA_LIB_ERROR
);
1146 * mklog_common - make a logical name from the driver and instance
1156 const size_t len
= CFGA_LOG_EXT_LEN
;
1158 char *drv
, *hp_name
;
1160 drv
= di_driver_name(node
);
1161 inst
= di_instance(node
);
1162 hp_name
= di_hp_name(hp
);
1165 if (drv
!= NULL
&& inst
!= -1 && hp_name
!= NULL
&&
1166 snprintf(liblocp
->ap_logical
, len
, "%s%d:%s", drv
, inst
,
1167 hp_name
) < len
) { /* snprintf returns strlen */
1171 return (CFGA_LIB_ERROR
);
1175 * resolve_lib_ref - relocate to use plugin lib
1180 lib_loc_t
*libloc_p
)
1183 void *libhdlp
= libp
->handle
;
1186 if ((sym
= dlsym(libhdlp
, "cfga_version")) == NULL
) {
1188 * Version symbol not defined, must be the first version
1190 plug_vers
= CFGA_HSL_V1
;
1192 plug_vers
= *((int *)sym
);
1196 * Check if plugin version matches request.
1198 if (!compat_plugin(&libloc_p
->vers_req
, plug_vers
)) {
1199 return (CFGA_NO_LIB
);
1203 * Record the plugin version and setup version dependant routines
1205 assert(plug_vers
< VERS_ARRAY_SZ
);
1206 libp
->plugin_vers
= plug_vers
;
1207 libp
->vers_ops
= &cfga_vers_ops
[plug_vers
];
1209 /* resolve symbols common to all versions */
1210 if ((sym
= dlsym(libhdlp
, "cfga_change_state")) == NULL
) {
1211 perror("dlsym: cfga_change_state");
1212 return (CFGA_LIB_ERROR
);
1214 libp
->cfga_change_state_p
= (cfga_err_t (*)(cfga_cmd_t
,
1215 const char *, const char *, struct cfga_confirm
*,
1216 struct cfga_msg
*, char **, cfga_flags_t
)) sym
;
1218 if ((sym
= dlsym(libhdlp
, "cfga_private_func")) == NULL
) {
1219 perror("dlsym: cfga_private_func");
1220 return (CFGA_LIB_ERROR
);
1222 libp
->cfga_private_func_p
= (cfga_err_t (*)(const char *,
1223 const char *, const char *, struct cfga_confirm
*,
1224 struct cfga_msg
*, char **, cfga_flags_t
))sym
;
1226 if ((sym
= dlsym(libhdlp
, "cfga_test")) == NULL
) {
1227 perror("dlsym: cfga_test");
1228 return (CFGA_LIB_ERROR
);
1230 libp
->cfga_test_p
= (cfga_err_t (*)(const char *, const char *,
1231 struct cfga_msg
*, char **, cfga_flags_t
))sym
;
1233 if ((sym
= dlsym(libhdlp
, "cfga_help")) == NULL
) {
1234 perror("dlsym: cfga_help");
1235 return (CFGA_LIB_ERROR
);
1237 libp
->cfga_help_p
= (cfga_err_t (*)(struct cfga_msg
*,
1238 const char *, cfga_flags_t
))sym
;
1240 if ((sym
= dlsym(libhdlp
, "cfga_ap_id_cmp")) == NULL
) {
1241 libp
->cfga_ap_id_cmp_p
= default_ap_id_cmp
;
1243 libp
->cfga_ap_id_cmp_p
= (int (*)(const
1244 cfga_ap_log_id_t
, const cfga_ap_log_id_t
))sym
;
1246 /* Resolve version specific symbols */
1247 return (libp
->vers_ops
->resolve_lib(libp
));
1252 null_resolve(plugin_lib_t
*libp
)
1258 resolve_v1(plugin_lib_t
*libp
)
1260 void *sym
, *libhdlp
= libp
->handle
;
1263 if (libp
->plugin_vers
!= CFGA_HSL_V1
) {
1264 return (CFGA_NO_LIB
);
1267 if ((sym
= dlsym(libhdlp
, "cfga_stat")) == NULL
) {
1268 perror("dlsym: cfga_stat");
1269 return (CFGA_LIB_ERROR
);
1271 libp
->cfga_stat_p
= (cfga_err_t (*)(const char *,
1272 struct cfga_stat_data
*, const char *,
1275 if ((sym
= dlsym(libhdlp
, "cfga_list")) == NULL
) {
1276 perror("dlsym: cfga_list");
1277 return (CFGA_LIB_ERROR
);
1279 libp
->cfga_list_p
= (cfga_err_t (*)(struct cfga_stat_data
**,
1280 int *, const char *, char **))sym
;
1286 resolve_v2(plugin_lib_t
*libp
)
1291 if (libp
->plugin_vers
!= CFGA_HSL_V2
) {
1292 return (CFGA_NO_LIB
);
1295 if ((sym
= dlsym(libp
->handle
, "cfga_list_ext")) == NULL
) {
1296 perror("dlsym: cfga_list_ext");
1297 return (CFGA_LIB_ERROR
);
1299 libp
->cfga_list_ext_p
= (cfga_err_t (*)(const char *,
1300 struct cfga_list_data
**, int *, const char *,
1301 const char *, char **, cfga_flags_t
))sym
;
1307 * config_calloc_check - perform allocation, check result and
1311 config_calloc_check(
1318 p
= calloc(nelem
, elsize
);
1320 config_err(0, ALLOC_FAILED
, errstring
);
1328 * config_get_lib - given an ap_id find the library name
1329 * If successful, the plugin library is held.
1334 lib_loc_t
*lib_loc_p
,
1337 char *dyncomp
, path
[PATH_MAX
];
1339 cfga_ap_types_t type
= UNKNOWN_AP
;
1340 cfga_err_t ret
= CFGA_ERROR
;
1342 if (ap_id
== NULL
) {
1343 config_err(0, INVALID_ARGS
, errstring
);
1347 lib_loc_p
->libp
= NULL
;
1349 if ((apdup
= config_calloc_check(1, strlen(ap_id
) + 1, errstring
))
1351 return (CFGA_LIB_ERROR
);
1353 (void) strcpy(apdup
, ap_id
);
1356 * Separate into base and dynamic components
1358 if ((ret
= split_apid(apdup
, &dyncomp
, errstring
)) != CFGA_OK
) {
1363 * No upper limit on version
1365 lib_loc_p
->vers_req
.v_max
= CFGA_HSL_VERS
;
1366 if (dyncomp
!= NULL
) {
1368 * We need atleast version 2 of the plug-in library
1369 * interface since the ap_id has a dynamic component.
1372 lib_loc_p
->vers_req
.v_min
= CFGA_HSL_V2
;
1374 lib_loc_p
->vers_req
.v_min
= CFGA_HSL_V1
;
1378 * If the ap_id is a devlink in CFGA_DEV_DIR, follow link
1379 * to get the physical ap_id.
1381 if ((type
= find_arg_type(apdup
)) == LOGICAL_LINK_AP
) {
1382 (void) snprintf(lib_loc_p
->ap_base
, sizeof (lib_loc_p
->ap_base
),
1383 "%s%s", CFGA_DEV_DIR SLASH
, apdup
);
1386 path
[sizeof (path
) - 1] = '\0';
1387 if (type
== LOGICAL_LINK_AP
&& realpath(lib_loc_p
->ap_base
, path
)
1389 (void) snprintf(lib_loc_p
->ap_base
, sizeof (lib_loc_p
->ap_base
),
1392 (void) snprintf(lib_loc_p
->ap_base
, sizeof (lib_loc_p
->ap_base
),
1398 * find and load the library
1399 * The base component of the ap_id is used to locate the plug-in
1401 * NOTE that PCIE/PCISHPC connectors also have minor nodes &
1402 * dev links created for now.
1404 if ((type
= find_arg_type(lib_loc_p
->ap_base
)) == PHYSICAL_AP
) {
1406 * physical ap_id: Use ap_base as root for tree walk
1407 * A link based apid (logical) will resolve to a physical
1410 ret
= find_ap_common(lib_loc_p
, lib_loc_p
->ap_base
,
1411 check_ap_phys
, check_ap_phys_hp
, errstring
);
1412 } else if ((type
== LOGICAL_DRV_AP
) ||
1413 (type
== AP_TYPE
&& dyncomp
== NULL
)) {
1415 * logical ap_id or ap_type: Use "/" as root for tree walk
1416 * Note: an aptype cannot have a dynamic component
1418 ret
= find_ap_common(lib_loc_p
, "/", check_ap
,
1419 check_ap_hp
, errstring
);
1421 ret
= CFGA_APID_NOEXIST
;
1424 if (ret
== CFGA_OK
) {
1427 * variables used by assert() only which is disabled
1428 * by defining NDEBUG (see top of this file)
1432 libp
= lib_loc_p
->libp
;
1435 assert(strcmp(libp
->libpath
, lib_loc_p
->pathname
) == 0);
1436 assert(VALID_HSL_VERS(libp
->plugin_vers
));
1439 * If a dynamic component was present, v1 plug-ins are not
1442 assert(dyncomp
== NULL
|| libp
->plugin_vers
>= CFGA_HSL_V2
);
1445 * ap_physical is passed to plugins as their ap_id argument.
1446 * Append dynamic component if any.
1448 append_dyn(lib_loc_p
->ap_physical
, dyncomp
,
1449 sizeof (lib_loc_p
->ap_physical
));
1453 lib_loc_p
->vers_req
.v_min
= INVALID_VERSION
;
1454 lib_loc_p
->vers_req
.v_max
= INVALID_VERSION
;
1455 *lib_loc_p
->ap_base
= '\0';
1461 if (ret
!= CFGA_OK
) {
1462 lib_loc_p
->libp
= NULL
;
1465 assert(ret
!= CFGA_OK
|| lib_loc_p
->libp
!= NULL
);
1470 /* load_lib - load library for non-SHP attachment point node */
1475 lib_loc_t
*libloc_p
)
1477 return (load_lib_impl(node
, minor
, NULL
, libloc_p
));
1480 /* load_lib_hp - load library for SHP attachment point node */
1485 lib_loc_t
*libloc_p
)
1487 return (load_lib_impl(node
, NULL
, hp
, libloc_p
));
1491 * load_lib_impl - Given a library pathname, create a entry for it
1492 * in the library list, * if one does not already exist, and read
1493 * lock it to keep it there.
1500 lib_loc_t
*libloc_p
)
1502 plugin_lib_t
*libp
, *list_libp
;
1506 if (minor
!= DI_MINOR_NIL
&& hp
!= DI_HP_NIL
)
1507 return (CFGA_LIB_ERROR
);
1509 if (minor
!= DI_MINOR_NIL
)
1510 name
= di_minor_name(minor
);
1512 name
= di_hp_name(hp
);
1515 * lock the library list
1517 (void) mutex_lock(&plugin_list_lock
);
1520 * see if lib exist in list, if not, allocate a new one
1522 list_libp
= lib_in_list(libloc_p
->pathname
);
1523 if (list_libp
!= NULL
) {
1524 hold_lib(list_libp
);
1525 (void) mutex_unlock(&plugin_list_lock
);
1527 /* fill in logical and physical name in libloc_p */
1528 libloc_p
->libp
= libp
= list_libp
;
1529 if (minor
!= DI_MINOR_NIL
) {
1530 if (libp
->vers_ops
->mklog(node
, minor
, libp
, libloc_p
)
1532 rele_lib(list_libp
);
1533 return (CFGA_LIB_ERROR
);
1536 if (mklog_hp(node
, hp
, libp
, libloc_p
) != CFGA_OK
) {
1537 rele_lib(list_libp
);
1538 return (CFGA_LIB_ERROR
);
1542 devfs_path
= di_devfs_path(node
);
1543 (void) snprintf(libloc_p
->ap_physical
, MAXPATHLEN
, "%s%s:%s",
1544 DEVICES_DIR
, devfs_path
, name
);
1545 di_devfs_path_free(devfs_path
);
1550 /* allocate a new plugin_lib_t structure */
1551 libp
= config_calloc_check(1, sizeof (plugin_lib_t
), NULL
);
1553 (void) mutex_unlock(&plugin_list_lock
);
1554 return (CFGA_LIB_ERROR
);
1557 (void) snprintf(libp
->libpath
, sizeof (libp
->libpath
), "%s",
1558 libloc_p
->pathname
);
1561 * ensure that the lib is open and linked in
1563 libp
->handle
= dlopen(libp
->libpath
, RTLD_NOW
);
1564 if (libp
->handle
== NULL
) {
1565 (void) mutex_unlock(&plugin_list_lock
);
1567 return (CFGA_NO_LIB
);
1570 if (minor
!= DI_MINOR_NIL
) {
1571 if (resolve_lib_ref(libp
, libloc_p
) != CFGA_OK
||
1572 libp
->vers_ops
->mklog(node
, minor
, libp
, libloc_p
)
1574 (void) mutex_unlock(&plugin_list_lock
);
1575 (void) dlclose(libp
->handle
);
1577 return (CFGA_NO_LIB
);
1580 if (resolve_lib_ref(libp
, libloc_p
) != CFGA_OK
||
1581 mklog_hp(node
, hp
, libp
, libloc_p
) != CFGA_OK
) {
1582 (void) mutex_unlock(&plugin_list_lock
);
1583 (void) dlclose(libp
->handle
);
1585 return (CFGA_NO_LIB
);
1590 * link in new entry to the end of list
1592 list_libp
= &plugin_list
;
1593 while (list_libp
->next
!= NULL
)
1594 list_libp
= list_libp
->next
;
1595 libp
->next
= list_libp
->next
;
1596 list_libp
->next
= libp
;
1598 /* Initialize refcnt to 1 */
1600 (void) mutex_init(&libp
->lock
, USYNC_THREAD
, NULL
);
1602 (void) mutex_unlock(&plugin_list_lock
);
1605 * record libp and physical node name in the libloc struct
1607 libloc_p
->libp
= libp
;
1608 devfs_path
= di_devfs_path(node
);
1609 (void) snprintf(libloc_p
->ap_physical
, MAXPATHLEN
, "%s%s:%s",
1610 DEVICES_DIR
, devfs_path
, name
);
1611 di_devfs_path_free(devfs_path
);
1617 #define NUM_LIB_NAMES 2
1620 * find_lib - find library for non-SHP attachment point node
1626 lib_loc_t
*libloc_p
)
1628 char name
[NUM_LIB_NAMES
][MAXPATHLEN
];
1629 char *class = NULL
, *drv
= NULL
;
1633 /* Make sure pathname and class is null if we fail */
1634 *libloc_p
->ap_class
= *libloc_p
->pathname
= '\0';
1637 * Initialize possible library tags.
1640 drv
= di_driver_name(node
);
1641 class = get_class(minor
);
1643 if (drv
== NULL
|| class == NULL
) {
1644 return (CFGA_LIB_ERROR
);
1648 (void) snprintf(&name
[i
++][0], sizeof (name
[0]), "%s", drv
);
1649 (void) snprintf(&name
[i
++][0], sizeof (name
[0]), "%s", class);
1652 * Cycle through the array of names to find the library.
1654 for (i
= 0; i
< NUM_LIB_NAMES
; i
++) {
1656 /* Attachment points may not have a class (i.e. are generic) */
1657 if (name
[i
][0] == '\0') {
1661 if (find_lib_impl(name
[i
], libloc_p
) == CFGA_OK
)
1665 return (CFGA_NO_LIB
);
1669 /* Record class name (if any) */
1670 (void) snprintf(libloc_p
->ap_class
, sizeof (libloc_p
->ap_class
), "%s",
1677 * find_lib_hp - find library for SHP attachment point
1684 lib_loc_t
*libloc_p
)
1686 char name
[MAXPATHLEN
];
1690 /* Make sure pathname and class is null if we fail */
1691 *libloc_p
->ap_class
= *libloc_p
->pathname
= '\0';
1694 * Initialize possible library tags.
1696 * Only support PCI class for now, this will need to be
1697 * changed as other plugins are migrated to SHP plugin.
1702 * No type check for now as PCI is the only class SHP plugin
1703 * supports. In the future we'll need to enable the type check
1704 * and set class accordingly, when non PCI plugins are migrated
1705 * to SHP. In that case we'll probably need to add an additional
1706 * interface between libcfgadm and the plugins, and SHP plugin will
1707 * implement this interface which will translate the bus specific
1708 * strings to standard classes that libcfgadm can recognize, for
1709 * all the buses it supports, e.g. for pci/pcie it will translate
1710 * PCIE_NATIVE_HP_TYPE to string "pci". We'll also need to bump up
1711 * SHP plugin version to 3 to use the new interface.
1713 class = di_hp_type(hp
);
1714 if ((strcmp(class, PCIE_NATIVE_HP_TYPE
) == 0) ||
1715 (strcmp(class, PCIE_ACPI_HP_TYPE
) == 0) ||
1716 (strcmp(class, PCIE_PCI_HP_TYPE
) == 0)) {
1722 (void) snprintf(&name
[0], sizeof (name
), "%s", "shp");
1724 if (find_lib_impl(name
, libloc_p
) == CFGA_OK
)
1727 return (CFGA_NO_LIB
);
1731 /* Record class name (if any) */
1732 (void) snprintf(libloc_p
->ap_class
, sizeof (libloc_p
->ap_class
), "%s",
1739 * find_lib_impl - Given an attachment point node find it's library
1744 lib_loc_t
*libloc_p
)
1746 char lib
[MAXPATHLEN
];
1747 struct stat lib_stat
;
1748 void *dlhandle
= NULL
;
1749 static char plat_name
[SYSINFO_LENGTH
];
1750 static char machine_name
[SYSINFO_LENGTH
];
1751 static char arch_name
[SYSINFO_LENGTH
];
1754 * Initialize machine name and arch name
1756 if (strncmp("", machine_name
, MAXPATHLEN
) == 0) {
1757 if (sysinfo(SI_PLATFORM
, plat_name
, SYSINFO_LENGTH
) == -1) {
1758 return (CFGA_ERROR
);
1760 if (sysinfo(SI_ARCHITECTURE
, arch_name
, SYSINFO_LENGTH
) == -1) {
1761 return (CFGA_ERROR
);
1763 if (sysinfo(SI_MACHINE
, machine_name
, SYSINFO_LENGTH
) == -1) {
1764 return (CFGA_ERROR
);
1769 * Try path based upon platform name
1771 (void) snprintf(lib
, sizeof (lib
), "%s%s%s%s%s",
1772 LIB_PATH_BASE1
, plat_name
, LIB_PATH_MIDDLE
,
1773 name
, LIB_PATH_TAIL
);
1775 if (stat(lib
, &lib_stat
) == 0) {
1776 /* file exists, is it a lib */
1777 dlhandle
= dlopen(lib
, RTLD_LAZY
);
1778 if (dlhandle
!= NULL
) {
1784 * Try path based upon machine name
1786 (void) snprintf(lib
, sizeof (lib
), "%s%s%s%s%s",
1787 LIB_PATH_BASE1
, machine_name
, LIB_PATH_MIDDLE
,
1788 name
, LIB_PATH_TAIL
);
1791 if (stat(lib
, &lib_stat
) == 0) {
1792 /* file exists, is it a lib */
1793 dlhandle
= dlopen(lib
, RTLD_LAZY
);
1794 if (dlhandle
!= NULL
) {
1800 * Try path based upon arch name
1802 (void) snprintf(lib
, sizeof (lib
), "%s%s%s%s%s",
1803 LIB_PATH_BASE1
, arch_name
, LIB_PATH_MIDDLE
,
1804 name
, LIB_PATH_TAIL
);
1806 if (stat(lib
, &lib_stat
) == 0) {
1807 /* file exists, is it a lib */
1808 dlhandle
= dlopen(lib
, RTLD_LAZY
);
1809 if (dlhandle
!= NULL
) {
1816 * Try generic location
1818 (void) snprintf(lib
, sizeof (lib
), "%s%s%s%s",
1819 LIB_PATH_BASE2
, LIB_PATH_MIDDLE
, name
, LIB_PATH_TAIL
);
1821 if (stat(lib
, &lib_stat
) == 0) {
1822 /* file exists, is it a lib */
1823 dlhandle
= dlopen(lib
, RTLD_LAZY
);
1824 if (dlhandle
!= NULL
) {
1829 return (CFGA_NO_LIB
);
1833 (void) snprintf(libloc_p
->pathname
, sizeof (libloc_p
->pathname
), "%s",
1836 (void) dlclose(dlhandle
);
1842 lookup_cache(lib_loc_t
*libloc_p
)
1845 (void) mutex_lock(&lib_cache_lock
);
1848 if (strcmp(entry
->lc_ap_id
, libloc_p
->ap_base
) == 0) {
1849 plugin_lib_t
*libp
= entry
->lc_libp
;
1850 libloc_p
->libp
= libp
;
1852 (void) strcpy(libloc_p
->pathname
, libp
->libpath
);
1853 (void) strcpy(libloc_p
->ap_physical
,
1854 entry
->lc_ap_physical
);
1855 (void) strcpy(libloc_p
->ap_logical
,
1856 entry
->lc_ap_logical
);
1857 (void) mutex_unlock(&lib_cache_lock
);
1860 entry
= entry
->lc_next
;
1862 (void) mutex_unlock(&lib_cache_lock
);
1864 return (CFGA_ERROR
);
1868 update_cache(lib_loc_t
*libloc_p
)
1871 entry
= config_calloc_check(1, sizeof (lib_cache_t
), NULL
);
1875 entry
->lc_ap_id
= strdup(libloc_p
->ap_base
);
1876 entry
->lc_ap_physical
= strdup(libloc_p
->ap_physical
);
1877 entry
->lc_ap_logical
= strdup(libloc_p
->ap_logical
);
1878 if ((entry
->lc_ap_id
== NULL
) || (entry
->lc_ap_physical
== NULL
) ||
1879 (entry
->lc_ap_logical
== NULL
)) {
1880 free(entry
->lc_ap_id
);
1881 free(entry
->lc_ap_physical
);
1882 free(entry
->lc_ap_logical
);
1887 (void) mutex_lock(&lib_cache_lock
);
1888 entry
->lc_libp
= libloc_p
->libp
;
1889 entry
->lc_next
= lib_cache
;
1891 hold_lib(entry
->lc_libp
); /* prevent stale cache */
1892 (void) mutex_unlock(&lib_cache_lock
);
1898 lib_cache_t
*entry
, *next
;
1899 (void) mutex_lock(&lib_cache_lock
);
1902 next
= entry
->lc_next
;
1903 rele_lib(entry
->lc_libp
);
1904 free(entry
->lc_ap_id
);
1905 free(entry
->lc_ap_physical
);
1906 free(entry
->lc_ap_logical
);
1910 (void) mutex_unlock(&lib_cache_lock
);
1914 * find_ap_common - locate a particular attachment point
1918 lib_loc_t
*libloc_p
,
1919 const char *physpath
,
1920 int (*fcn
)(di_node_t node
, di_minor_t minor
, void *arg
),
1921 int (*fcn_hp
)(di_node_t node
, di_hp_t hp
, void *arg
),
1924 di_node_t rnode
, wnode
;
1928 if (lookup_cache(libloc_p
) == CFGA_OK
)
1931 if ((rpath
= config_calloc_check(1, strlen(physpath
) + 1,
1932 errstring
)) == NULL
) {
1933 return (CFGA_LIB_ERROR
);
1936 (void) strcpy(rpath
, physpath
);
1938 /* Remove devices prefix (if any) */
1939 len
= strlen(DEVICES_DIR
);
1940 if (strncmp(rpath
, DEVICES_DIR SLASH
, len
+ strlen(SLASH
)) == 0) {
1941 (void) memmove(rpath
, rpath
+ len
,
1942 strlen(rpath
+ len
) + 1);
1945 /* Remove dynamic component if any */
1946 if ((cp
= GET_DYN(rpath
)) != NULL
) {
1950 /* Remove minor name (if any) */
1951 if ((cp
= strrchr(rpath
, ':')) != NULL
) {
1956 * begin walk of device tree
1958 * Since we create minor nodes & dev links for both all PCI/PCIE
1959 * connectors, but only create hp nodes for PCIE/PCISHPC connectors
1960 * of the new framework, we should first match with hp nodes. If
1961 * the ap_id refers to a PCIE/PCISHPC connector, we'll be able to
1964 rnode
= di_init("/", DINFOSUBTREE
| DINFOHP
);
1966 wnode
= di_lookup_node(rnode
, rpath
);
1968 wnode
= DI_NODE_NIL
;
1970 if (wnode
== DI_NODE_NIL
) {
1971 if (rnode
== DI_NODE_NIL
) {
1973 config_err(errno
, DI_INIT_FAILED
, errstring
);
1974 return (CFGA_LIB_ERROR
);
1977 * di_lookup_node() may fail, either because the
1978 * ap_id does not exist, or because the ap_id refers
1979 * to a legacy PCI slot, thus we'll not able to
1980 * find node using DINFOHP, try to see if we can
1981 * find one using DINFOCACHE.
1988 libloc_p
->libp
= NULL
;
1989 libloc_p
->status
= CFGA_APID_NOEXIST
;
1991 (void) di_walk_hp(wnode
, NULL
, DI_HP_CONNECTOR
,
1997 * Failed to find a matching hp node, try minor node.
1999 if (libloc_p
->libp
== NULL
) {
2001 rnode
= di_init("/", DINFOCACHE
);
2003 wnode
= di_lookup_node(rnode
, rpath
);
2005 wnode
= DI_NODE_NIL
;
2007 if (wnode
== DI_NODE_NIL
) {
2008 if (rnode
== DI_NODE_NIL
) {
2010 config_err(errno
, DI_INIT_FAILED
, errstring
);
2011 return (CFGA_LIB_ERROR
);
2014 * di_lookup_node() may fail, because the
2015 * ap_id does not exist.
2019 return (CFGA_APID_NOEXIST
);
2023 libloc_p
->libp
= NULL
;
2024 libloc_p
->status
= CFGA_APID_NOEXIST
;
2026 (void) di_walk_minor(wnode
, "ddi_ctl:attachment_point",
2027 DI_CHECK_ALIAS
|DI_CHECK_INTERNAL_PATH
,
2035 if (libloc_p
->libp
!= NULL
) {
2036 update_cache(libloc_p
);
2039 return (libloc_p
->status
);
2044 * check_ap - called for each non-SHP attachment point found
2052 return (check_ap_impl(node
, minor
, NULL
, arg
));
2056 * check_ap_hp - called for each SHP attachment point found
2064 return (check_ap_impl(node
, NULL
, hp
, arg
));
2068 * check_ap_impl - called for each attachment point found
2070 * This is used in cases where a particular attachment point
2071 * or type of attachment point is specified via a logical name or ap_type.
2072 * Not used for physical names or in the list case with no
2083 char aptype
[MAXPATHLEN
];
2084 char *recep_id
= NULL
;
2087 char inst
[MAXPATHLEN
];
2088 char inst2
[MAXPATHLEN
];
2089 lib_loc_t
*libloc_p
;
2090 int comparison_test
;
2092 cfga_ap_types_t type
;
2094 if (minor
!= DI_MINOR_NIL
&& hp
!= DI_HP_NIL
)
2095 return (DI_WALK_CONTINUE
);
2097 libloc_p
= (lib_loc_t
*)arg
;
2099 (void) snprintf(aptype
, sizeof (aptype
), "%s", libloc_p
->ap_base
);
2102 * This routime handles only aptypes and driver based logical apids.
2104 type
= find_arg_type(aptype
);
2105 if (type
== LOGICAL_DRV_AP
) {
2106 cp
= strchr(aptype
, ':');
2110 while (isdigit(*cp
) && cp
!= aptype
)
2114 (void) snprintf(inst
, sizeof (inst
), "%s", cp
);
2117 } else if (type
!= AP_TYPE
) {
2118 libloc_p
->status
= CFGA_APID_NOEXIST
;
2119 return (DI_WALK_CONTINUE
);
2122 if (minor
!= DI_MINOR_NIL
)
2123 node_minor
= di_minor_name(minor
);
2125 node_minor
= di_hp_name(hp
);
2127 drv_name
= di_driver_name(node
);
2128 instance
= di_instance(node
);
2130 if (node_minor
== NULL
|| drv_name
== NULL
|| instance
== -1) {
2131 libloc_p
->status
= CFGA_APID_NOEXIST
;
2132 return (DI_WALK_CONTINUE
);
2135 (void) sprintf(inst2
, "%d", instance
);
2138 * If the base matches driver and instance try and find a lib for it,
2139 * then load it. On any failure we continue the walk.
2141 * driver based logical ap_ids are derived from driver name + instance.
2142 * Ap_types are just partial driver names.
2146 comparison_test
= 0;
2147 if (type
== AP_TYPE
) {
2148 if (strncmp(aptype
, drv_name
, strlen(aptype
)) == 0) {
2149 comparison_test
= 1;
2152 if (strcmp(aptype
, drv_name
) == 0 &&
2153 strcmp(recep_id
, node_minor
) == 0 &&
2154 strcmp(inst
, inst2
) == 0) {
2155 comparison_test
= 1;
2159 if (comparison_test
) {
2161 * save the correct type of error so user does not get confused
2163 if (minor
!= DI_MINOR_NIL
) {
2164 if (find_lib(node
, minor
, libloc_p
) != CFGA_OK
) {
2165 libloc_p
->status
= CFGA_NO_LIB
;
2166 return (DI_WALK_CONTINUE
);
2168 if (load_lib(node
, minor
, libloc_p
) != CFGA_OK
) {
2169 libloc_p
->status
= CFGA_LIB_ERROR
;
2170 return (DI_WALK_CONTINUE
);
2173 if (find_lib_hp(node
, hp
, libloc_p
) != CFGA_OK
) {
2174 libloc_p
->status
= CFGA_NO_LIB
;
2175 return (DI_WALK_CONTINUE
);
2177 if (load_lib_hp(node
, hp
, libloc_p
) != CFGA_OK
) {
2178 libloc_p
->status
= CFGA_LIB_ERROR
;
2179 return (DI_WALK_CONTINUE
);
2182 libloc_p
->status
= CFGA_OK
;
2183 return (DI_WALK_TERMINATE
);
2185 libloc_p
->status
= CFGA_APID_NOEXIST
;
2186 return (DI_WALK_CONTINUE
);
2192 * check_ap_phys - called for each non-SHP attachment point found
2200 return (check_ap_phys_impl(node
, minor
, DI_HP_NIL
, arg
));
2204 * check_ap_phys_hp - called for each SHP attachment point found
2212 return (check_ap_phys_impl(node
, DI_HP_NIL
, hp
, arg
));
2216 * check_ap_phys_impl - called for each attachment point found
2218 * This is used in cases where a particular attachment point
2219 * is specified via a physical name. If the name matches then
2220 * we try and find and load the library for it.
2229 lib_loc_t
*libloc_p
;
2230 char phys_name
[MAXPATHLEN
];
2234 if (minor
!= DI_MINOR_NIL
&& hp
!= DI_HP_NIL
)
2235 return (DI_WALK_CONTINUE
);
2237 libloc_p
= (lib_loc_t
*)arg
;
2238 devfs_path
= di_devfs_path(node
);
2239 if (minor
!= DI_MINOR_NIL
)
2240 minor_name
= di_minor_name(minor
);
2242 minor_name
= di_hp_name(hp
);
2244 if (devfs_path
== NULL
|| minor_name
== NULL
) {
2245 libloc_p
->status
= CFGA_APID_NOEXIST
;
2246 return (DI_WALK_CONTINUE
);
2249 (void) snprintf(phys_name
, sizeof (phys_name
), "%s%s:%s",
2250 DEVICES_DIR
, devfs_path
, minor_name
);
2252 di_devfs_path_free(devfs_path
);
2254 if (strcmp(phys_name
, libloc_p
->ap_base
) == 0) {
2255 if (minor
!= DI_MINOR_NIL
) {
2256 if (find_lib(node
, minor
, libloc_p
) != CFGA_OK
) {
2257 libloc_p
->status
= CFGA_NO_LIB
;
2258 return (DI_WALK_CONTINUE
);
2260 if (load_lib(node
, minor
, libloc_p
) != CFGA_OK
) {
2261 libloc_p
->status
= CFGA_LIB_ERROR
;
2262 return (DI_WALK_CONTINUE
);
2265 if (find_lib_hp(node
, hp
, libloc_p
) != CFGA_OK
) {
2266 libloc_p
->status
= CFGA_NO_LIB
;
2267 return (DI_WALK_CONTINUE
);
2269 if (load_lib_hp(node
, hp
, libloc_p
) != CFGA_OK
) {
2270 libloc_p
->status
= CFGA_LIB_ERROR
;
2271 return (DI_WALK_CONTINUE
);
2275 libloc_p
->status
= CFGA_OK
;
2276 return (DI_WALK_TERMINATE
);
2278 libloc_p
->status
= CFGA_APID_NOEXIST
;
2279 return (DI_WALK_CONTINUE
);
2286 * See if library, as specified by the full pathname and controller
2287 * instance number is already represented in the plugin library list.
2288 * If the instance number is -1 it is ignored.
2290 static plugin_lib_t
*
2291 lib_in_list(char *libpath
)
2293 plugin_lib_t
*libp
= NULL
;
2295 for (libp
= plugin_list
.next
; libp
!= NULL
; libp
= libp
->next
) {
2296 if (strncmp(libpath
, libp
->libpath
, MAXPATHLEN
) == 0) {
2307 * Coalesce stat and list data into single array
2311 cfga_list_data_t
**ap_id_list
,
2313 list_stat_t
*lstatp
)
2316 stat_data_list_t
*slp
;
2317 cfga_list_data_t
*cldp
;
2319 cfga_err_t rc
= CFGA_OK
;
2322 assert(*lstatp
->countp
>= 0);
2324 if (*lstatp
->countp
== 0) {
2331 * allocate the array
2333 if ((cldp
= config_calloc_check(*lstatp
->countp
,
2334 sizeof (cfga_list_data_t
), lstatp
->errstr
)) == NULL
) {
2335 rc
= CFGA_LIB_ERROR
;
2340 * copy all the stat elements (if any) into the array
2343 for (i
= 0; slp
!= NULL
; i
++) {
2344 if (i
>= *lstatp
->countp
) {
2345 rc
= CFGA_LIB_ERROR
;
2348 stat_to_list(&cldp
[i
], &slp
->stat_data
);
2353 * copy all the list elements (if any) into the array
2356 for (; alp
!= NULL
; ) {
2357 if (i
+ alp
->nelem
> *lstatp
->countp
) {
2358 rc
= CFGA_LIB_ERROR
;
2362 for (j
= 0; j
< alp
->nelem
; i
++, j
++) {
2363 cldp
[i
] = alp
->array
[j
];
2368 if (i
!= *lstatp
->countp
) {
2369 rc
= CFGA_LIB_ERROR
;
2380 if (rc
== CFGA_OK
) {
2382 *nlistp
= *lstatp
->countp
;
2392 * The caller of this routine may supply a buffer through
2393 * ap_id_list for returning data. Otherwise, this routine allocates the
2397 realloc_data(cfga_stat_data_t
**ap_id_list
, int *nlistp
, list_stat_t
*lstatp
)
2400 stat_data_list_t
*slp
;
2401 cfga_stat_data_t
*csdp
, *buf
;
2405 assert(*lstatp
->countp
>= 0);
2407 if (*lstatp
->countp
== 0) {
2414 * allocate the array if caller does not supply one.
2416 if (*ap_id_list
== NULL
) {
2417 if ((buf
= config_calloc_check(*lstatp
->countp
,
2418 sizeof (cfga_stat_data_t
), lstatp
->errstr
)) == NULL
) {
2419 rc
= CFGA_LIB_ERROR
;
2427 * copy the stat elements into the array
2431 for (i
= 0; slp
!= NULL
; i
++) {
2432 if (i
>= *lstatp
->countp
) {
2433 rc
= CFGA_LIB_ERROR
;
2436 *csdp
++ = slp
->stat_data
;
2443 if (rc
== CFGA_OK
) {
2444 *nlistp
= *lstatp
->countp
;
2448 * Free buffer only if we allocated it.
2450 if (*ap_id_list
== NULL
) {
2456 assert(lstatp
->al
== NULL
);
2464 * list_common - walk the device tree and stat all attachment points.
2467 list_common(list_stat_t
*lstatp
, const char *class)
2470 char nodetype
[MAXPATHLEN
];
2471 const char *l_class
, *l_sep
;
2474 * May walk a subset of all attachment points in the device tree if
2475 * a class is specified
2477 if (class != NULL
) {
2481 l_sep
= l_class
= "";
2484 (void) snprintf(nodetype
, sizeof (nodetype
), "%s%s%s",
2485 DDI_NT_ATTACHMENT_POINT
, l_sep
, l_class
);
2490 if ((rnode
= di_init("/", DINFOSUBTREE
| DINFOHP
)) == DI_NODE_NIL
) {
2491 config_err(errno
, DI_INIT_FAILED
, lstatp
->errstr
);
2492 return (CFGA_LIB_ERROR
);
2494 /* No need to filter on class for now */
2495 (void) di_walk_hp(rnode
, NULL
, DI_HP_CONNECTOR
,
2496 lstatp
, do_list_common_hp
);
2501 * Walk all minor nodes
2502 * but exclude PCIE/PCIESHPC connectors which have been walked above.
2504 if ((rnode
= di_init("/", DINFOCACHE
)) == DI_NODE_NIL
) {
2505 config_err(errno
, DI_INIT_FAILED
, lstatp
->errstr
);
2506 return (CFGA_LIB_ERROR
);
2508 (void) di_walk_minor(rnode
, nodetype
,
2509 DI_CHECK_ALIAS
|DI_CHECK_INTERNAL_PATH
, lstatp
, do_list_common
);
2513 if (lstatp
->shp_errstr
!= NULL
) {
2514 *(lstatp
->errstr
) = strdup(lstatp
->shp_errstr
);
2515 free(lstatp
->shp_errstr
);
2516 lstatp
->shp_errstr
= NULL
;
2523 config_err(int errnum
, int err_type
, char **errstring
)
2525 char *p
= NULL
, *q
= NULL
;
2526 char *syserr
= NULL
;
2527 char syserr_num
[20];
2531 * If errstring is null it means user in not interested in getting
2532 * error status. So we don't do all the work
2534 if (errstring
== NULL
) {
2539 syserr
= strerror(errnum
);
2540 if (syserr
== NULL
) {
2541 (void) sprintf(syserr_num
, "errno=%d", errnum
);
2542 syserr
= syserr_num
;
2547 q
= dgettext(TEXT_DOMAIN
, err_strings
[err_type
]);
2550 if (syserr
!= NULL
) {
2551 len
+= strlen(err_sep
) + strlen(syserr
);
2554 p
= malloc(len
+ 1);
2560 (void) strcpy(p
, q
);
2561 if (syserr
!= NULL
) {
2562 (void) strcat(p
, err_sep
);
2563 (void) strcat(p
, syserr
);
2570 * do_list_common - list non-SHP attachment point
2573 do_list_common(di_node_t node
, di_minor_t minor
, void *arg
)
2580 if ((minor_name
= di_minor_name(minor
)) == NULL
)
2581 return (DI_WALK_CONTINUE
);
2584 * since PCIE/PCIHSHPC connectors have both hp nodes and minor nodes
2585 * created for now, we need to specifically exclude these connectors
2586 * during walking minor nodes.
2588 if ((phys_path
= di_devfs_path(node
)) == NULL
)
2589 return (DI_WALK_CONTINUE
);
2590 rnode
= di_init(phys_path
, DINFOSUBTREE
| DINFOHP
);
2591 di_devfs_path_free(phys_path
);
2592 if (rnode
== DI_NODE_NIL
)
2593 return (DI_WALK_CONTINUE
);
2595 for (hp
= DI_HP_NIL
; (hp
= di_hp_next(rnode
, hp
)) != DI_HP_NIL
; ) {
2596 if (strcmp(di_hp_name(hp
), minor_name
) == 0) {
2598 return (DI_WALK_CONTINUE
);
2604 return (do_list_common_impl(node
, minor
, NULL
, arg
));
2608 * do_list_common_hp - list SHP attachment point
2616 return (do_list_common_impl(node
, NULL
, hp
, arg
));
2620 * do_list_common_impl - Routine to list attachment point as part of
2621 * a config_list opertion. Used by both v1 and v2 interfaces.
2622 * This is somewhat similar to config_get_lib() and its helper routines
2623 * except that the ap_ids are always physical and don't have dynamic
2627 do_list_common_impl(
2635 list_stat_t
*lstatp
= NULL
;
2636 cfga_err_t ret
= CFGA_ERROR
;
2638 if (minor
!= DI_MINOR_NIL
&& hp
!= DI_HP_NIL
)
2639 return (DI_WALK_CONTINUE
);
2641 lstatp
= (list_stat_t
*)arg
;
2643 lib_loc
.libp
= NULL
;
2645 * try and find a lib for this node
2647 if (minor
!= DI_MINOR_NIL
) {
2648 ret
= find_lib(node
, minor
, &lib_loc
);
2650 ret
= find_lib_hp(node
, hp
, &lib_loc
);
2652 if (ret
!= CFGA_OK
) {
2653 return (DI_WALK_CONTINUE
);
2657 * Load all plugins. We will check compatibility later in this
2660 lib_loc
.vers_req
.v_min
= CFGA_HSL_V1
;
2661 lib_loc
.vers_req
.v_max
= CFGA_HSL_VERS
;
2663 if (minor
!= DI_MINOR_NIL
) {
2664 ret
= load_lib(node
, minor
, &lib_loc
);
2666 ret
= load_lib_hp(node
, hp
, &lib_loc
);
2668 if (ret
!= CFGA_OK
) {
2669 return (DI_WALK_CONTINUE
);
2672 libp
= lib_loc
.libp
;
2673 assert(libp
!= NULL
);
2676 * Note: For list type routines (list all attachment points in
2677 * device tree) we don't pass errstring to the plugin, nor do we
2678 * stop the walk if an error occurs in the plugin.
2680 if (compat_plugin(&lstatp
->use_vers
, libp
->plugin_vers
)) {
2681 if (minor
!= DI_MINOR_NIL
) {
2682 (void) libp
->vers_ops
->stat_plugin(lstatp
,
2686 * If the underlying hotplug daemon is not enabled,
2687 * the SHP attach points will not be shown, this
2688 * could confuse the uesrs. We specifically pass the
2689 * errstring to SHP plugin so that it can set the
2690 * errstring accordingly in this case, giving users
2693 ret
= libp
->vers_ops
->stat_plugin(lstatp
,
2694 &lib_loc
, lstatp
->errstr
);
2695 if (ret
== CFGA_NOTSUPP
&& *(lstatp
->errstr
) != NULL
) {
2696 if (lstatp
->shp_errstr
== NULL
) {
2697 lstatp
->shp_errstr
=
2698 strdup(*(lstatp
->errstr
));
2702 if (*(lstatp
->errstr
) != NULL
) {
2703 free(*(lstatp
->errstr
));
2704 *(lstatp
->errstr
) = NULL
;
2710 return (DI_WALK_CONTINUE
);
2714 * stat_common - stat a user specified set of attachment points.
2719 char *const *ap_ids
,
2721 list_stat_t
*lstatp
)
2726 cfga_err_t rc
= CFGA_OK
;
2730 * operate on each ap_id
2732 for (i
= 0; i
< num_ap_ids
; i
++) {
2734 if ((rc
= config_get_lib(ap_ids
[i
], &libloc
,
2735 lstatp
->errstr
)) != CFGA_OK
) {
2738 assert(libloc
.libp
!= NULL
);
2742 * do pre-filtering if requested
2744 if (class != NULL
&& strcmp(libloc
.ap_class
, class)) {
2750 * Unlike list type routines, while stat'ing specific
2751 * attachment points we pass errstring to the plugins
2752 * and halt if an error occurs in the plugin.
2754 rc
= libp
->vers_ops
->stat_plugin(lstatp
, &libloc
,
2757 if (rc
!= CFGA_OK
) {
2762 if (rc
!= CFGA_OK
) {
2770 null_stat_plugin(list_stat_t
*lstatp
, lib_loc_t
*libloc_p
, char **errstring
)
2776 * Pass errstring as a separate argument. Some higher level routines need
2780 stat_plugin_v1(list_stat_t
*lstatp
, lib_loc_t
*libloc_p
, char **errstring
)
2782 stat_data_list_t
*slp
, *slp2
= NULL
;
2786 * allocate stat data buffer and list element
2788 if ((slp
= config_calloc_check(1, sizeof (stat_data_list_t
),
2789 errstring
)) == NULL
) {
2790 return (CFGA_LIB_ERROR
);
2797 if ((rc
= (*(libloc_p
->libp
->cfga_stat_p
))(libloc_p
->ap_physical
,
2798 &slp
->stat_data
, lstatp
->opts
, errstring
)) != CFGA_OK
) {
2805 * Set up the logical and physical id's.
2806 * For v1 interfaces, the generic library (libcfgadm) creates the
2807 * ap_ids. mklog() is assumed to have been called in
2808 * the caller of this routine.
2810 (void) snprintf(slp
->stat_data
.ap_log_id
, CFGA_AP_LOG_ID_LEN
, "%s",
2811 libloc_p
->ap_logical
);
2813 (void) snprintf(slp
->stat_data
.ap_phys_id
, CFGA_AP_PHYS_ID_LEN
, "%s",
2814 libloc_p
->ap_physical
);
2819 if ((slp2
= lstatp
->sdl
) == NULL
) {
2822 while (slp2
->next
!= NULL
)
2828 (*lstatp
->countp
)++;
2834 stat_plugin_v2(list_stat_t
*lstatp
, lib_loc_t
*libloc_p
, char **errstring
)
2837 array_list_t
*alp
, *alp2
= NULL
;
2842 * allocate array list
2844 if ((alp
= config_calloc_check(1, sizeof (array_list_t
),
2845 errstring
)) == NULL
) {
2846 return (CFGA_LIB_ERROR
);
2853 * The listopts argument is currently unused. Use NULL
2856 if ((rc
= (*(libloc_p
->libp
->cfga_list_ext_p
))(
2857 libloc_p
->ap_physical
, &alp
->array
, &alp
->nelem
, lstatp
->opts
, NULL
,
2858 errstring
, lstatp
->flags
)) != CFGA_OK
|| alp
->nelem
<= 0) {
2865 * Set up the logical and physical id's if necessary.
2866 * For v2 interfaces, the generic library (libcfgadm) creates the
2867 * ap_ids only if there are no dynamic attachment points and the
2868 * plug-in does not create the name itself. mklog() is
2869 * assumed to have been called in the caller of this routine.
2871 if (alp
->nelem
== 1) {
2874 clog
= (alp
->array
[0]).ap_log_id
[0];
2875 cphys
= (alp
->array
[0]).ap_phys_id
[0];
2878 (void) snprintf((alp
->array
[0]).ap_log_id
,
2879 sizeof ((alp
->array
[0]).ap_log_id
), "%s",
2880 libloc_p
->ap_logical
);
2883 if (cphys
== '\0') {
2884 (void) snprintf((alp
->array
[0]).ap_phys_id
,
2885 sizeof ((alp
->array
[0]).ap_phys_id
), "%s",
2886 libloc_p
->ap_physical
);
2890 if (libloc_p
->ap_class
[0] == '\0') {
2891 class = CFGA_NO_CLASS
;
2893 class = libloc_p
->ap_class
;
2896 /* Fill in the class information for all list elements */
2897 for (i
= 0; i
< alp
->nelem
; i
++) {
2898 (void) snprintf((alp
->array
[i
]).ap_class
,
2899 sizeof ((alp
->array
[i
]).ap_class
), "%s", class);
2905 if ((alp2
= lstatp
->al
) == NULL
) {
2908 while (alp2
->next
!= NULL
)
2914 (*lstatp
->countp
) += alp
->nelem
;
2920 * Check if a plugin version is within requested limits.
2923 compat_plugin(vers_req_t
*reqp
, int plugin_vers
)
2926 if (!VALID_HSL_VERS(reqp
->v_min
) || !VALID_HSL_VERS(reqp
->v_max
) ||
2927 !VALID_HSL_VERS(plugin_vers
)) {
2931 if (plugin_vers
< reqp
->v_min
|| plugin_vers
> reqp
->v_max
) {
2940 * find_arg_type - determine if an argument is an ap_id or an ap_type.
2941 * Adapted from cfgadm.c
2943 static cfga_ap_types_t
2944 find_arg_type(const char *ap_id
)
2947 cfga_ap_types_t type
= UNKNOWN_AP
;
2950 int size_ap
= 0, size_mkr
= 0, digit
= 0, i
= 0;
2951 char *cp
, path
[MAXPATHLEN
], ap_base
[MAXPATHLEN
];
2957 if (ap_id
== NULL
|| *ap_id
== '\0') {
2959 return (UNKNOWN_AP
);
2963 * Extract the base component
2965 if ((cp
= GET_DYN(ap_id
)) != NULL
) {
2968 len
= strlen(ap_id
);
2971 if (len
>= sizeof (ap_base
)) {
2972 return (UNKNOWN_AP
);
2975 /* Copy only the first "len" chars */
2976 (void) strncpy(ap_base
, ap_id
, len
);
2977 ap_base
[len
] = '\0';
2980 * If it starts with a slash and is stat-able its a physical.
2982 if (*ap_base
== '/' && stat(ap_base
, &sbuf
) == 0) {
2983 return (PHYSICAL_AP
);
2987 * Is this a symlink in CFGA_DEV_DIR ?
2989 (void) snprintf(path
, sizeof (path
), "%s%s",
2990 CFGA_DEV_DIR SLASH
, ap_base
);
2992 if (lstat(path
, &sbuf
) == 0 && S_ISLNK(sbuf
.st_mode
) &&
2993 stat(path
, &sbuf
) == 0) {
2994 return (LOGICAL_LINK_AP
);
2998 * Check for ":" which is always present in an ap_id
2999 * but not in an ap_type.
3000 * we need to check that the characters right before the : are digits
3001 * since an ap_id is of the form <name><instance>:<specific ap name>
3003 if ((mkr
= strchr(ap_base
, ':')) == NULL
) {
3006 size_ap
= strlen(ap_base
);
3007 size_mkr
= strlen(mkr
);
3011 for (i
= size_ap
- size_mkr
- 1; i
> 0; i
--) {
3012 if ((int)isdigit(mkr
[i
])) {
3020 type
= LOGICAL_DRV_AP
;
3029 null_get_cond(lib_loc_t
*liblocp
, cfga_cond_t
*condp
, char **errstring
)
3035 get_cond_v1(lib_loc_t
*liblocp
, cfga_cond_t
*condp
, char **errstring
)
3038 cfga_stat_data_t sdbuf
;
3042 libp
= liblocp
->libp
;
3043 if (libp
->plugin_vers
!= CFGA_HSL_V1
) {
3044 return (CFGA_LIB_ERROR
);
3048 if ((rc
= (*liblocp
->libp
->cfga_stat_p
)(
3049 liblocp
->ap_physical
, &sdbuf
, NULL
, errstring
))
3051 *condp
= sdbuf
.ap_cond
;
3053 *condp
= CFGA_COND_UNKNOWN
;
3060 get_cond_v2(lib_loc_t
*liblocp
, cfga_cond_t
*condp
, char **errstring
)
3064 cfga_list_data_t
*ldbufp
;
3068 libp
= liblocp
->libp
;
3069 if (libp
->plugin_vers
!= CFGA_HSL_V2
) {
3070 return (CFGA_LIB_ERROR
);
3076 if ((rc
= (*liblocp
->libp
->cfga_list_ext_p
)(
3077 liblocp
->ap_physical
, &ldbufp
, &nelem
, NULL
, NULL
,
3078 errstring
, 0)) == CFGA_OK
) {
3079 assert(nelem
== 1 && ldbufp
!= NULL
);
3081 *condp
= ldbufp
->ap_cond
;
3084 *condp
= CFGA_COND_UNKNOWN
;
3090 /* mask represents the flags accepted */
3092 check_flags(cfga_flags_t flags
, cfga_flags_t mask
, char **errstring
)
3094 if ((flags
& ~mask
) != 0) {
3095 config_err(0, INVALID_ARGS
, errstring
);
3096 return (CFGA_ERROR
);
3103 check_apids(int num_ap_ids
, char *const *ap_ids
, char **errstring
)
3105 if (num_ap_ids
<= 0 || ap_ids
== NULL
) {
3106 config_err(0, INVALID_ARGS
, errstring
);
3107 return (CFGA_ERROR
);
3114 * Returns the class or the empty string if attacment point has
3118 get_class(di_minor_t minor
)
3124 if (minor
== DI_MINOR_NIL
) {
3128 cp
= di_minor_nodetype(minor
);
3133 len
= strlen(DDI_NT_ATTACHMENT_POINT
);
3134 if (strncmp(cp
, DDI_NT_ATTACHMENT_POINT
, len
)) {
3141 if (c
!= '\0' && c
!= ':') {
3154 * Transform stat data to list data
3157 stat_to_list(cfga_list_data_t
*lp
, cfga_stat_data_t
*statp
)
3160 (void) snprintf(lp
->ap_log_id
, sizeof (lp
->ap_log_id
), "%s",
3163 (void) snprintf(lp
->ap_phys_id
, sizeof (lp
->ap_phys_id
), "%s",
3166 (void) snprintf(lp
->ap_class
, sizeof (lp
->ap_class
), "%s",
3169 lp
->ap_r_state
= statp
->ap_r_state
;
3170 lp
->ap_o_state
= statp
->ap_o_state
;
3171 lp
->ap_cond
= statp
->ap_cond
;
3172 lp
->ap_busy
= statp
->ap_busy
;
3173 lp
->ap_status_time
= statp
->ap_status_time
;
3175 (void) snprintf(lp
->ap_info
, sizeof (lp
->ap_info
), "%s",
3177 (void) snprintf(lp
->ap_type
, sizeof (lp
->ap_type
), "%s",
3182 lstat_free(list_stat_t
*lstatp
)
3184 stat_data_list_t
*slp
, *slp2
;
3185 array_list_t
*ap
, *ap2
;
3188 while (slp
!= NULL
) {
3197 while (ap
!= NULL
) {
3208 split_apid(char *ap_id
, char **dyncompp
, char **errstring
)
3214 if (ap_id
== NULL
) {
3215 return (CFGA_ERROR
);
3218 if ((cp
= strstr(ap_id
, CFGA_DYN_SEP
)) == NULL
) {
3223 cp
+= strlen(CFGA_DYN_SEP
);
3224 if ((*dyncompp
= config_calloc_check(1, strlen(cp
) + 1,
3225 errstring
)) == NULL
) {
3226 return (CFGA_LIB_ERROR
);
3228 (void) strcpy(*dyncompp
, cp
);
3234 append_dyn(char *buf
, const char *dyncomp
, size_t blen
)
3236 if (dyncomp
!= NULL
) {
3237 char *cp
= buf
+ strlen(buf
);
3238 size_t len
= blen
- strlen(buf
);
3240 (void) snprintf(cp
, len
, "%s%s", CFGA_DYN_SEP
,
3246 * Default implementation of cfga_ap_id_cmp. Works for most cases
3247 * except for long hex number sequences like world-wide-name.
3249 * This function compares the ap's in a generic way. It does so by
3250 * determining the place of difference between the 2 aps. If the first
3251 * difference is a digit, it attempts to obtain the numbers and compare them
3252 * Otherwise it just compares the aps as strings
3255 default_ap_id_cmp(const char *ap_id1
, const char *ap_id2
)
3260 * Search for first different char
3262 while (ap_id1
[i
] == ap_id2
[i
] && ap_id1
[i
] != '\0')
3266 * If one of the char is a digit, back up to where the
3267 * number started, compare the number.
3269 if (isdigit(ap_id1
[i
]) || isdigit(ap_id2
[i
])) {
3270 while ((i
> 0) && isdigit(ap_id1
[i
- 1]))
3273 if (isdigit(ap_id1
[i
]) && isdigit(ap_id2
[i
]))
3274 return (atoi(ap_id1
+ i
) - atoi(ap_id2
+ i
));
3277 /* One of them isn't a number, compare the char */
3278 return (ap_id1
[i
] - ap_id2
[i
]);
3282 hold_lib(plugin_lib_t
*libp
)
3284 assert(libp
->refcnt
>= 0);
3285 (void) mutex_lock(&libp
->lock
);
3287 (void) mutex_unlock(&libp
->lock
);
3291 rele_lib(plugin_lib_t
*libp
)
3293 assert(libp
->refcnt
> 0);
3294 (void) mutex_lock(&libp
->lock
);
3296 (void) mutex_unlock(&libp
->lock
);