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