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