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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <strings.h>
27 #include <assert.h>
28 #include <fm/libtopo.h>
29 #include <topo_prop.h>
30 #include <topo_string.h>
31 #include <topo_alloc.h>
32 #include <topo_error.h>
33 #include <topo_method.h>
34
35 /*
36 * Topology nodes are permitted to contain property information.
37 * Property information is organized according to property grouping.
38 * Each property group defines a name, a stability level for that name,
39 * a stability level for all underlying property data (name, type, values),
40 * a version for the property group definition and and a list of uniquely
41 * defined properties. Property group versions are incremented when one of
42 * the following changes occurs:
43 * - a property name changes
44 * - a property type changes
45 * - a property definition is removed from the group
46 * Compatible changes such as new property definitions in the group do
47 * not require version changes.
48 *
49 * Each property defines a unique (within the group) name, a type and
50 * a value. Properties may be statically defined as int32, uint32, int64,
51 * uint64, fmri, string or arrays of each type. Properties may also be
52 * dynamically exported via module registered methods. For example, a module
53 * may register a method to export an ASRU property that is dynamically
54 * contructed when a call to topo_node_fmri() is invoked for a particular
55 * topology node.
56 *
57 * Static properties are persistently attached to topology nodes during
58 * enumeration by an enumeration module or as part of XML statements in a
59 * toplogy map file using the topo_prop_set* family of routines. Similarly,
60 * property methods are registered during enumeration or as part of
61 * statements in topololgy map files. Set-up of property methods is performed
62 * by calling topo_prop_method_register().
63 *
64 * All properties, whether statically persisted in a snapshot or dynamically
65 * obtained, may be read via the topo_prop_get* family of interfaces.
66 * Callers wishing to receive all property groups and properties for a given
67 * node may use topo_prop_getall(). This routine returns a nested nvlist
68 * of all groupings and property (name, type, value) sets. Groupings
69 * are defined by TOPO_PROP_GROUP (name, data stability, name stability and
70 * version) and a nested nvlist of properties (TOPO_PROP_VAL). Each property
71 * value is defined by its name, type and value.
72 */
73 static void topo_propval_destroy(topo_propval_t *);
74
75 static topo_pgroup_t *
pgroup_get(tnode_t * node,const char * pgname)76 pgroup_get(tnode_t *node, const char *pgname)
77 {
78 topo_pgroup_t *pg;
79 /*
80 * Check for an existing pgroup
81 */
82 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
83 pg = topo_list_next(pg)) {
84 if (strcmp(pg->tpg_info->tpi_name, pgname) == 0) {
85 return (pg);
86 }
87 }
88
89 return (NULL);
90 }
91
92 static topo_propval_t *
propval_get(topo_pgroup_t * pg,const char * pname)93 propval_get(topo_pgroup_t *pg, const char *pname)
94 {
95 topo_proplist_t *pvl;
96
97 if (pg == NULL)
98 return (NULL);
99
100 for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
101 pvl = topo_list_next(pvl)) {
102 if (strcmp(pvl->tp_pval->tp_name, pname) == 0)
103 return (pvl->tp_pval);
104 }
105
106 return (NULL);
107 }
108
109 static int
method_geterror(nvlist_t * nvl,int err,int * errp)110 method_geterror(nvlist_t *nvl, int err, int *errp)
111 {
112 if (nvl != NULL)
113 nvlist_free(nvl);
114
115 *errp = err;
116
117 return (-1);
118 }
119
120 static int
prop_method_get(tnode_t * node,topo_propval_t * pv,topo_propmethod_t * pm,nvlist_t * pargs,int * err)121 prop_method_get(tnode_t *node, topo_propval_t *pv, topo_propmethod_t *pm,
122 nvlist_t *pargs, int *err)
123 {
124 int ret;
125 nvlist_t *args, *nvl;
126 char *name;
127 topo_type_t type;
128
129 if (topo_hdl_nvalloc(pv->tp_hdl, &args, NV_UNIQUE_NAME) < 0 ||
130 nvlist_add_nvlist(args, TOPO_PROP_ARGS, pm->tpm_args) != 0)
131 return (method_geterror(NULL, ETOPO_PROP_NVL, err));
132
133 if (pargs != NULL)
134 if (nvlist_add_nvlist(args, TOPO_PROP_PARGS, pargs) != 0)
135 return (method_geterror(args, ETOPO_PROP_NVL, err));
136
137 /*
138 * Now, get the latest value
139 *
140 * Grab a reference to the property and then unlock the node. This will
141 * allow property methods to safely re-enter the prop_get codepath,
142 * making it possible for property methods to access other property
143 * values on the same node w\o causing a deadlock.
144 */
145 topo_prop_hold(pv);
146 topo_node_unlock(node);
147 if (topo_method_call(node, pm->tpm_name, pm->tpm_version,
148 args, &nvl, err) < 0) {
149 topo_node_lock(node);
150 topo_prop_rele(pv);
151 return (method_geterror(args, *err, err));
152 }
153 topo_node_lock(node);
154 topo_prop_rele(pv);
155
156 nvlist_free(args);
157
158 /* Verify the property contents */
159 ret = nvlist_lookup_string(nvl, TOPO_PROP_VAL_NAME, &name);
160 if (ret != 0 || strcmp(name, pv->tp_name) != 0)
161 return (method_geterror(nvl, ETOPO_PROP_NAME, err));
162
163 ret = nvlist_lookup_uint32(nvl, TOPO_PROP_VAL_TYPE, (uint32_t *)&type);
164 if (ret != 0 || type != pv->tp_type)
165 return (method_geterror(nvl, ETOPO_PROP_TYPE, err));
166
167 /* Release the last value and re-assign to the new value */
168 if (pv->tp_val != NULL)
169 nvlist_free(pv->tp_val);
170 pv->tp_val = nvl;
171
172 return (0);
173 }
174
175 static topo_propval_t *
prop_get(tnode_t * node,const char * pgname,const char * pname,nvlist_t * pargs,int * err)176 prop_get(tnode_t *node, const char *pgname, const char *pname, nvlist_t *pargs,
177 int *err)
178 {
179 topo_propval_t *pv = NULL;
180
181 if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL) {
182 *err = ETOPO_PROP_NOENT;
183 return (NULL);
184 }
185
186 if (pv->tp_flag & TOPO_PROP_NONVOLATILE && pv->tp_val != NULL)
187 return (pv);
188
189 if (pv->tp_method != NULL) {
190 if (prop_method_get(node, pv, pv->tp_method, pargs, err) < 0)
191 return (NULL);
192 }
193
194 return (pv);
195 }
196
197 static int
get_properror(tnode_t * node,int * errp,int err)198 get_properror(tnode_t *node, int *errp, int err)
199 {
200 topo_node_unlock(node);
201 *errp = err;
202 return (-1);
203 }
204
205 static int
prop_getval(tnode_t * node,const char * pgname,const char * pname,void * val,topo_type_t type,uint_t * nelems,int * err)206 prop_getval(tnode_t *node, const char *pgname, const char *pname, void *val,
207 topo_type_t type, uint_t *nelems, int *err)
208 {
209 int i, j, ret = 0;
210 topo_hdl_t *thp = node->tn_hdl;
211 topo_propval_t *pv;
212
213 topo_node_lock(node);
214 if ((pv = prop_get(node, pgname, pname, NULL, err))
215 == NULL)
216 return (get_properror(node, err, *err));
217
218 if (pv->tp_type != type)
219 return (get_properror(node, err, ETOPO_PROP_TYPE));
220
221 switch (type) {
222 case TOPO_TYPE_INT32:
223 ret = nvlist_lookup_int32(pv->tp_val, TOPO_PROP_VAL_VAL,
224 (int32_t *)val);
225 break;
226 case TOPO_TYPE_UINT32:
227 ret = nvlist_lookup_uint32(pv->tp_val,
228 TOPO_PROP_VAL_VAL, (uint32_t *)val);
229 break;
230 case TOPO_TYPE_INT64:
231 ret = nvlist_lookup_int64(pv->tp_val, TOPO_PROP_VAL_VAL,
232 (int64_t *)val);
233 break;
234 case TOPO_TYPE_UINT64:
235 ret = nvlist_lookup_uint64(pv->tp_val,
236 TOPO_PROP_VAL_VAL, (uint64_t *)val);
237 break;
238 case TOPO_TYPE_DOUBLE:
239 ret = nvlist_lookup_double(pv->tp_val,
240 TOPO_PROP_VAL_VAL, (double *)val);
241 break;
242 case TOPO_TYPE_STRING: {
243 char *str;
244
245 ret = nvlist_lookup_string(pv->tp_val,
246 TOPO_PROP_VAL_VAL, &str);
247 if (ret == 0) {
248 char *s2;
249 if ((s2 = topo_hdl_strdup(thp, str)) == NULL)
250 ret = -1;
251 else
252 *(char **)val = s2;
253 }
254 break;
255 }
256 case TOPO_TYPE_FMRI: {
257 nvlist_t *nvl;
258
259 ret = nvlist_lookup_nvlist(pv->tp_val,
260 TOPO_PROP_VAL_VAL, &nvl);
261 if (ret == 0)
262 ret = topo_hdl_nvdup(thp, nvl,
263 (nvlist_t **)val);
264 break;
265 }
266 case TOPO_TYPE_INT32_ARRAY: {
267 int32_t *a1, *a2;
268
269 if ((ret = nvlist_lookup_int32_array(pv->tp_val,
270 TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
271 break;
272 if ((a1 = topo_hdl_alloc(thp, sizeof (int32_t) *
273 *nelems)) == NULL) {
274 ret = ETOPO_NOMEM;
275 break;
276 }
277 for (i = 0; i < *nelems; ++i)
278 a1[i] = a2[i];
279 *(int32_t **)val = a1;
280 break;
281 }
282 case TOPO_TYPE_UINT32_ARRAY: {
283 uint32_t *a1, *a2;
284
285 if ((ret = nvlist_lookup_uint32_array(pv->tp_val,
286 TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
287 break;
288 if ((a1 = topo_hdl_alloc(thp, sizeof (uint32_t) *
289 *nelems)) == NULL) {
290 ret = ETOPO_NOMEM;
291 break;
292 }
293 for (i = 0; i < *nelems; ++i)
294 a1[i] = a2[i];
295 *(uint32_t **)val = a1;
296 break;
297 }
298 case TOPO_TYPE_INT64_ARRAY: {
299 int64_t *a1, *a2;
300
301 if ((ret = nvlist_lookup_int64_array(pv->tp_val,
302 TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
303 break;
304 if ((a1 = topo_hdl_alloc(thp, sizeof (int64_t) *
305 *nelems)) == NULL) {
306 ret = ETOPO_NOMEM;
307 break;
308 }
309 for (i = 0; i < *nelems; ++i)
310 a1[i] = a2[i];
311 *(int64_t **)val = a1;
312 break;
313 }
314 case TOPO_TYPE_UINT64_ARRAY: {
315 uint64_t *a1, *a2;
316
317 if ((ret = nvlist_lookup_uint64_array(pv->tp_val,
318 TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
319 break;
320 if ((a1 = topo_hdl_alloc(thp, sizeof (uint64_t) *
321 *nelems)) == NULL) {
322 ret = ETOPO_NOMEM;
323 break;
324 }
325 for (i = 0; i < *nelems; ++i)
326 a1[i] = a2[i];
327 *(uint64_t **)val = a1;
328 break;
329 }
330 case TOPO_TYPE_STRING_ARRAY: {
331 char **a1, **a2;
332
333 if ((ret = nvlist_lookup_string_array(pv->tp_val,
334 TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
335 break;
336 if ((a1 = topo_hdl_alloc(thp, sizeof (char *) *
337 *nelems)) == NULL) {
338 ret = ETOPO_NOMEM;
339 break;
340 }
341 for (i = 0; i < *nelems; ++i) {
342 if ((a1[i] = topo_hdl_strdup(thp, a2[i]))
343 == NULL) {
344 for (j = 0; j < i; ++j)
345 topo_hdl_free(thp, a1[j],
346 sizeof (char *));
347 topo_hdl_free(thp, a1,
348 sizeof (char *) * *nelems);
349 break;
350 }
351 }
352 *(char ***)val = a1;
353 break;
354 }
355 case TOPO_TYPE_FMRI_ARRAY: {
356 nvlist_t **a1, **a2;
357
358 if ((ret = nvlist_lookup_nvlist_array(pv->tp_val,
359 TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
360 break;
361 if ((a1 = topo_hdl_alloc(thp, sizeof (nvlist_t *) *
362 *nelems)) == NULL) {
363 ret = ETOPO_NOMEM;
364 break;
365 }
366 for (i = 0; i < *nelems; ++i) {
367 if (topo_hdl_nvdup(thp, a2[i], &a1[i]) < 0) {
368 for (j = 0; j < i; ++j)
369 nvlist_free(a1[j]);
370 topo_hdl_free(thp, a1,
371 sizeof (nvlist_t *) * *nelems);
372 break;
373 }
374 }
375 *(nvlist_t ***)val = a1;
376 break;
377 }
378 default:
379 ret = ETOPO_PROP_NOENT;
380 }
381
382 if (ret != 0)
383 if (ret == ENOENT)
384 return (get_properror(node, err, ETOPO_PROP_NOENT));
385 else if (ret < ETOPO_UNKNOWN)
386 return (get_properror(node, err, ETOPO_PROP_NVL));
387 else
388 return (get_properror(node, err, ret));
389
390 topo_node_unlock(node);
391 return (0);
392 }
393
394 int
topo_prop_get_int32(tnode_t * node,const char * pgname,const char * pname,int32_t * val,int * err)395 topo_prop_get_int32(tnode_t *node, const char *pgname, const char *pname,
396 int32_t *val, int *err)
397 {
398 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_INT32,
399 NULL, err));
400 }
401
402 int
topo_prop_get_uint32(tnode_t * node,const char * pgname,const char * pname,uint32_t * val,int * err)403 topo_prop_get_uint32(tnode_t *node, const char *pgname, const char *pname,
404 uint32_t *val, int *err)
405 {
406 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_UINT32,
407 NULL, err));
408 }
409
410 int
topo_prop_get_int64(tnode_t * node,const char * pgname,const char * pname,int64_t * val,int * err)411 topo_prop_get_int64(tnode_t *node, const char *pgname, const char *pname,
412 int64_t *val, int *err)
413 {
414 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_INT64,
415 NULL, err));
416 }
417
418 int
topo_prop_get_uint64(tnode_t * node,const char * pgname,const char * pname,uint64_t * val,int * err)419 topo_prop_get_uint64(tnode_t *node, const char *pgname, const char *pname,
420 uint64_t *val, int *err)
421 {
422 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_UINT64,
423 NULL, err));
424 }
425
426 int
topo_prop_get_double(tnode_t * node,const char * pgname,const char * pname,double * val,int * err)427 topo_prop_get_double(tnode_t *node, const char *pgname, const char *pname,
428 double *val, int *err)
429 {
430 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_DOUBLE,
431 NULL, err));
432 }
433
434 int
topo_prop_get_string(tnode_t * node,const char * pgname,const char * pname,char ** val,int * err)435 topo_prop_get_string(tnode_t *node, const char *pgname, const char *pname,
436 char **val, int *err)
437 {
438 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_STRING,
439 NULL, err));
440 }
441
442 int
topo_prop_get_fmri(tnode_t * node,const char * pgname,const char * pname,nvlist_t ** val,int * err)443 topo_prop_get_fmri(tnode_t *node, const char *pgname, const char *pname,
444 nvlist_t **val, int *err)
445 {
446 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_FMRI,
447 NULL, err));
448 }
449
450 int
topo_prop_get_int32_array(tnode_t * node,const char * pgname,const char * pname,int32_t ** val,uint_t * nelem,int * err)451 topo_prop_get_int32_array(tnode_t *node, const char *pgname, const char *pname,
452 int32_t **val, uint_t *nelem, int *err)
453 {
454 return (prop_getval(node, pgname, pname, (void *)val,
455 TOPO_TYPE_INT32_ARRAY, nelem, err));
456 }
457
458 int
topo_prop_get_uint32_array(tnode_t * node,const char * pgname,const char * pname,uint32_t ** val,uint_t * nelem,int * err)459 topo_prop_get_uint32_array(tnode_t *node, const char *pgname, const char *pname,
460 uint32_t **val, uint_t *nelem, int *err)
461 {
462 return (prop_getval(node, pgname, pname, (void *)val,
463 TOPO_TYPE_UINT32_ARRAY, nelem, err));
464 }
465
466 int
topo_prop_get_int64_array(tnode_t * node,const char * pgname,const char * pname,int64_t ** val,uint_t * nelem,int * err)467 topo_prop_get_int64_array(tnode_t *node, const char *pgname, const char *pname,
468 int64_t **val, uint_t *nelem, int *err)
469 {
470 return (prop_getval(node, pgname, pname, (void *)val,
471 TOPO_TYPE_INT64_ARRAY, nelem, err));
472 }
473
474 int
topo_prop_get_uint64_array(tnode_t * node,const char * pgname,const char * pname,uint64_t ** val,uint_t * nelem,int * err)475 topo_prop_get_uint64_array(tnode_t *node, const char *pgname, const char *pname,
476 uint64_t **val, uint_t *nelem, int *err)
477 {
478 return (prop_getval(node, pgname, pname, (void *)val,
479 TOPO_TYPE_UINT64_ARRAY, nelem, err));
480 }
481
482 int
topo_prop_get_string_array(tnode_t * node,const char * pgname,const char * pname,char *** val,uint_t * nelem,int * err)483 topo_prop_get_string_array(tnode_t *node, const char *pgname, const char *pname,
484 char ***val, uint_t *nelem, int *err)
485 {
486 return (prop_getval(node, pgname, pname, (void *)val,
487 TOPO_TYPE_STRING_ARRAY, nelem, err));
488 }
489
490 int
topo_prop_get_fmri_array(tnode_t * node,const char * pgname,const char * pname,nvlist_t *** val,uint_t * nelem,int * err)491 topo_prop_get_fmri_array(tnode_t *node, const char *pgname, const char *pname,
492 nvlist_t ***val, uint_t *nelem, int *err)
493 {
494 return (prop_getval(node, pgname, pname, (void *)val,
495 TOPO_TYPE_FMRI_ARRAY, nelem, err));
496 }
497
498 static topo_propval_t *
set_seterror(tnode_t * node,topo_proplist_t * pvl,int * errp,int err)499 set_seterror(tnode_t *node, topo_proplist_t *pvl, int *errp, int err)
500 {
501 topo_hdl_t *thp = node->tn_hdl;
502 topo_propval_t *pv;
503
504 if (pvl != NULL) {
505 pv = pvl->tp_pval;
506 topo_propval_destroy(pv);
507 topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
508 }
509
510 topo_node_unlock(node);
511 *errp = err;
512
513 return (NULL);
514 }
515
516 static topo_propval_t *
prop_create(tnode_t * node,const char * pgname,const char * pname,topo_type_t type,int flag,int * err)517 prop_create(tnode_t *node, const char *pgname, const char *pname,
518 topo_type_t type, int flag, int *err)
519 {
520 topo_hdl_t *thp = node->tn_hdl;
521 topo_pgroup_t *pg;
522 topo_propval_t *pv;
523 topo_proplist_t *pvl;
524
525 /*
526 * Replace existing prop value with new one
527 */
528 if ((pg = pgroup_get(node, pgname)) == NULL) {
529 topo_node_unlock(node);
530 *err = ETOPO_PROP_NOENT;
531 return (NULL);
532 }
533
534 if ((pv = propval_get(pg, pname)) != NULL) {
535 if (pv->tp_type != type)
536 return (set_seterror(node, NULL, err, ETOPO_PROP_TYPE));
537 else if (! (pv->tp_flag & TOPO_PROP_MUTABLE))
538 return (set_seterror(node, NULL, err, ETOPO_PROP_DEFD));
539
540 nvlist_free(pv->tp_val);
541 pv->tp_val = NULL;
542 } else {
543 if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t)))
544 == NULL)
545 return (set_seterror(node, NULL, err, ETOPO_NOMEM));
546
547 if ((pv = topo_hdl_zalloc(thp, sizeof (topo_propval_t)))
548 == NULL)
549 return (set_seterror(node, pvl, err, ETOPO_NOMEM));
550
551 pv->tp_hdl = thp;
552 pvl->tp_pval = pv;
553
554 if ((pv->tp_name = topo_hdl_strdup(thp, pname))
555 == NULL)
556 return (set_seterror(node, pvl, err, ETOPO_NOMEM));
557 pv->tp_flag = flag;
558 pv->tp_type = type;
559 topo_prop_hold(pv);
560 topo_list_append(&pg->tpg_pvals, pvl);
561 }
562
563 return (pv);
564 }
565
566 static int
topo_prop_set(tnode_t * node,const char * pgname,const char * pname,topo_type_t type,int flag,void * val,int nelems,int * err)567 topo_prop_set(tnode_t *node, const char *pgname, const char *pname,
568 topo_type_t type, int flag, void *val, int nelems, int *err)
569 {
570 int ret;
571 topo_hdl_t *thp = node->tn_hdl;
572 nvlist_t *nvl;
573
574 if (topo_hdl_nvalloc(thp, &nvl, NV_UNIQUE_NAME) < 0) {
575 *err = ETOPO_PROP_NVL;
576 return (-1);
577 }
578
579 ret = nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, pname);
580 ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, type);
581 switch (type) {
582 case TOPO_TYPE_INT32:
583 ret |= nvlist_add_int32(nvl, TOPO_PROP_VAL_VAL,
584 *(int32_t *)val);
585 break;
586 case TOPO_TYPE_UINT32:
587 ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL,
588 *(uint32_t *)val);
589 break;
590 case TOPO_TYPE_INT64:
591 ret |= nvlist_add_int64(nvl, TOPO_PROP_VAL_VAL,
592 *(int64_t *)val);
593 break;
594 case TOPO_TYPE_UINT64:
595 ret |= nvlist_add_uint64(nvl, TOPO_PROP_VAL_VAL,
596 *(uint64_t *)val);
597 break;
598 case TOPO_TYPE_DOUBLE:
599 ret |= nvlist_add_double(nvl, TOPO_PROP_VAL_VAL,
600 *(double *)val);
601 break;
602 case TOPO_TYPE_STRING:
603 ret |= nvlist_add_string(nvl, TOPO_PROP_VAL_VAL,
604 (char *)val);
605 break;
606 case TOPO_TYPE_FMRI:
607 ret |= nvlist_add_nvlist(nvl, TOPO_PROP_VAL_VAL,
608 (nvlist_t *)val);
609 break;
610 case TOPO_TYPE_INT32_ARRAY:
611 ret |= nvlist_add_int32_array(nvl,
612 TOPO_PROP_VAL_VAL, (int32_t *)val, nelems);
613 break;
614 case TOPO_TYPE_UINT32_ARRAY:
615 ret |= nvlist_add_uint32_array(nvl,
616 TOPO_PROP_VAL_VAL, (uint32_t *)val, nelems);
617 break;
618 case TOPO_TYPE_INT64_ARRAY:
619 ret |= nvlist_add_int64_array(nvl,
620 TOPO_PROP_VAL_VAL, (int64_t *)val, nelems);
621 break;
622 case TOPO_TYPE_UINT64_ARRAY:
623 ret |= nvlist_add_uint64_array(nvl,
624 TOPO_PROP_VAL_VAL, (uint64_t *)val, nelems);
625 break;
626 case TOPO_TYPE_STRING_ARRAY:
627 ret |= nvlist_add_string_array(nvl,
628 TOPO_PROP_VAL_VAL, (char **)val, nelems);
629 break;
630 case TOPO_TYPE_FMRI_ARRAY:
631 ret |= nvlist_add_nvlist_array(nvl,
632 TOPO_PROP_VAL_VAL, (nvlist_t **)val, nelems);
633 break;
634 default:
635 *err = ETOPO_PROP_TYPE;
636 return (-1);
637 }
638
639 if (ret != 0) {
640 nvlist_free(nvl);
641 if (ret == ENOMEM) {
642 *err = ETOPO_PROP_NOMEM;
643 return (-1);
644 } else {
645 *err = ETOPO_PROP_NVL;
646 return (-1);
647 }
648 }
649
650 if (topo_prop_setprop(node, pgname, nvl, flag, nvl, err) != 0) {
651 nvlist_free(nvl);
652 return (-1); /* err set */
653 }
654 nvlist_free(nvl);
655 return (ret);
656 }
657
658 int
topo_prop_set_int32(tnode_t * node,const char * pgname,const char * pname,int flag,int32_t val,int * err)659 topo_prop_set_int32(tnode_t *node, const char *pgname, const char *pname,
660 int flag, int32_t val, int *err)
661 {
662 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT32, flag,
663 &val, 1, err));
664 }
665
666 int
topo_prop_set_uint32(tnode_t * node,const char * pgname,const char * pname,int flag,uint32_t val,int * err)667 topo_prop_set_uint32(tnode_t *node, const char *pgname, const char *pname,
668 int flag, uint32_t val, int *err)
669 {
670 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT32, flag,
671 &val, 1, err));
672 }
673
674 int
topo_prop_set_int64(tnode_t * node,const char * pgname,const char * pname,int flag,int64_t val,int * err)675 topo_prop_set_int64(tnode_t *node, const char *pgname, const char *pname,
676 int flag, int64_t val, int *err)
677 {
678 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT64, flag,
679 &val, 1, err));
680 }
681
682 int
topo_prop_set_uint64(tnode_t * node,const char * pgname,const char * pname,int flag,uint64_t val,int * err)683 topo_prop_set_uint64(tnode_t *node, const char *pgname, const char *pname,
684 int flag, uint64_t val, int *err)
685 {
686 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT64, flag,
687 &val, 1, err));
688 }
689
690 int
topo_prop_set_double(tnode_t * node,const char * pgname,const char * pname,int flag,double val,int * err)691 topo_prop_set_double(tnode_t *node, const char *pgname, const char *pname,
692 int flag, double val, int *err)
693 {
694 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_DOUBLE, flag,
695 &val, 1, err));
696 }
697
698 int
topo_prop_set_string(tnode_t * node,const char * pgname,const char * pname,int flag,const char * val,int * err)699 topo_prop_set_string(tnode_t *node, const char *pgname, const char *pname,
700 int flag, const char *val, int *err)
701 {
702 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_STRING, flag,
703 (void *)val, 1, err));
704 }
705
706 int
topo_prop_set_fmri(tnode_t * node,const char * pgname,const char * pname,int flag,const nvlist_t * fmri,int * err)707 topo_prop_set_fmri(tnode_t *node, const char *pgname, const char *pname,
708 int flag, const nvlist_t *fmri, int *err)
709 {
710 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_FMRI, flag,
711 (void *)fmri, 1, err));
712 }
713
714 int
topo_prop_set_int32_array(tnode_t * node,const char * pgname,const char * pname,int flag,int32_t * val,uint_t nelems,int * err)715 topo_prop_set_int32_array(tnode_t *node, const char *pgname, const char *pname,
716 int flag, int32_t *val, uint_t nelems, int *err)
717 {
718 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT32_ARRAY, flag,
719 val, nelems, err));
720 }
721
722 int
topo_prop_set_uint32_array(tnode_t * node,const char * pgname,const char * pname,int flag,uint32_t * val,uint_t nelems,int * err)723 topo_prop_set_uint32_array(tnode_t *node, const char *pgname, const char *pname,
724 int flag, uint32_t *val, uint_t nelems, int *err)
725 {
726 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT32_ARRAY, flag,
727 val, nelems, err));
728 }
729
730 int
topo_prop_set_int64_array(tnode_t * node,const char * pgname,const char * pname,int flag,int64_t * val,uint_t nelems,int * err)731 topo_prop_set_int64_array(tnode_t *node, const char *pgname, const char *pname,
732 int flag, int64_t *val, uint_t nelems, int *err)
733 {
734 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT64_ARRAY, flag,
735 val, nelems, err));
736 }
737
738 int
topo_prop_set_uint64_array(tnode_t * node,const char * pgname,const char * pname,int flag,uint64_t * val,uint_t nelems,int * err)739 topo_prop_set_uint64_array(tnode_t *node, const char *pgname, const char *pname,
740 int flag, uint64_t *val, uint_t nelems, int *err)
741 {
742 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT64_ARRAY, flag,
743 val, nelems, err));
744 }
745
746 int
topo_prop_set_string_array(tnode_t * node,const char * pgname,const char * pname,int flag,const char ** val,uint_t nelems,int * err)747 topo_prop_set_string_array(tnode_t *node, const char *pgname, const char *pname,
748 int flag, const char **val, uint_t nelems, int *err)
749 {
750 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_STRING_ARRAY, flag,
751 (void *)val, nelems, err));
752 }
753
754 int
topo_prop_set_fmri_array(tnode_t * node,const char * pgname,const char * pname,int flag,const nvlist_t ** fmri,uint_t nelems,int * err)755 topo_prop_set_fmri_array(tnode_t *node, const char *pgname, const char *pname,
756 int flag, const nvlist_t **fmri, uint_t nelems, int *err)
757 {
758 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_FMRI_ARRAY, flag,
759 (void *)fmri, nelems, err));
760 }
761
762 /*
763 * topo_prop_setprop() is a private project function for fmtopo
764 */
765 int
topo_prop_setprop(tnode_t * node,const char * pgname,nvlist_t * prop,int flag,nvlist_t * pargs,int * err)766 topo_prop_setprop(tnode_t *node, const char *pgname, nvlist_t *prop,
767 int flag, nvlist_t *pargs, int *err)
768 {
769 int ret;
770 topo_hdl_t *thp = node->tn_hdl;
771 topo_propval_t *pv;
772 nvlist_t *nvl, *args;
773 char *name;
774 topo_type_t type;
775
776 if (nvlist_lookup_string(prop, TOPO_PROP_VAL_NAME, &name) != 0) {
777 *err = ETOPO_PROP_NAME;
778 return (-1);
779 }
780 if (nvlist_lookup_uint32(prop, TOPO_PROP_VAL_TYPE, (uint32_t *)&type)
781 != 0) {
782 *err = ETOPO_PROP_TYPE;
783 return (-1);
784 }
785
786 topo_node_lock(node);
787 if ((pv = prop_create(node, pgname, name, type, flag, err)) == NULL)
788 return (-1); /* unlocked and err set */
789
790 /*
791 * Set by method or set to new prop value. If we fail, leave
792 * property in list with old value.
793 */
794 if (pv->tp_method != NULL) {
795 topo_propmethod_t *pm = pv->tp_method;
796
797 if (topo_hdl_nvalloc(pv->tp_hdl, &args, NV_UNIQUE_NAME) < 0) {
798 topo_node_unlock(node);
799 *err = ETOPO_PROP_NOMEM;
800 return (-1);
801 }
802 ret = nvlist_add_nvlist(args, TOPO_PROP_ARGS, pm->tpm_args);
803 if (pargs != NULL)
804 ret |= nvlist_add_nvlist(args, TOPO_PROP_PARGS, pargs);
805
806 if (ret != 0) {
807 topo_node_unlock(node);
808 nvlist_free(args);
809 *err = ETOPO_PROP_NVL;
810 return (-1);
811 }
812
813 /*
814 *
815 * Grab a reference to the property and then unlock the node.
816 * This will allow property methods to safely re-enter the
817 * prop_get codepath, making it possible for property methods
818 * to access other property values on the same node w\o causing
819 * a deadlock.
820 *
821 * We don't technically need this now, since this interface is
822 * currently only used by fmtopo (which is single-threaded), but
823 * we may make this interface available to other parts of
824 * libtopo in the future, so best to make it MT-safe now.
825 */
826 topo_prop_hold(pv);
827 topo_node_unlock(node);
828 ret = topo_method_call(node, pm->tpm_name, pm->tpm_version,
829 args, &nvl, err);
830 topo_node_lock(node);
831 topo_prop_rele(pv);
832
833 nvlist_free(args);
834 } else {
835 if ((ret = topo_hdl_nvdup(thp, prop, &nvl)) != 0)
836 *err = ETOPO_PROP_NOMEM;
837 }
838
839 if (ret != 0) {
840 topo_node_unlock(node);
841 return (-1);
842 }
843
844 pv->tp_val = nvl;
845 topo_node_unlock(node);
846 return (0);
847 }
848
849 static int
register_methoderror(tnode_t * node,topo_propmethod_t * pm,int * errp,int l,int err)850 register_methoderror(tnode_t *node, topo_propmethod_t *pm, int *errp, int l,
851 int err)
852 {
853 topo_hdl_t *thp = node->tn_hdl;
854
855 if (pm != NULL) {
856 if (pm->tpm_name != NULL)
857 topo_hdl_strfree(thp, pm->tpm_name);
858 if (pm->tpm_args != NULL)
859 nvlist_free(pm->tpm_args);
860 topo_hdl_free(thp, pm, sizeof (topo_propmethod_t));
861 }
862
863 *errp = err;
864
865 if (l != 0)
866 topo_node_unlock(node);
867
868 return (-1);
869 }
870
871 int
prop_method_register(tnode_t * node,const char * pgname,const char * pname,topo_type_t ptype,const char * mname,topo_version_t version,const nvlist_t * args,int * err)872 prop_method_register(tnode_t *node, const char *pgname, const char *pname,
873 topo_type_t ptype, const char *mname, topo_version_t version,
874 const nvlist_t *args, int *err)
875 {
876 topo_hdl_t *thp = node->tn_hdl;
877 topo_propmethod_t *pm = NULL;
878 topo_propval_t *pv = NULL;
879
880 if ((pm = topo_hdl_zalloc(thp, sizeof (topo_propmethod_t))) == NULL)
881 return (register_methoderror(node, pm, err, 1,
882 ETOPO_PROP_NOMEM));
883
884 if ((pm->tpm_name = topo_hdl_strdup(thp, mname)) == NULL)
885 return (register_methoderror(node, pm, err, 1,
886 ETOPO_PROP_NOMEM));
887
888 pm->tpm_version = version;
889
890 if (topo_hdl_nvdup(thp, (nvlist_t *)args, &pm->tpm_args) != 0)
891 return (register_methoderror(node, pm, err, 1,
892 ETOPO_PROP_NOMEM));
893
894 /*
895 * It's possible the property may already exist. However we still want
896 * to allow the method to be registered. This is to handle the case
897 * where we specify a prop method in an xml map to override the value
898 * that was set by the enumerator.
899 *
900 * By default, propmethod-backed properties are not MUTABLE. This is
901 * done to simplify the programming model for modules that implement
902 * property methods as most propmethods tend to only support get
903 * operations. Enumerator modules can override this by calling
904 * topo_prop_setmutable(). Propmethods that are registered via XML can
905 * be set as mutable via the optional "mutable" attribute, which will
906 * result in the xml parser calling topo_prop_setflags() after
907 * registering the propmethod.
908 */
909 if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL)
910 if ((pv = prop_create(node, pgname, pname, ptype,
911 TOPO_PROP_IMMUTABLE, err)) == NULL) {
912 /* node unlocked */
913 return (register_methoderror(node, pm, err, 0, *err));
914 }
915
916 if (pv->tp_method != NULL)
917 return (register_methoderror(node, pm, err, 1,
918 ETOPO_METHOD_DEFD));
919
920 if (pv->tp_val != NULL) {
921 nvlist_free(pv->tp_val);
922 pv->tp_val = NULL;
923 }
924 pv->tp_method = pm;
925
926 topo_node_unlock(node);
927
928 return (0);
929 }
930
931 int
topo_prop_method_register(tnode_t * node,const char * pgname,const char * pname,topo_type_t ptype,const char * mname,const nvlist_t * args,int * err)932 topo_prop_method_register(tnode_t *node, const char *pgname, const char *pname,
933 topo_type_t ptype, const char *mname, const nvlist_t *args, int *err)
934 {
935 topo_imethod_t *mp;
936
937 topo_node_lock(node);
938
939 if ((mp = topo_method_lookup(node, mname)) == NULL)
940 return (register_methoderror(node, NULL, err, 1,
941 ETOPO_METHOD_NOTSUP)); /* node unlocked */
942
943 topo_node_lock(node);
944
945 return (prop_method_register(node, pgname, pname, ptype, mname,
946 mp->tim_version, args, err)); /* err set and node unlocked */
947 }
948
949 int
topo_prop_method_version_register(tnode_t * node,const char * pgname,const char * pname,topo_type_t ptype,const char * mname,topo_version_t version,const nvlist_t * args,int * err)950 topo_prop_method_version_register(tnode_t *node, const char *pgname,
951 const char *pname, topo_type_t ptype, const char *mname,
952 topo_version_t version, const nvlist_t *args, int *err)
953 {
954 topo_imethod_t *mp;
955
956 topo_node_lock(node);
957
958 if ((mp = topo_method_lookup(node, mname)) == NULL)
959 return (register_methoderror(node, NULL, err, 1,
960 ETOPO_METHOD_NOTSUP)); /* node unlocked */
961
962 topo_node_lock(node);
963
964 if (version < mp->tim_version)
965 return (register_methoderror(node, NULL, err, 1,
966 ETOPO_METHOD_VEROLD));
967 if (version > mp->tim_version)
968 return (register_methoderror(node, NULL, err, 1,
969 ETOPO_METHOD_VERNEW));
970
971 return (prop_method_register(node, pgname, pname, ptype, mname,
972 version, args, err)); /* err set and node unlocked */
973 }
974
975 void
topo_prop_method_unregister(tnode_t * node,const char * pgname,const char * pname)976 topo_prop_method_unregister(tnode_t *node, const char *pgname,
977 const char *pname)
978 {
979 topo_propval_t *pv;
980 topo_pgroup_t *pg;
981 topo_proplist_t *pvl;
982 topo_hdl_t *thp = node->tn_hdl;
983
984 topo_node_lock(node);
985
986 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
987 pg = topo_list_next(pg)) {
988 if (strcmp(pg->tpg_info->tpi_name, pgname) == 0) {
989 break;
990 }
991 }
992
993 if (pg == NULL) {
994 topo_node_unlock(node);
995 return;
996 }
997
998 for (pvl = topo_list_next(&pg->tpg_list); pvl != NULL;
999 pvl = topo_list_next(pvl)) {
1000 pv = pvl->tp_pval;
1001 if (strcmp(pv->tp_name, pname) == 0) {
1002 topo_list_delete(&pg->tpg_pvals, pvl);
1003 assert(pv->tp_refs == 1);
1004 topo_prop_rele(pv);
1005 topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
1006 break;
1007 }
1008 }
1009
1010 topo_node_unlock(node);
1011 }
1012
1013 int
topo_prop_setmutable(tnode_t * node,const char * pgname,const char * pname,int * err)1014 topo_prop_setmutable(tnode_t *node, const char *pgname, const char *pname,
1015 int *err)
1016 {
1017 topo_propval_t *pv = NULL;
1018
1019 topo_node_lock(node);
1020 if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL) {
1021 topo_node_unlock(node);
1022 *err = ETOPO_PROP_NOENT;
1023 return (-1);
1024 }
1025
1026 /*
1027 * If the property is being inherited then we don't want to allow a
1028 * change from IMMUTABLE to MUTABLE.
1029 */
1030 if (pv->tp_refs > 1) {
1031 topo_node_unlock(node);
1032 *err = ETOPO_PROP_DEFD;
1033 return (-1);
1034 }
1035 pv->tp_flag |= TOPO_PROP_MUTABLE;
1036
1037 topo_node_unlock(node);
1038
1039 return (0);
1040 }
1041 int
topo_prop_setnonvolatile(tnode_t * node,const char * pgname,const char * pname,int * err)1042 topo_prop_setnonvolatile(tnode_t *node, const char *pgname, const char *pname,
1043 int *err)
1044 {
1045 topo_propval_t *pv = NULL;
1046
1047 topo_node_lock(node);
1048 if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL) {
1049 topo_node_unlock(node);
1050 *err = ETOPO_PROP_NOENT;
1051 return (-1);
1052 }
1053
1054 pv->tp_flag |= TOPO_PROP_NONVOLATILE;
1055
1056 topo_node_unlock(node);
1057
1058 return (0);
1059 }
1060
1061 static int
inherit_seterror(tnode_t * node,int * errp,int err)1062 inherit_seterror(tnode_t *node, int *errp, int err)
1063 {
1064 topo_node_unlock(node);
1065 topo_node_unlock(node->tn_parent);
1066
1067 *errp = err;
1068
1069 return (-1);
1070 }
1071
1072 int
topo_prop_inherit(tnode_t * node,const char * pgname,const char * name,int * err)1073 topo_prop_inherit(tnode_t *node, const char *pgname, const char *name, int *err)
1074 {
1075 topo_hdl_t *thp = node->tn_hdl;
1076 tnode_t *pnode = node->tn_parent;
1077 topo_pgroup_t *pg;
1078 topo_propval_t *pv;
1079 topo_proplist_t *pvl;
1080
1081 topo_node_lock(pnode);
1082 topo_node_lock(node);
1083
1084 /*
1085 * Check if the requested property group and prop val are already set
1086 * on the node.
1087 */
1088 if (propval_get(pgroup_get(node, pgname), name) != NULL)
1089 return (inherit_seterror(node, err, ETOPO_PROP_DEFD));
1090
1091 /*
1092 * Check if the requested property group and prop val exists on the
1093 * parent node
1094 */
1095 if ((pv = propval_get(pgroup_get(pnode, pgname), name)) == NULL)
1096 return (inherit_seterror(node, err, ETOPO_PROP_NOENT));
1097
1098 /*
1099 * Can this propval be inherited?
1100 */
1101 if (pv->tp_flag & TOPO_PROP_MUTABLE)
1102 return (inherit_seterror(node, err, ETOPO_PROP_NOINHERIT));
1103
1104 /*
1105 * Property group should already exist: bump the ref count for this
1106 * propval and add it to the node's property group
1107 */
1108 if ((pg = pgroup_get(node, pgname)) == NULL)
1109 return (inherit_seterror(node, err, ETOPO_PROP_NOENT));
1110
1111 if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t)))
1112 == NULL)
1113 return (inherit_seterror(node, err, ETOPO_NOMEM));
1114
1115 topo_prop_hold(pv);
1116 pvl->tp_pval = pv;
1117 topo_list_append(&pg->tpg_pvals, pvl);
1118
1119 topo_node_unlock(node);
1120 topo_node_unlock(pnode);
1121
1122 return (0);
1123 }
1124
1125 topo_pgroup_info_t *
topo_pgroup_info(tnode_t * node,const char * pgname,int * err)1126 topo_pgroup_info(tnode_t *node, const char *pgname, int *err)
1127 {
1128 topo_hdl_t *thp = node->tn_hdl;
1129 topo_pgroup_t *pg;
1130 topo_ipgroup_info_t *pip;
1131 topo_pgroup_info_t *info;
1132
1133 topo_node_lock(node);
1134 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
1135 pg = topo_list_next(pg)) {
1136 if (strcmp(pgname, pg->tpg_info->tpi_name) == 0) {
1137 if ((info = topo_hdl_alloc(thp,
1138 sizeof (topo_pgroup_info_t))) == NULL)
1139 return (NULL);
1140
1141 pip = pg->tpg_info;
1142 if ((info->tpi_name =
1143 topo_hdl_strdup(thp, pip->tpi_name)) == NULL) {
1144 *err = ETOPO_PROP_NOMEM;
1145 topo_hdl_free(thp, info,
1146 sizeof (topo_pgroup_info_t));
1147 topo_node_unlock(node);
1148 return (NULL);
1149 }
1150 info->tpi_namestab = pip->tpi_namestab;
1151 info->tpi_datastab = pip->tpi_datastab;
1152 info->tpi_version = pip->tpi_version;
1153 topo_node_unlock(node);
1154 return (info);
1155 }
1156 }
1157
1158 *err = ETOPO_PROP_NOENT;
1159 topo_node_unlock(node);
1160 return (NULL);
1161 }
1162
1163 static int
pgroup_seterr(tnode_t * node,topo_pgroup_t * pg,topo_ipgroup_info_t * pip,int * err)1164 pgroup_seterr(tnode_t *node, topo_pgroup_t *pg, topo_ipgroup_info_t *pip,
1165 int *err)
1166 {
1167 topo_hdl_t *thp = node->tn_hdl;
1168
1169 if (pip != NULL) {
1170 if (pip->tpi_name != NULL)
1171 topo_hdl_strfree(thp, (char *)pip->tpi_name);
1172 topo_hdl_free(thp, pip, sizeof (topo_ipgroup_info_t));
1173 }
1174
1175 topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
1176 *err = ETOPO_NOMEM;
1177
1178 topo_node_unlock(node);
1179
1180 return (-1);
1181 }
1182
1183 int
topo_pgroup_create(tnode_t * node,const topo_pgroup_info_t * pinfo,int * err)1184 topo_pgroup_create(tnode_t *node, const topo_pgroup_info_t *pinfo, int *err)
1185 {
1186 topo_pgroup_t *pg;
1187 topo_ipgroup_info_t *pip;
1188 topo_hdl_t *thp = node->tn_hdl;
1189
1190 *err = 0;
1191
1192 topo_node_lock(node);
1193 /*
1194 * Check for an existing pgroup
1195 */
1196 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
1197 pg = topo_list_next(pg)) {
1198 if (strcmp(pg->tpg_info->tpi_name, pinfo->tpi_name) == 0) {
1199 *err = ETOPO_PROP_DEFD;
1200 topo_node_unlock(node);
1201 return (-1);
1202 }
1203 }
1204
1205 if ((pg = topo_hdl_zalloc(thp, sizeof (topo_pgroup_t))) == NULL) {
1206 *err = ETOPO_NOMEM;
1207 topo_node_unlock(node);
1208 return (-1);
1209 }
1210
1211 if ((pip = topo_hdl_zalloc(thp, sizeof (topo_ipgroup_info_t)))
1212 == NULL)
1213 return (pgroup_seterr(node, pg, pip, err));
1214
1215 if ((pip->tpi_name = topo_hdl_strdup(thp, pinfo->tpi_name))
1216 == NULL)
1217 return (pgroup_seterr(node, pg, pip, err));
1218
1219 pip->tpi_namestab = pinfo->tpi_namestab;
1220 pip->tpi_datastab = pinfo->tpi_datastab;
1221 pip->tpi_version = pinfo->tpi_version;
1222
1223 pg->tpg_info = pip;
1224
1225 topo_list_append(&node->tn_pgroups, pg);
1226 topo_node_unlock(node);
1227
1228 return (0);
1229 }
1230
1231 void
topo_pgroup_destroy(tnode_t * node,const char * pname)1232 topo_pgroup_destroy(tnode_t *node, const char *pname)
1233 {
1234 topo_hdl_t *thp = node->tn_hdl;
1235 topo_pgroup_t *pg;
1236 topo_proplist_t *pvl;
1237 topo_ipgroup_info_t *pip;
1238
1239 topo_node_lock(node);
1240 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
1241 pg = topo_list_next(pg)) {
1242 if (strcmp(pg->tpg_info->tpi_name, pname) == 0) {
1243 break;
1244 }
1245 }
1246
1247 if (pg == NULL) {
1248 topo_node_unlock(node);
1249 return;
1250 }
1251
1252 while ((pvl = topo_list_next(&pg->tpg_list)) != NULL) {
1253 topo_list_delete(&pg->tpg_pvals, pvl);
1254 topo_prop_rele(pvl->tp_pval);
1255 topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
1256 }
1257
1258 topo_list_delete(&node->tn_pgroups, pg);
1259 topo_node_unlock(node);
1260
1261 pip = pg->tpg_info;
1262 if (pip != NULL) {
1263 if (pip->tpi_name != NULL)
1264 topo_hdl_strfree(thp, (char *)pip->tpi_name);
1265 topo_hdl_free(thp, pip, sizeof (topo_ipgroup_info_t));
1266 }
1267
1268 topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
1269 }
1270
1271 void
topo_pgroup_destroy_all(tnode_t * node)1272 topo_pgroup_destroy_all(tnode_t *node)
1273 {
1274 topo_hdl_t *thp = node->tn_hdl;
1275 topo_pgroup_t *pg;
1276 topo_proplist_t *pvl;
1277 topo_ipgroup_info_t *pip;
1278
1279 topo_node_lock(node);
1280 while ((pg = topo_list_next(&node->tn_pgroups)) != NULL) {
1281 while ((pvl = topo_list_next(&pg->tpg_pvals)) != NULL) {
1282 topo_list_delete(&pg->tpg_pvals, pvl);
1283 topo_prop_rele(pvl->tp_pval);
1284 topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
1285 }
1286
1287 topo_list_delete(&node->tn_pgroups, pg);
1288
1289 pip = pg->tpg_info;
1290 if (pip != NULL) {
1291 if (pip->tpi_name != NULL)
1292 topo_hdl_strfree(thp, (char *)pip->tpi_name);
1293 topo_hdl_free(thp, pip, sizeof (topo_pgroup_info_t));
1294 }
1295
1296 topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
1297 }
1298 topo_node_unlock(node);
1299 }
1300
1301 static void
propmethod_destroy(topo_hdl_t * thp,topo_propval_t * pv)1302 propmethod_destroy(topo_hdl_t *thp, topo_propval_t *pv)
1303 {
1304 topo_propmethod_t *pm;
1305
1306 pm = pv->tp_method;
1307 if (pm != NULL) {
1308 if (pm->tpm_name != NULL)
1309 topo_hdl_strfree(thp, pm->tpm_name);
1310 if (pm->tpm_args != NULL)
1311 nvlist_free(pm->tpm_args);
1312 topo_hdl_free(thp, pm, sizeof (topo_propmethod_t));
1313 pv->tp_method = NULL;
1314 }
1315 }
1316
1317 static void
topo_propval_destroy(topo_propval_t * pv)1318 topo_propval_destroy(topo_propval_t *pv)
1319 {
1320 topo_hdl_t *thp;
1321
1322 if (pv == NULL)
1323 return;
1324
1325 thp = pv->tp_hdl;
1326
1327 if (pv->tp_name != NULL)
1328 topo_hdl_strfree(thp, pv->tp_name);
1329
1330 if (pv->tp_val != NULL)
1331 nvlist_free(pv->tp_val);
1332
1333 propmethod_destroy(thp, pv);
1334
1335 topo_hdl_free(thp, pv, sizeof (topo_propval_t));
1336 }
1337
1338 void
topo_prop_hold(topo_propval_t * pv)1339 topo_prop_hold(topo_propval_t *pv)
1340 {
1341 pv->tp_refs++;
1342 }
1343
1344 void
topo_prop_rele(topo_propval_t * pv)1345 topo_prop_rele(topo_propval_t *pv)
1346 {
1347 pv->tp_refs--;
1348
1349 assert(pv->tp_refs >= 0);
1350
1351 if (pv->tp_refs == 0)
1352 topo_propval_destroy(pv);
1353 }
1354
1355 /*
1356 * topo_prop_getprop() and topo_prop_getprops() are private project functions
1357 * for fmtopo
1358 */
1359 int
topo_prop_getprop(tnode_t * node,const char * pgname,const char * pname,nvlist_t * args,nvlist_t ** prop,int * err)1360 topo_prop_getprop(tnode_t *node, const char *pgname, const char *pname,
1361 nvlist_t *args, nvlist_t **prop, int *err)
1362 {
1363 topo_hdl_t *thp = node->tn_hdl;
1364 topo_propval_t *pv;
1365
1366 topo_node_lock(node);
1367 if ((pv = prop_get(node, pgname, pname, args, err)) == NULL) {
1368 (void) get_properror(node, err, *err);
1369 return (-1);
1370 }
1371
1372 if (topo_hdl_nvdup(thp, pv->tp_val, prop) != 0) {
1373 (void) get_properror(node, err, ETOPO_NOMEM);
1374 return (-1);
1375 }
1376 topo_node_unlock(node);
1377
1378 return (0);
1379 }
1380
1381 static int
prop_val_add(tnode_t * node,nvlist_t ** nvl,topo_propval_t * pv,int * err)1382 prop_val_add(tnode_t *node, nvlist_t **nvl, topo_propval_t *pv, int *err)
1383 {
1384 if (pv->tp_method != NULL)
1385 if (prop_method_get(node, pv, pv->tp_method, NULL, err) < 0)
1386 return (-1);
1387
1388 if (pv->tp_val == NULL) {
1389 *err = ETOPO_PROP_NOENT;
1390 return (-1);
1391 }
1392
1393 if (topo_hdl_nvdup(pv->tp_hdl, pv->tp_val, nvl) != 0) {
1394 *err = ETOPO_PROP_NOMEM;
1395 return (-1);
1396 }
1397
1398 return (0);
1399 }
1400
1401 static int
get_pgrp_seterror(tnode_t * node,nvlist_t * nvl,int * errp,int err)1402 get_pgrp_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err)
1403 {
1404 topo_node_unlock(node);
1405
1406 if (nvl != NULL)
1407 nvlist_free(nvl);
1408
1409 *errp = err;
1410
1411 return (-1);
1412 }
1413
1414 int
topo_prop_getpgrp(tnode_t * node,const char * pgname,nvlist_t ** pgrp,int * err)1415 topo_prop_getpgrp(tnode_t *node, const char *pgname, nvlist_t **pgrp,
1416 int *err)
1417 {
1418 int ret;
1419 topo_hdl_t *thp = node->tn_hdl;
1420 nvlist_t *nvl, *pvnvl;
1421 topo_pgroup_t *pg;
1422 topo_propval_t *pv;
1423 topo_proplist_t *pvl;
1424
1425 if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) {
1426 *err = ETOPO_NOMEM;
1427 return (-1);
1428 }
1429
1430 topo_node_lock(node);
1431 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
1432 pg = topo_list_next(pg)) {
1433
1434 if (strcmp(pgname, pg->tpg_info->tpi_name) != 0)
1435 continue;
1436
1437 if (nvlist_add_string(nvl, TOPO_PROP_GROUP_NAME,
1438 pg->tpg_info->tpi_name) != 0 ||
1439 nvlist_add_string(nvl, TOPO_PROP_GROUP_NSTAB,
1440 topo_stability2name(pg->tpg_info->tpi_namestab)) != 0 ||
1441 nvlist_add_string(nvl, TOPO_PROP_GROUP_DSTAB,
1442 topo_stability2name(pg->tpg_info->tpi_datastab)) != 0 ||
1443 nvlist_add_int32(nvl, TOPO_PROP_GROUP_VERSION,
1444 pg->tpg_info->tpi_version) != 0)
1445 return (get_pgrp_seterror(node, nvl, err,
1446 ETOPO_PROP_NVL));
1447
1448 for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
1449 pvl = topo_list_next(pvl)) {
1450
1451 pv = pvl->tp_pval;
1452 if (prop_val_add(node, &pvnvl, pv, err) < 0) {
1453 return (get_pgrp_seterror(node, nvl, err,
1454 *err));
1455 }
1456 if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_VAL,
1457 pvnvl)) != 0) {
1458 nvlist_free(pvnvl);
1459 return (get_pgrp_seterror(node, nvl, err, ret));
1460 }
1461
1462 nvlist_free(pvnvl);
1463 }
1464 topo_node_unlock(node);
1465 *pgrp = nvl;
1466 return (0);
1467 }
1468
1469 topo_node_unlock(node);
1470 *err = ETOPO_PROP_NOENT;
1471 return (-1);
1472 }
1473
1474 static nvlist_t *
get_all_seterror(tnode_t * node,nvlist_t * nvl,int * errp,int err)1475 get_all_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err)
1476 {
1477 topo_node_unlock(node);
1478
1479 if (nvl != NULL)
1480 nvlist_free(nvl);
1481
1482 *errp = err;
1483
1484 return (NULL);
1485 }
1486
1487 nvlist_t *
topo_prop_getprops(tnode_t * node,int * err)1488 topo_prop_getprops(tnode_t *node, int *err)
1489 {
1490 int ret;
1491 topo_hdl_t *thp = node->tn_hdl;
1492 nvlist_t *nvl, *pgnvl, *pvnvl;
1493 topo_pgroup_t *pg;
1494 topo_propval_t *pv;
1495 topo_proplist_t *pvl;
1496
1497 topo_node_lock(node);
1498 if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) {
1499 return (get_all_seterror(node, NULL, err, ETOPO_NOMEM));
1500 }
1501
1502 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
1503 pg = topo_list_next(pg)) {
1504 if (topo_hdl_nvalloc(thp, &pgnvl, 0) != 0)
1505 return (get_all_seterror(node, nvl, err, ETOPO_NOMEM));
1506
1507 if (nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NAME,
1508 pg->tpg_info->tpi_name) != 0 ||
1509 nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NSTAB,
1510 topo_stability2name(pg->tpg_info->tpi_namestab)) != 0 ||
1511 nvlist_add_string(pgnvl, TOPO_PROP_GROUP_DSTAB,
1512 topo_stability2name(pg->tpg_info->tpi_datastab)) != 0 ||
1513 nvlist_add_int32(pgnvl, TOPO_PROP_GROUP_VERSION,
1514 pg->tpg_info->tpi_version) != 0)
1515 return (get_all_seterror(node, nvl, err,
1516 ETOPO_PROP_NVL));
1517
1518 for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
1519 pvl = topo_list_next(pvl)) {
1520
1521 pv = pvl->tp_pval;
1522 if (prop_val_add(node, &pvnvl, pv, err) < 0) {
1523 nvlist_free(pgnvl);
1524 return (get_all_seterror(node, nvl, err, *err));
1525 }
1526 if ((ret = nvlist_add_nvlist(pgnvl, TOPO_PROP_VAL,
1527 pvnvl)) != 0) {
1528 nvlist_free(pgnvl);
1529 nvlist_free(pvnvl);
1530 return (get_all_seterror(node, nvl, err, ret));
1531 }
1532
1533 nvlist_free(pvnvl);
1534 }
1535 if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_GROUP, pgnvl))
1536 != 0) {
1537 nvlist_free(pgnvl);
1538 return (get_all_seterror(node, nvl, err, ret));
1539 }
1540
1541 nvlist_free(pgnvl);
1542 }
1543
1544 topo_node_unlock(node);
1545
1546 return (nvl);
1547 }
1548