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