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 /*
23 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2020 Joyent, Inc.
25 * Copyright 2026 Oxide Computer Company
26 */
27
28 #include <libxml/parser.h>
29 #include <libxml/xinclude.h>
30 #include <sys/fm/protocol.h>
31 #include <assert.h>
32 #include <string.h>
33 #include <strings.h>
34 #include <ctype.h>
35 #include <errno.h>
36 #include <limits.h>
37 #include <fm/libtopo.h>
38 #include <unistd.h>
39 #include <sys/stat.h>
40 #include <fcntl.h>
41 #include <topo_file.h>
42 #include <topo_mod.h>
43 #include <topo_subr.h>
44 #include <topo_alloc.h>
45 #include <topo_parse.h>
46 #include <topo_error.h>
47
48 static tf_rdata_t *topo_xml_walk(topo_mod_t *, tf_info_t *, xmlNodePtr,
49 tnode_t *);
50 static tf_edata_t *enum_attributes_process(topo_mod_t *, xmlNodePtr);
51 static int enum_run(topo_mod_t *, tf_rdata_t *);
52 static int fac_enum_run(topo_mod_t *, tnode_t *, const char *);
53 static int fac_process(topo_mod_t *, xmlNodePtr, tf_rdata_t *, tnode_t *);
54 static int fac_enum_process(topo_mod_t *, xmlNodePtr, tnode_t *);
55 static int decorate_nodes(topo_mod_t *, tf_rdata_t *, xmlNodePtr, tnode_t *,
56 tf_pad_t **);
57
58
59 int
xmlattr_to_stab(topo_mod_t * mp,xmlNodePtr n,const char * stabname,topo_stability_t * rs)60 xmlattr_to_stab(topo_mod_t *mp, xmlNodePtr n, const char *stabname,
61 topo_stability_t *rs)
62 {
63 xmlChar *str;
64 int rv = 0;
65
66 if (n == NULL) {
67 /* If there is no Stability defined, we default to private */
68 *rs = TOPO_STABILITY_PRIVATE;
69 return (0);
70 }
71 if ((str = xmlGetProp(n, (xmlChar *)stabname)) == NULL) {
72 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
73 "attribute to stability:\n");
74 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
75 }
76
77 if (xmlStrcmp(str, (xmlChar *)Internal) == 0) {
78 *rs = TOPO_STABILITY_INTERNAL;
79 } else if (xmlStrcmp(str, (xmlChar *)Private) == 0) {
80 *rs = TOPO_STABILITY_PRIVATE;
81 } else if (xmlStrcmp(str, (xmlChar *)Obsolete) == 0) {
82 *rs = TOPO_STABILITY_OBSOLETE;
83 } else if (xmlStrcmp(str, (xmlChar *)External) == 0) {
84 *rs = TOPO_STABILITY_EXTERNAL;
85 } else if (xmlStrcmp(str, (xmlChar *)Unstable) == 0) {
86 *rs = TOPO_STABILITY_UNSTABLE;
87 } else if (xmlStrcmp(str, (xmlChar *)Evolving) == 0) {
88 *rs = TOPO_STABILITY_EVOLVING;
89 } else if (xmlStrcmp(str, (xmlChar *)Stable) == 0) {
90 *rs = TOPO_STABILITY_STABLE;
91 } else if (xmlStrcmp(str, (xmlChar *)Standard) == 0) {
92 *rs = TOPO_STABILITY_STANDARD;
93 } else {
94 xmlFree(str);
95 return (topo_mod_seterrno(mp, ETOPO_PRSR_BADSTAB));
96 }
97 xmlFree(str);
98 return (rv);
99 }
100
101 int
xmlattr_to_int(topo_mod_t * mp,xmlNodePtr n,const char * propname,uint64_t * value)102 xmlattr_to_int(topo_mod_t *mp,
103 xmlNodePtr n, const char *propname, uint64_t *value)
104 {
105 xmlChar *str;
106 xmlChar *estr;
107
108 if ((str = xmlGetProp(n, (xmlChar *)propname)) == NULL) {
109 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
110 "%s: failed to lookup %s attribute", __func__, propname);
111 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
112 }
113 errno = 0;
114 *value = strtoull((char *)str, (char **)&estr, 0);
115 if (errno != 0 || *estr != '\0') {
116 /* no conversion was done */
117 xmlFree(str);
118 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
119 "%s: failed to convert %s attribute", __func__, propname);
120 return (topo_mod_seterrno(mp, ETOPO_PRSR_BADNUM));
121 }
122 xmlFree(str);
123 return (0);
124 }
125
126 int
xmlattr_to_double(topo_mod_t * mp,xmlNodePtr n,const char * propname,double * value)127 xmlattr_to_double(topo_mod_t *mp,
128 xmlNodePtr n, const char *propname, double *value)
129 {
130 xmlChar *str;
131 xmlChar *estr;
132
133 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
134 "xmlattr_to_double(propname=%s)\n", propname);
135 if ((str = xmlGetProp(n, (xmlChar *)propname)) == NULL)
136 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
137
138 errno = 0;
139 *value = strtold((char *)str, (char **)&estr);
140 if (errno != 0 || *estr != '\0') {
141 /* full or partial conversion failure */
142 xmlFree(str);
143 return (topo_mod_seterrno(mp, ETOPO_PRSR_BADNUM));
144 }
145 xmlFree(str);
146 return (0);
147 }
148
149 static int
xmlattr_to_fmri(topo_mod_t * mp,xmlNodePtr xn,const char * propname,nvlist_t ** rnvl)150 xmlattr_to_fmri(topo_mod_t *mp,
151 xmlNodePtr xn, const char *propname, nvlist_t **rnvl)
152 {
153 xmlChar *str;
154
155 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "xmlattr_to_fmri(propname=%s)\n",
156 propname);
157 if ((str = xmlGetProp(xn, (xmlChar *)propname)) == NULL)
158 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
159 if (topo_mod_str2nvl(mp, (const char *)str, rnvl) < 0) {
160 xmlFree(str);
161 return (-1);
162 }
163 xmlFree(str);
164 return (0);
165 }
166
167 static topo_type_t
xmlattr_to_type(topo_mod_t * mp,xmlNodePtr xn,xmlChar * attr)168 xmlattr_to_type(topo_mod_t *mp, xmlNodePtr xn, xmlChar *attr)
169 {
170 topo_type_t rv;
171 xmlChar *str;
172 if ((str = xmlGetProp(xn, (xmlChar *)attr)) == NULL) {
173 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "%s attribute missing",
174 attr);
175 (void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
176 return (TOPO_TYPE_INVALID);
177 }
178 if (xmlStrcmp(str, (xmlChar *)Int32) == 0) {
179 rv = TOPO_TYPE_INT32;
180 } else if (xmlStrcmp(str, (xmlChar *)UInt32) == 0) {
181 rv = TOPO_TYPE_UINT32;
182 } else if (xmlStrcmp(str, (xmlChar *)Int64) == 0) {
183 rv = TOPO_TYPE_INT64;
184 } else if (xmlStrcmp(str, (xmlChar *)UInt64) == 0) {
185 rv = TOPO_TYPE_UINT64;
186 } else if (xmlStrcmp(str, (xmlChar *)FMRI) == 0) {
187 rv = TOPO_TYPE_FMRI;
188 } else if (xmlStrcmp(str, (xmlChar *)String) == 0) {
189 rv = TOPO_TYPE_STRING;
190 } else if (xmlStrcmp(str, (xmlChar *)Double) == 0) {
191 rv = TOPO_TYPE_DOUBLE;
192 } else if (xmlStrcmp(str, (xmlChar *)Int32_Arr) == 0) {
193 rv = TOPO_TYPE_INT32_ARRAY;
194 } else if (xmlStrcmp(str, (xmlChar *)UInt32_Arr) == 0) {
195 rv = TOPO_TYPE_UINT32_ARRAY;
196 } else if (xmlStrcmp(str, (xmlChar *)Int64_Arr) == 0) {
197 rv = TOPO_TYPE_INT64_ARRAY;
198 } else if (xmlStrcmp(str, (xmlChar *)UInt64_Arr) == 0) {
199 rv = TOPO_TYPE_UINT64_ARRAY;
200 } else if (xmlStrcmp(str, (xmlChar *)String_Arr) == 0) {
201 rv = TOPO_TYPE_STRING_ARRAY;
202 } else if (xmlStrcmp(str, (xmlChar *)FMRI_Arr) == 0) {
203 rv = TOPO_TYPE_FMRI_ARRAY;
204 } else {
205 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
206 "Unrecognized type attribute value '%s'.\n", str);
207 (void) topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE);
208 xmlFree(str);
209 return (TOPO_TYPE_INVALID);
210 }
211 xmlFree(str);
212 return (rv);
213 }
214
215 static int
xlate_common(topo_mod_t * mp,xmlNodePtr xn,topo_type_t ptype,nvlist_t * nvl,const char * name)216 xlate_common(topo_mod_t *mp, xmlNodePtr xn, topo_type_t ptype, nvlist_t *nvl,
217 const char *name)
218 {
219 int rv = 0;
220 uint64_t ui;
221 double dbl;
222 uint_t i = 0, nelems = 0;
223 nvlist_t *fmri;
224 xmlChar *str;
225 char **strarrbuf;
226 void *arrbuf;
227 nvlist_t **nvlarrbuf;
228 xmlNodePtr cn;
229
230 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "xlate_common(name=%s)\n", name);
231 switch (ptype) {
232 case TOPO_TYPE_INT32:
233 if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
234 return (-1);
235 rv = nvlist_add_int32(nvl, name, (int32_t)ui);
236 break;
237 case TOPO_TYPE_UINT32:
238 if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
239 return (-1);
240 rv = nvlist_add_uint32(nvl, name, (uint32_t)ui);
241 break;
242 case TOPO_TYPE_INT64:
243 if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
244 return (-1);
245 rv = nvlist_add_int64(nvl, name, (int64_t)ui);
246 break;
247 case TOPO_TYPE_UINT64:
248 if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
249 return (-1);
250 rv = nvlist_add_uint64(nvl, name, ui);
251 break;
252 case TOPO_TYPE_DOUBLE:
253 if (xmlattr_to_double(mp, xn, Value, &dbl) < 0)
254 return (-1);
255 rv = nvlist_add_double(nvl, name, dbl);
256 break;
257 case TOPO_TYPE_FMRI:
258 if (xmlattr_to_fmri(mp, xn, Value, &fmri) < 0)
259 return (-1);
260 rv = nvlist_add_nvlist(nvl, name, fmri);
261 nvlist_free(fmri);
262 break;
263 case TOPO_TYPE_STRING:
264 if ((str = xmlGetProp(xn, (xmlChar *)Value)) == NULL)
265 return (-1);
266 rv = nvlist_add_string(nvl, name, (char *)str);
267 xmlFree(str);
268 break;
269 case TOPO_TYPE_INT32_ARRAY:
270 case TOPO_TYPE_UINT32_ARRAY:
271 case TOPO_TYPE_INT64_ARRAY:
272 case TOPO_TYPE_UINT64_ARRAY:
273 case TOPO_TYPE_STRING_ARRAY:
274 case TOPO_TYPE_FMRI_ARRAY:
275 for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next)
276 if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
277 (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0))
278 nelems++;
279
280 if (nelems < 1) {
281 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "No <propitem> "
282 "or <argitem> elements found for array val");
283 return (-1);
284 }
285 break;
286 default:
287 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
288 "Unrecognized type attribute (ptype = %d)\n", ptype);
289 return (topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE));
290 }
291
292 switch (ptype) {
293 case TOPO_TYPE_INT32_ARRAY:
294 if ((arrbuf = topo_mod_alloc(mp, (nelems * sizeof (int32_t))))
295 == NULL)
296 return (topo_mod_seterrno(mp, ETOPO_NOMEM));
297 for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
298 if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
299 (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
300
301 if (xmlattr_to_int(mp, cn, Value, &ui) < 0)
302 return (-1);
303 ((int32_t *)arrbuf)[i++] = (int32_t)ui;
304 }
305 }
306
307 rv = nvlist_add_int32_array(nvl, name, (int32_t *)arrbuf,
308 nelems);
309 topo_mod_free(mp, arrbuf, (nelems * sizeof (int32_t)));
310 break;
311 case TOPO_TYPE_UINT32_ARRAY:
312 if ((arrbuf = topo_mod_alloc(mp, (nelems * sizeof (uint32_t))))
313 == NULL)
314 return (topo_mod_seterrno(mp, ETOPO_NOMEM));
315 for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
316 if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
317 (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
318
319 if (xmlattr_to_int(mp, cn, Value, &ui) < 0)
320 return (-1);
321 ((uint32_t *)arrbuf)[i++] = (uint32_t)ui;
322 }
323 }
324
325 rv = nvlist_add_uint32_array(nvl, name, (uint32_t *)arrbuf,
326 nelems);
327 topo_mod_free(mp, arrbuf, (nelems * sizeof (uint32_t)));
328 break;
329 case TOPO_TYPE_INT64_ARRAY:
330 if ((arrbuf = topo_mod_alloc(mp, (nelems * sizeof (int64_t))))
331 == NULL)
332 return (topo_mod_seterrno(mp, ETOPO_NOMEM));
333 for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
334 if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
335 (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
336
337 if (xmlattr_to_int(mp, cn, Value, &ui) < 0)
338 return (-1);
339 ((int64_t *)arrbuf)[i++] = (int64_t)ui;
340 }
341 }
342
343 rv = nvlist_add_int64_array(nvl, name, (int64_t *)arrbuf,
344 nelems);
345 topo_mod_free(mp, arrbuf, (nelems * sizeof (int64_t)));
346 break;
347 case TOPO_TYPE_UINT64_ARRAY:
348 if ((arrbuf = topo_mod_alloc(mp, (nelems * sizeof (uint64_t))))
349 == NULL)
350 return (topo_mod_seterrno(mp, ETOPO_NOMEM));
351 for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
352 if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
353 (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
354
355 if (xmlattr_to_int(mp, cn, Value, &ui) < 0)
356 return (-1);
357 ((uint64_t *)arrbuf)[i++] = ui;
358 }
359 }
360
361 rv = nvlist_add_uint64_array(nvl, name, arrbuf,
362 nelems);
363 topo_mod_free(mp, arrbuf, (nelems * sizeof (uint64_t)));
364 break;
365 case TOPO_TYPE_STRING_ARRAY:
366 if ((strarrbuf = topo_mod_alloc(mp, (nelems * sizeof (char *))))
367 == NULL)
368 return (topo_mod_seterrno(mp, ETOPO_NOMEM));
369 for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
370 if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
371 (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
372
373 if ((str = xmlGetProp(cn, (xmlChar *)Value))
374 == NULL)
375 return (-1);
376
377 strarrbuf[i++] =
378 topo_mod_strdup(mp, (const char *)str);
379 xmlFree(str);
380 }
381 }
382
383 rv = nvlist_add_string_array(nvl, name, strarrbuf, nelems);
384 topo_mod_strfreev(mp, strarrbuf, nelems);
385 break;
386 case TOPO_TYPE_FMRI_ARRAY:
387 if ((nvlarrbuf = topo_mod_alloc(mp, (nelems *
388 sizeof (nvlist_t *)))) == NULL)
389 return (topo_mod_seterrno(mp, ETOPO_NOMEM));
390 for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
391 if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
392 (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
393
394 if ((str = xmlGetProp(cn, (xmlChar *)Value))
395 == NULL)
396 return (-1);
397
398 if (topo_mod_str2nvl(mp, (const char *)str,
399 &(nvlarrbuf[i++])) < 0) {
400 xmlFree(str);
401 return (-1);
402 }
403 xmlFree(str);
404 }
405 }
406
407 rv = nvlist_add_nvlist_array(nvl, name, nvlarrbuf,
408 nelems);
409 topo_mod_free(mp, nvlarrbuf, (nelems * sizeof (nvlist_t *)));
410 break;
411 default:
412 /*
413 * Invalid types were handled in the switch statement above
414 * this. Items in this case don't need additional processing.
415 */
416 break;
417 }
418
419 if (rv != 0) {
420 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
421 "Nvlist construction failed.\n");
422 return (topo_mod_seterrno(mp, ETOPO_NOMEM));
423 } else
424 return (0);
425 }
426
427 static int
xmlprop_xlate(topo_mod_t * mp,xmlNodePtr xn,nvlist_t * nvl)428 xmlprop_xlate(topo_mod_t *mp, xmlNodePtr xn, nvlist_t *nvl)
429 {
430 topo_type_t ptype;
431 xmlChar *str;
432
433 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "xmlprop_xlate\n");
434 if ((str = xmlGetProp(xn, (xmlChar *)Immutable)) != NULL) {
435 if (xmlStrcmp(str, (xmlChar *)False) == 0)
436 (void) nvlist_add_boolean_value(nvl, INV_IMMUTE,
437 B_FALSE);
438 else
439 (void) nvlist_add_boolean_value(nvl, INV_IMMUTE,
440 B_TRUE);
441 xmlFree(str);
442 } else {
443 (void) nvlist_add_boolean_value(nvl, INV_IMMUTE, B_TRUE);
444 }
445
446 if ((ptype = xmlattr_to_type(mp, xn, (xmlChar *)Type))
447 == TOPO_TYPE_INVALID)
448 return (-1);
449
450 if (nvlist_add_int32(nvl, INV_PVALTYPE, ptype) != 0)
451 return (-1);
452
453 return (xlate_common(mp, xn, ptype, nvl, INV_PVAL));
454 }
455
456 static int
dependent_create(topo_mod_t * mp,tf_info_t * xinfo,tf_pad_t * pad,xmlNodePtr dxn,tnode_t * ptn)457 dependent_create(topo_mod_t *mp,
458 tf_info_t *xinfo, tf_pad_t *pad, xmlNodePtr dxn, tnode_t *ptn)
459 {
460 tf_rdata_t *rp, *pp, *np;
461 xmlChar *grptype;
462 int sibs = 0;
463
464 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "dependent_create\n");
465 if ((grptype = xmlGetProp(dxn, (xmlChar *)Grouping)) == NULL) {
466 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
467 "Dependents missing grouping attribute");
468 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
469 }
470
471 pp = NULL;
472 if (xmlStrcmp(grptype, (xmlChar *)Siblings) == 0) {
473 rp = pad->tpad_sibs;
474 sibs++;
475 } else if (xmlStrcmp(grptype, (xmlChar *)Children) == 0) {
476 rp = pad->tpad_child;
477 } else {
478 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
479 "Dependents have bogus grouping attribute");
480 xmlFree(grptype);
481 return (topo_mod_seterrno(mp, ETOPO_PRSR_BADGRP));
482 }
483 xmlFree(grptype);
484 /* Add processed dependents to the tail of the list */
485 while (rp != NULL) {
486 pp = rp;
487 rp = rp->rd_next;
488 }
489 if ((np = topo_xml_walk(mp, xinfo, dxn, ptn)) == NULL) {
490 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
491 "error within dependent .xml topology: "
492 "%s\n", topo_strerror(topo_mod_errno(mp)));
493 return (-1);
494 }
495 if (pp != NULL)
496 pp->rd_next = np;
497 else if (sibs == 1)
498 pad->tpad_sibs = np;
499 else
500 pad->tpad_child = np;
501 return (0);
502 }
503
504 static int
dependents_create(topo_mod_t * mp,tf_info_t * xinfo,tf_pad_t * pad,xmlNodePtr pxn,tnode_t * ptn)505 dependents_create(topo_mod_t *mp,
506 tf_info_t *xinfo, tf_pad_t *pad, xmlNodePtr pxn, tnode_t *ptn)
507 {
508 xmlNodePtr cn;
509
510 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "dependents_create\n");
511 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
512 if (xmlStrcmp(cn->name, (xmlChar *)Dependents) == 0) {
513 if (dependent_create(mp, xinfo, pad, cn, ptn) < 0)
514 return (-1);
515 }
516 }
517 return (0);
518 }
519
520 static int
prop_create(topo_mod_t * mp,nvlist_t * pfmri,tnode_t * ptn,const char * gnm,const char * pnm,topo_type_t ptype,int flag)521 prop_create(topo_mod_t *mp,
522 nvlist_t *pfmri, tnode_t *ptn, const char *gnm, const char *pnm,
523 topo_type_t ptype, int flag)
524 {
525 nvlist_t *fmri, **fmriarr;
526 uint32_t ui32, *ui32arr;
527 uint64_t ui64, *ui64arr;
528 int32_t i32, *i32arr;
529 int64_t i64, *i64arr;
530 double dbl;
531 uint_t nelem;
532 char *str, **strarr;
533 int err, e;
534
535 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "prop_create(pgrp = %s, "
536 "prop = %s)\n", gnm, pnm);
537 switch (ptype) {
538 case TOPO_TYPE_INT32:
539 e = nvlist_lookup_int32(pfmri, INV_PVAL, &i32);
540 break;
541 case TOPO_TYPE_UINT32:
542 e = nvlist_lookup_uint32(pfmri, INV_PVAL, &ui32);
543 break;
544 case TOPO_TYPE_INT64:
545 e = nvlist_lookup_int64(pfmri, INV_PVAL, &i64);
546 break;
547 case TOPO_TYPE_UINT64:
548 e = nvlist_lookup_uint64(pfmri, INV_PVAL, &ui64);
549 break;
550 case TOPO_TYPE_DOUBLE:
551 e = nvlist_lookup_double(pfmri, INV_PVAL, &dbl);
552 break;
553 case TOPO_TYPE_FMRI:
554 e = nvlist_lookup_nvlist(pfmri, INV_PVAL, &fmri);
555 break;
556 case TOPO_TYPE_STRING:
557 e = nvlist_lookup_string(pfmri, INV_PVAL, &str);
558 break;
559 case TOPO_TYPE_INT32_ARRAY:
560 e = nvlist_lookup_int32_array(pfmri, INV_PVAL, &i32arr, &nelem);
561 break;
562 case TOPO_TYPE_UINT32_ARRAY:
563 e = nvlist_lookup_uint32_array(pfmri, INV_PVAL, &ui32arr,
564 &nelem);
565 break;
566 case TOPO_TYPE_INT64_ARRAY:
567 e = nvlist_lookup_int64_array(pfmri, INV_PVAL, &i64arr,
568 &nelem);
569 break;
570 case TOPO_TYPE_UINT64_ARRAY:
571 e = nvlist_lookup_uint64_array(pfmri, INV_PVAL, &ui64arr,
572 &nelem);
573 break;
574 case TOPO_TYPE_STRING_ARRAY:
575 e = nvlist_lookup_string_array(pfmri, INV_PVAL, &strarr,
576 &nelem);
577 break;
578 case TOPO_TYPE_FMRI_ARRAY:
579 e = nvlist_lookup_nvlist_array(pfmri, INV_PVAL, &fmriarr,
580 &nelem);
581 break;
582 default:
583 e = ETOPO_PRSR_BADTYPE;
584 break;
585 }
586 if (e != 0) {
587 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
588 "prop_create: prop value lookup failed.\n");
589 return (topo_mod_seterrno(mp, e));
590 }
591 switch (ptype) {
592 case TOPO_TYPE_INT32:
593 e = topo_prop_set_int32(ptn, gnm, pnm, flag, i32, &err);
594 break;
595 case TOPO_TYPE_UINT32:
596 e = topo_prop_set_uint32(ptn, gnm, pnm, flag, ui32, &err);
597 break;
598 case TOPO_TYPE_INT64:
599 e = topo_prop_set_int64(ptn, gnm, pnm, flag, i64, &err);
600 break;
601 case TOPO_TYPE_UINT64:
602 e = topo_prop_set_uint64(ptn, gnm, pnm, flag, ui64, &err);
603 break;
604 case TOPO_TYPE_DOUBLE:
605 e = topo_prop_set_double(ptn, gnm, pnm, flag, dbl, &err);
606 break;
607 case TOPO_TYPE_FMRI:
608 e = topo_prop_set_fmri(ptn, gnm, pnm, flag, fmri, &err);
609 break;
610 case TOPO_TYPE_STRING:
611 e = topo_prop_set_string(ptn, gnm, pnm, flag, str, &err);
612 break;
613 case TOPO_TYPE_INT32_ARRAY:
614 e = topo_prop_set_int32_array(ptn, gnm, pnm, flag, i32arr,
615 nelem, &err);
616 break;
617 case TOPO_TYPE_UINT32_ARRAY:
618 e = topo_prop_set_uint32_array(ptn, gnm, pnm, flag, ui32arr,
619 nelem, &err);
620 break;
621 case TOPO_TYPE_INT64_ARRAY:
622 e = topo_prop_set_int64_array(ptn, gnm, pnm, flag, i64arr,
623 nelem, &err);
624 break;
625 case TOPO_TYPE_UINT64_ARRAY:
626 e = topo_prop_set_uint64_array(ptn, gnm, pnm, flag, ui64arr,
627 nelem, &err);
628 break;
629 case TOPO_TYPE_STRING_ARRAY:
630 e = topo_prop_set_string_array(ptn, gnm, pnm, flag,
631 (const char **)strarr, nelem, &err);
632 break;
633 case TOPO_TYPE_FMRI_ARRAY:
634 e = topo_prop_set_fmri_array(ptn, gnm, pnm, flag,
635 (const nvlist_t **)fmriarr, nelem, &err);
636 break;
637 default:
638 e = ETOPO_PRSR_BADTYPE;
639 break;
640 }
641 if (e != 0 && err != ETOPO_PROP_DEFD) {
642
643 /*
644 * Some properties may have already been set
645 * in topo_node_bind() or topo_prop_inherit if we are
646 * enumerating from a static .xml file
647 */
648 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "prop set "
649 "failed %s/%s:%s\n", gnm, pnm, topo_strerror(err));
650 return (topo_mod_seterrno(mp, err));
651 }
652 return (0);
653 }
654
655 static int
props_create(topo_mod_t * mp,tnode_t * ptn,const char * gnm,nvlist_t ** props,int nprops)656 props_create(topo_mod_t *mp,
657 tnode_t *ptn, const char *gnm, nvlist_t **props, int nprops)
658 {
659 topo_type_t ptype;
660 boolean_t pim;
661 char *pnm;
662 int32_t i32;
663 int flag;
664 int pn;
665 int e;
666
667 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "props_create(pgrp = %s)\n",
668 gnm);
669 for (pn = 0; pn < nprops; pn++) {
670 e = nvlist_lookup_string(props[pn], INV_PNAME, &pnm);
671 if (e != 0) {
672 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
673 "props create lookup (%s) failure: %s",
674 INV_PNAME, strerror(e));
675 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
676 }
677 e = nvlist_lookup_boolean_value(props[pn], INV_IMMUTE, &pim);
678 if (e != 0) {
679 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
680 "props create lookup (%s) failure: %s",
681 INV_IMMUTE, strerror(e));
682 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
683 }
684 flag = (pim == B_TRUE) ?
685 TOPO_PROP_IMMUTABLE : TOPO_PROP_MUTABLE;
686
687 e = nvlist_lookup_int32(props[pn], INV_PVALTYPE, &i32);
688 if (e != 0) {
689 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
690 "props create lookup (%s) failure: %s",
691 INV_PVALTYPE, strerror(e));
692 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
693 }
694 ptype = (topo_type_t)i32;
695 if (prop_create(mp, props[pn], ptn, gnm, pnm, ptype, flag) < 0)
696 return (-1);
697 }
698 return (0);
699 }
700
701 static int
pgroups_create(topo_mod_t * mp,tf_pad_t * pad,tnode_t * ptn)702 pgroups_create(topo_mod_t *mp, tf_pad_t *pad, tnode_t *ptn)
703 {
704 topo_pgroup_info_t pgi;
705 nvlist_t **props;
706 char *gnm;
707 char *nmstab, *dstab;
708 uint32_t rnprops, nprops;
709 uint32_t gv;
710 int pg;
711 int e;
712
713 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroups_create: %s=%d\n",
714 topo_node_name(ptn), topo_node_instance(ptn));
715 for (pg = 0; pg < pad->tpad_pgcnt; pg++) {
716 e = nvlist_lookup_string(pad->tpad_pgs[pg],
717 INV_PGRP_NAME, &gnm);
718 if (e != 0) {
719 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
720 "pad lookup (%s) failed (%s).\n",
721 INV_PGRP_NAME, strerror(errno));
722 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
723 }
724 e = nvlist_lookup_string(pad->tpad_pgs[pg],
725 INV_PGRP_NMSTAB, &nmstab);
726 if (e != 0) {
727 if (e != ENOENT) {
728 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
729 "pad lookup (%s) "
730 "failed.\n", INV_PGRP_NMSTAB);
731 return (topo_mod_seterrno(mp,
732 ETOPO_PRSR_NVPROP));
733 } else {
734 nmstab = TOPO_STABSTR_PRIVATE;
735 }
736 }
737 e = nvlist_lookup_string(pad->tpad_pgs[pg],
738 INV_PGRP_DSTAB, &dstab);
739 if (e != 0) {
740 if (e != ENOENT) {
741 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
742 "pad lookup (%s) failed.\n",
743 INV_PGRP_DSTAB);
744 return (topo_mod_seterrno(mp,
745 ETOPO_PRSR_NVPROP));
746 } else {
747 dstab = TOPO_STABSTR_PRIVATE;
748 }
749 }
750 e = nvlist_lookup_uint32(pad->tpad_pgs[pg],
751 INV_PGRP_VER, &gv);
752 if (e != 0) {
753 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
754 "pad lookup (%s) failed.\n",
755 INV_PGRP_VER);
756 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
757 }
758 pgi.tpi_name = gnm;
759 pgi.tpi_namestab = topo_name2stability(nmstab);
760 pgi.tpi_datastab = topo_name2stability(dstab);
761 pgi.tpi_version = gv;
762 if (topo_pgroup_create(ptn, &pgi, &e) != 0) {
763 if (e != ETOPO_PROP_DEFD) {
764 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
765 "pgroups create failure: %s\n",
766 topo_strerror(e));
767 return (-1);
768 }
769 }
770 e = nvlist_lookup_uint32(pad->tpad_pgs[pg],
771 INV_PGRP_NPROP, &rnprops);
772 /*
773 * The number of properties could be zero if the property
774 * group only contains propmethod declarations
775 */
776 if (rnprops > 0) {
777 e |= nvlist_lookup_nvlist_array(pad->tpad_pgs[pg],
778 INV_PGRP_ALLPROPS, &props, &nprops);
779 if (rnprops != nprops) {
780 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
781 "recorded number of props %d does not "
782 "match number of props recorded %d.\n",
783 rnprops, nprops);
784 }
785 if (props_create(mp, ptn, gnm, props, nprops) < 0)
786 return (-1);
787 }
788 }
789 return (0);
790 }
791
792 static nvlist_t *
pval_record(topo_mod_t * mp,xmlNodePtr xn)793 pval_record(topo_mod_t *mp, xmlNodePtr xn)
794 {
795 nvlist_t *pnvl = NULL;
796 xmlChar *pname;
797
798 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pval_record\n");
799 if ((pname = xmlGetProp(xn, (xmlChar *)Name)) == NULL) {
800 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
801 "propval lacks a name\n");
802 (void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
803 return (NULL);
804 }
805 if (topo_mod_nvalloc(mp, &pnvl, NV_UNIQUE_NAME) < 0) {
806 xmlFree(pname);
807 return (NULL);
808 }
809 if (nvlist_add_string(pnvl, INV_PNAME, (char *)pname) < 0) {
810 xmlFree(pname);
811 nvlist_free(pnvl);
812 return (NULL);
813 }
814 xmlFree(pname);
815 /* FMXXX stability of the property name */
816
817 if (xmlprop_xlate(mp, xn, pnvl) < 0) {
818 nvlist_free(pnvl);
819 return (NULL);
820 }
821 return (pnvl);
822 }
823
824
825 struct propmeth_data {
826 const char *pg_name;
827 const char *prop_name;
828 topo_type_t prop_type;
829 const char *meth_name;
830 topo_version_t meth_ver;
831 nvlist_t *arg_nvl;
832 };
833
834 static int
register_method(topo_mod_t * mp,tnode_t * ptn,struct propmeth_data * meth)835 register_method(topo_mod_t *mp, tnode_t *ptn, struct propmeth_data *meth)
836 {
837 int err;
838
839 if (topo_prop_method_version_register(ptn, meth->pg_name,
840 meth->prop_name, meth->prop_type, meth->meth_name, meth->meth_ver,
841 meth->arg_nvl, &err) != 0) {
842
843 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "failed to register "
844 "propmethod %s for property \"%s\" in propgrp %s on node "
845 "%s=%d (%s)\n",
846 meth->meth_name, meth->prop_name, meth->pg_name,
847 topo_node_name(ptn), topo_node_instance(ptn),
848 topo_strerror(err));
849 return (-1);
850 }
851 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
852 "registered method %s on %s=%d\n",
853 meth->meth_name, topo_node_name(ptn), topo_node_instance(ptn));
854
855 return (0);
856 }
857
858 static int
pmeth_record(topo_mod_t * mp,const char * pg_name,xmlNodePtr xn,tnode_t * tn,const char * rname,const char * ppgrp_name)859 pmeth_record(topo_mod_t *mp, const char *pg_name, xmlNodePtr xn, tnode_t *tn,
860 const char *rname, const char *ppgrp_name)
861 {
862 nvlist_t *arg_nvl = NULL;
863 xmlNodePtr cn;
864 xmlChar *meth_name = NULL, *prop_name = NULL;
865 xmlChar *arg_name = NULL;
866 uint64_t meth_ver, is_mutable = 0, is_nonvolatile = 0;
867 topo_type_t prop_type;
868 struct propmeth_data meth;
869 int ret = 0, err;
870 topo_type_t ptype;
871 tnode_t *tmp;
872
873 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pmeth_record: %s=%d "
874 "(pgrp=%s)\n", topo_node_name(tn), topo_node_instance(tn), pg_name);
875
876 /*
877 * Get propmethod attribute values
878 */
879 if ((meth_name = xmlGetProp(xn, (xmlChar *)Name)) == NULL) {
880 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
881 "propmethod element lacks a name attribute\n");
882 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
883 }
884 if (xmlattr_to_int(mp, xn, Version, &meth_ver) < 0) {
885 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
886 "propmethod element lacks version attribute\n");
887 ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
888 goto pmr_done;
889 }
890 /*
891 * The "mutable" and "nonvoltile" attributes are optional. If not
892 * specified we default to false (0)
893 */
894 (void) xmlattr_to_int(mp, xn, Mutable, &is_mutable);
895 (void) xmlattr_to_int(mp, xn, Nonvolatile, &is_nonvolatile);
896
897 if ((prop_name = xmlGetProp(xn, (xmlChar *)Propname)) == NULL) {
898 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
899 "propmethod element lacks propname attribute\n");
900 ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
901 goto pmr_done;
902 }
903 if ((prop_type = xmlattr_to_type(mp, xn, (xmlChar *)Proptype))
904 == TOPO_TYPE_INVALID) {
905 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
906 "error decoding proptype attribute\n");
907 ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
908 goto pmr_done;
909 }
910
911 /*
912 * Allocate method argument nvlist
913 */
914 if (topo_mod_nvalloc(mp, &arg_nvl, NV_UNIQUE_NAME) < 0) {
915 ret = topo_mod_seterrno(mp, ETOPO_NOMEM);
916 goto pmr_done;
917 }
918
919 /*
920 * Iterate through the argval nodes and build the argval nvlist
921 */
922 for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
923 if (xmlStrcmp(cn->name, (xmlChar *)Argval) == 0) {
924 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
925 "found argval element\n");
926 if ((arg_name = xmlGetProp(cn, (xmlChar *)Name))
927 == NULL) {
928 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
929 "argval element lacks a name attribute\n");
930 ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
931 goto pmr_done;
932 }
933 if ((ptype = xmlattr_to_type(mp, cn, (xmlChar *)Type))
934 == TOPO_TYPE_INVALID) {
935 ret = topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE);
936 xmlFree(arg_name);
937 break;
938 }
939 if (xlate_common(mp, cn, ptype, arg_nvl,
940 (const char *)arg_name) != 0) {
941 ret = topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE);
942 xmlFree(arg_name);
943 break;
944 }
945 }
946 if (arg_name) {
947 xmlFree(arg_name);
948 arg_name = NULL;
949 }
950 }
951
952 if (ret != 0)
953 goto pmr_done;
954
955 /*
956 * Register the prop method for all of the nodes in our range
957 */
958 meth.pg_name = (const char *)pg_name;
959 meth.prop_name = (const char *)prop_name;
960 meth.prop_type = prop_type;
961 meth.meth_name = (const char *)meth_name;
962 meth.meth_ver = meth_ver;
963 meth.arg_nvl = arg_nvl;
964
965 /*
966 * If the propgroup element is under a range element, we'll apply
967 * the method to all of the topo nodes at this level with the same
968 * range name.
969 *
970 * Otherwise, if the propgroup element is under a node element
971 * then we'll simply register the method for this node.
972 */
973 if (strcmp(ppgrp_name, Range) == 0) {
974 for (tmp = tn; tmp != NULL; tmp = topo_child_next(NULL, tmp)) {
975 if (strcmp(rname, topo_node_name(tmp)) == 0) {
976 if (register_method(mp, tmp, &meth) != 0) {
977 ret = topo_mod_seterrno(mp,
978 ETOPO_PRSR_REGMETH);
979 goto pmr_done;
980 }
981 if (is_mutable) {
982 if (topo_prop_setmutable(tmp,
983 meth.pg_name, meth.prop_name, &err)
984 != 0) {
985 ret = topo_mod_seterrno(mp,
986 ETOPO_PRSR_REGMETH);
987 goto pmr_done;
988 }
989 }
990 if (is_nonvolatile) {
991 if (topo_prop_setnonvolatile(tmp,
992 meth.pg_name, meth.prop_name, &err)
993 != 0) {
994 ret = topo_mod_seterrno(mp,
995 ETOPO_PRSR_REGMETH);
996 goto pmr_done;
997 }
998 }
999 }
1000 }
1001 } else {
1002 if (register_method(mp, tn, &meth) != 0) {
1003 ret = topo_mod_seterrno(mp, ETOPO_PRSR_REGMETH);
1004 goto pmr_done;
1005 }
1006 if (is_mutable) {
1007 if (topo_prop_setmutable(tn, meth.pg_name,
1008 meth.prop_name, &err) != 0) {
1009 ret = topo_mod_seterrno(mp,
1010 ETOPO_PRSR_REGMETH);
1011 goto pmr_done;
1012 }
1013 }
1014 if (is_nonvolatile) {
1015 if (topo_prop_setnonvolatile(tn, meth.pg_name,
1016 meth.prop_name, &err) != 0) {
1017 ret = topo_mod_seterrno(mp,
1018 ETOPO_PRSR_REGMETH);
1019 goto pmr_done;
1020 }
1021 }
1022 }
1023
1024 pmr_done:
1025 if (meth_name)
1026 xmlFree(meth_name);
1027 if (prop_name)
1028 xmlFree(prop_name);
1029 nvlist_free(arg_nvl);
1030 return (ret);
1031 }
1032
1033
1034 static int
pgroup_record(topo_mod_t * mp,xmlNodePtr pxn,tnode_t * tn,const char * rname,tf_pad_t * rpad,int pi,const char * ppgrp_name)1035 pgroup_record(topo_mod_t *mp, xmlNodePtr pxn, tnode_t *tn, const char *rname,
1036 tf_pad_t *rpad, int pi, const char *ppgrp_name)
1037 {
1038 topo_stability_t nmstab, dstab;
1039 uint64_t ver;
1040 xmlNodePtr cn;
1041 xmlChar *name;
1042 nvlist_t **apl = NULL;
1043 nvlist_t *pgnvl = NULL;
1044 int pcnt = 0;
1045 int ai = 0;
1046 int e;
1047
1048 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroup_record\n");
1049 if ((name = xmlGetProp(pxn, (xmlChar *)Name)) == NULL) {
1050 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1051 "propgroup lacks a name\n");
1052 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
1053 }
1054 if (xmlattr_to_int(mp, pxn, Version, &ver) < 0) {
1055 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1056 "propgroup lacks a version\n");
1057 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
1058 }
1059 if (xmlattr_to_stab(mp, pxn, Namestab, &nmstab) < 0) {
1060 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1061 "propgroup lacks name-stability\n");
1062 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
1063 }
1064 if (xmlattr_to_stab(mp, pxn, Datastab, &dstab) < 0) {
1065 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1066 "propgroup lacks data-stability\n");
1067 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
1068 }
1069
1070 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroup %s\n", (char *)name);
1071 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
1072 if (xmlStrcmp(cn->name, (xmlChar *)Propval) == 0)
1073 pcnt++;
1074 }
1075
1076 if (topo_mod_nvalloc(mp, &pgnvl, NV_UNIQUE_NAME) < 0) {
1077 xmlFree(name);
1078 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1079 "failed to allocate propgroup nvlist\n");
1080 return (topo_mod_seterrno(mp, ETOPO_NOMEM));
1081 }
1082
1083 e = nvlist_add_string(pgnvl, INV_PGRP_NAME, (char *)name);
1084 e |= nvlist_add_uint32(pgnvl, INV_PGRP_NMSTAB, nmstab);
1085 e |= nvlist_add_uint32(pgnvl, INV_PGRP_DSTAB, dstab);
1086 e |= nvlist_add_uint32(pgnvl, INV_PGRP_VER, ver);
1087 e |= nvlist_add_uint32(pgnvl, INV_PGRP_NPROP, pcnt);
1088 if (pcnt > 0)
1089 if (e != 0 ||
1090 (apl = topo_mod_zalloc(mp, pcnt * sizeof (nvlist_t *)))
1091 == NULL) {
1092 xmlFree(name);
1093 nvlist_free(pgnvl);
1094 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1095 "failed to allocate nvlist array for properties"
1096 "(e=%d)\n", e);
1097 return (topo_mod_seterrno(mp, ETOPO_NOMEM));
1098 }
1099 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
1100 if (xmlStrcmp(cn->name, (xmlChar *)Propval) == 0) {
1101 if (ai < pcnt) {
1102 if ((apl[ai] = pval_record(mp, cn)) == NULL)
1103 break;
1104 }
1105 ai++;
1106 } else if (xmlStrcmp(cn->name, (xmlChar *)Prop_meth) == 0) {
1107 if (pmeth_record(mp, (const char *)name, cn, tn, rname,
1108 ppgrp_name) < 0)
1109 break;
1110 }
1111 }
1112 xmlFree(name);
1113 if (pcnt > 0) {
1114 e |= (ai != pcnt);
1115 e |= nvlist_add_nvlist_array(pgnvl, INV_PGRP_ALLPROPS, apl,
1116 pcnt);
1117 for (ai = 0; ai < pcnt; ai++)
1118 nvlist_free(apl[ai]);
1119 topo_mod_free(mp, apl, pcnt * sizeof (nvlist_t *));
1120 if (e != 0) {
1121 nvlist_free(pgnvl);
1122 return (-1);
1123 }
1124 }
1125 rpad->tpad_pgs[pi] = pgnvl;
1126 return (0);
1127 }
1128
1129 static int
pgroups_record(topo_mod_t * mp,xmlNodePtr pxn,tnode_t * tn,const char * rname,tf_pad_t * rpad,const char * ppgrp)1130 pgroups_record(topo_mod_t *mp, xmlNodePtr pxn, tnode_t *tn, const char *rname,
1131 tf_pad_t *rpad, const char *ppgrp)
1132 {
1133 xmlNodePtr cn;
1134 int pi = 0;
1135
1136 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroups_record: pxn->name=%s\n",
1137 pxn->name);
1138 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
1139 if (xmlStrcmp(cn->name, (xmlChar *)Propgrp) == 0) {
1140 if (pgroup_record(mp, cn, tn, rname, rpad, pi++, ppgrp)
1141 < 0)
1142 return (-1);
1143 }
1144 }
1145 return (0);
1146 }
1147
1148 /*
1149 * psn: pointer to a "set" XML node
1150 * key: string to search the set for
1151 *
1152 * returns: 1, if the set contains key
1153 * 0, otherwise
1154 */
1155 static int
set_contains(topo_mod_t * mp,char * key,char * set)1156 set_contains(topo_mod_t *mp, char *key, char *set)
1157 {
1158 char *prod;
1159 int rv = 0;
1160
1161 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "set_contains(key = %s, "
1162 "setlist = %s)\n", key, set);
1163
1164 prod = strtok((char *)set, "|");
1165 if (prod && (strcmp(key, prod) == 0))
1166 return (1);
1167
1168 while ((prod = strtok(NULL, "|")))
1169 if (strcmp(key, prod) == 0)
1170 return (1);
1171
1172 return (rv);
1173 }
1174
1175
1176 /*
1177 * Process the property group and dependents xmlNode children of
1178 * parent xmlNode pxn.
1179 */
1180 static int
pad_process(topo_mod_t * mp,tf_rdata_t * rd,xmlNodePtr pxn,tnode_t * ptn,tf_pad_t ** rpad)1181 pad_process(topo_mod_t *mp, tf_rdata_t *rd, xmlNodePtr pxn, tnode_t *ptn,
1182 tf_pad_t **rpad)
1183 {
1184 xmlNodePtr cn, gcn, psn = NULL, target;
1185 /* Explicitly initialize ecn to help -Wmaybe-unit */
1186 xmlNodePtr def_set = NULL, ecn = NULL;
1187 tnode_t *ct;
1188 tf_pad_t *new = *rpad;
1189 tf_rdata_t tmp_rd;
1190 int pgcnt = 0;
1191 int dcnt = 0;
1192 int ecnt = 0;
1193 int joined_set = 0, inst;
1194 xmlChar *set;
1195 char *key;
1196
1197 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1198 "pad_process beneath %s=%d\n", topo_node_name(ptn),
1199 topo_node_instance(ptn));
1200 if (new == NULL) {
1201 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
1202 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1203 "cn->name is %s \n", (char *)cn->name);
1204 /*
1205 * We're iterating through the XML children looking for
1206 * four types of elements:
1207 * 1) dependents elements
1208 * 2) unconstrained pgroup elements
1209 * 3) pgroup elements constrained by set elements
1210 * 4) enum-method elements for the case that we want
1211 * to post-process a statically defined node
1212 */
1213 if (xmlStrcmp(cn->name, (xmlChar *)Dependents) == 0)
1214 dcnt++;
1215 else if (xmlStrcmp(cn->name, (xmlChar *)Propgrp) == 0)
1216 pgcnt++;
1217 else if (xmlStrcmp(cn->name, (xmlChar *)Enum_meth)
1218 == 0) {
1219 ecn = cn;
1220 ecnt++;
1221 } else if (xmlStrcmp(cn->name, (xmlChar *)Set) == 0) {
1222 if (joined_set)
1223 continue;
1224 set = xmlGetProp(cn, (xmlChar *)Setlist);
1225
1226 key = mp->tm_hdl->th_product;
1227
1228 /*
1229 * If it's the default set then we'll store
1230 * a pointer to it so that if none of the other
1231 * sets apply to our product we can fall
1232 * back to this one.
1233 */
1234 if (strcmp((char *)set, "default") == 0)
1235 def_set = cn;
1236 else if (set_contains(mp, key, (char *)set)) {
1237 psn = cn;
1238 joined_set = 1;
1239 for (gcn = cn->xmlChildrenNode;
1240 gcn != NULL; gcn = gcn->next) {
1241 if (xmlStrcmp(gcn->name,
1242 (xmlChar *)Propgrp) == 0)
1243 pgcnt++;
1244 }
1245 }
1246 xmlFree(set);
1247 }
1248 }
1249 /*
1250 * If we haven't found a set that contains our product AND
1251 * a default set exists, then we'll process it.
1252 */
1253 if (!joined_set && def_set) {
1254 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1255 "Falling back to default set\n");
1256 joined_set = 1;
1257 psn = def_set;
1258 for (gcn = psn->xmlChildrenNode; gcn != NULL;
1259 gcn = gcn->next) {
1260 if (xmlStrcmp(gcn->name, (xmlChar *)Propgrp)
1261 == 0)
1262 pgcnt++;
1263 }
1264 }
1265 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1266 "pad_process: dcnt=%d, pgcnt=%d, ecnt=%d, joined_set=%d\n",
1267 dcnt, pgcnt, ecnt, joined_set);
1268 /*
1269 * Here we allocate an element in an intermediate data structure
1270 * which keeps track property groups and dependents of the range
1271 * currently being processed.
1272 *
1273 * This structure is referenced in pgroups_record() to create
1274 * the actual property groups in the topo tree
1275 */
1276 if ((new = tf_pad_new(mp, pgcnt, dcnt)) == NULL)
1277 return (-1);
1278
1279 if (pgcnt > 0) {
1280 new->tpad_pgs =
1281 topo_mod_zalloc(mp, pgcnt * sizeof (nvlist_t *));
1282 if (new->tpad_pgs == NULL) {
1283 tf_pad_free(mp, new);
1284 return (-1);
1285 }
1286 }
1287 /*
1288 * If the property groups are contained within a set
1289 * then they will be one level lower in the XML tree.
1290 */
1291 if (joined_set)
1292 target = psn;
1293 else
1294 target = pxn;
1295
1296 /*
1297 * If there is no "node" element under the "range"
1298 * element, then we need to attach the facility node to
1299 * each node in this range.
1300 *
1301 * Otherwise we only attach it to the current node
1302 */
1303 if (xmlStrcmp(target->name, (xmlChar *)Range) == 0 ||
1304 xmlStrcmp(target->name, (xmlChar *)Set) == 0) {
1305 for (ct = topo_child_first(rd->rd_pn);
1306 ct != NULL;
1307 ct = topo_child_next(rd->rd_pn, ct)) {
1308
1309 if (strcmp(topo_node_name(ct),
1310 rd->rd_name) != 0)
1311 continue;
1312
1313 inst = topo_node_instance(ct);
1314 if (inst < rd->rd_min || inst > rd->rd_max)
1315 continue;
1316
1317 if (fac_enum_process(mp, target, ct) < 0)
1318 return (-1);
1319
1320 if (fac_process(mp, target, rd, ct) < 0)
1321 return (-1);
1322 }
1323 } else {
1324 if (fac_enum_process(mp, target, ptn) < 0)
1325 return (-1);
1326 if (fac_process(mp, target, rd, ptn) < 0)
1327 return (-1);
1328 }
1329 if (pgcnt > 0 && pgroups_record(mp, target, ptn, rd->rd_name,
1330 new, (const char *)pxn->name) < 0) {
1331 tf_pad_free(mp, new);
1332 return (-1);
1333 }
1334 *rpad = new;
1335 }
1336
1337 /*
1338 * We need to process the property groups before enumerating any
1339 * dependents as that enuemration can itself have dependencies on
1340 * properties set on the parent node.
1341 */
1342 if (new->tpad_pgcnt > 0)
1343 if (pgroups_create(mp, new, ptn) < 0)
1344 return (-1);
1345
1346 /*
1347 * If an enum-method element was found, AND we're a child of a
1348 * node element, then we invoke the enumerator so that it can do
1349 * post-processing of the node.
1350 */
1351 if (ecnt && (strcmp((const char *)pxn->name, Node) == 0)) {
1352 if ((tmp_rd.rd_einfo = enum_attributes_process(mp, ecn))
1353 == NULL)
1354 return (-1);
1355 tmp_rd.rd_mod = mp;
1356 tmp_rd.rd_name = rd->rd_name;
1357 tmp_rd.rd_min = rd->rd_min;
1358 tmp_rd.rd_max = rd->rd_max;
1359 tmp_rd.rd_pn = ptn;
1360 if (enum_run(mp, &tmp_rd) < 0) {
1361 /*
1362 * Note the failure but continue on
1363 */
1364 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1365 "pad_process: enumeration failed.\n");
1366 }
1367 tf_edata_free(mp, tmp_rd.rd_einfo);
1368 }
1369
1370 if (new->tpad_dcnt > 0)
1371 if (dependents_create(mp, rd->rd_finfo, new, pxn, ptn) < 0)
1372 return (-1);
1373
1374 return (0);
1375 }
1376
1377
1378 static int
fac_enum_process(topo_mod_t * mp,xmlNodePtr pn,tnode_t * ptn)1379 fac_enum_process(topo_mod_t *mp, xmlNodePtr pn, tnode_t *ptn)
1380 {
1381 xmlNodePtr cn;
1382 xmlChar *fprov = NULL;
1383 int rv = 0;
1384
1385 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1386 "fac_enum_process() called for %s=%d\n", topo_node_name(ptn),
1387 topo_node_instance(ptn));
1388
1389 for (cn = pn->xmlChildrenNode; cn != NULL; cn = cn->next) {
1390
1391 if (xmlStrcmp(cn->name, (xmlChar *)"fac-enum") != 0)
1392 continue;
1393
1394 if ((fprov = xmlGetProp(cn, (xmlChar *)Provider)) == NULL)
1395 goto fenumdone;
1396 /*
1397 * Invoke enum entry point in facility provider which will
1398 * cause the facility enumeration node method to be
1399 * registered.
1400 */
1401 if (fac_enum_run(mp, ptn, (const char *)fprov) != 0) {
1402 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1403 "fac_enum_process: enum entry point failed!\n");
1404 goto fenumdone;
1405 }
1406 xmlFree(fprov);
1407 }
1408 return (0);
1409 fenumdone:
1410 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "fac-enum processing failed\n");
1411
1412 if (fprov != NULL)
1413 xmlFree(fprov);
1414
1415 return (rv);
1416 }
1417
1418
1419 static int
fac_process(topo_mod_t * mp,xmlNodePtr pn,tf_rdata_t * rd,tnode_t * ptn)1420 fac_process(topo_mod_t *mp, xmlNodePtr pn, tf_rdata_t *rd, tnode_t *ptn)
1421 {
1422 xmlNodePtr cn;
1423 xmlChar *fname = NULL, *ftype = NULL, *provider = NULL;
1424 tnode_t *ntn = NULL;
1425 tf_idata_t *newi;
1426 int err;
1427 topo_pgroup_info_t pgi;
1428
1429 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1430 "fac_process() called for %s=%d\n", topo_node_name(ptn),
1431 topo_node_instance(ptn));
1432
1433 for (cn = pn->xmlChildrenNode; cn != NULL; cn = cn->next) {
1434
1435 if (xmlStrcmp(cn->name, (xmlChar *)Facility) != 0)
1436 continue;
1437
1438 if ((fname = xmlGetProp(cn, (xmlChar *)Name)) == NULL)
1439 goto facdone;
1440
1441 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1442 "processing facility node '%s'\n", fname);
1443
1444 if ((ftype = xmlGetProp(cn, (xmlChar *)Type)) == NULL)
1445 goto facdone;
1446
1447 if ((provider = xmlGetProp(cn, (xmlChar *)Provider)) == NULL)
1448 goto facdone;
1449
1450 if (xmlStrcmp(ftype, (xmlChar *)Sensor) != 0 &&
1451 xmlStrcmp(ftype, (xmlChar *)Indicator) != 0)
1452 goto facdone;
1453
1454 if ((ntn = topo_node_facbind(mp, ptn, (char *)fname,
1455 (char *)ftype)) == NULL)
1456 goto facdone;
1457
1458 pgi.tpi_name = TOPO_PGROUP_FACILITY;
1459 pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
1460 pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
1461 pgi.tpi_version = 1;
1462 if (topo_pgroup_create(ntn, &pgi, &err) != 0) {
1463 if (err != ETOPO_PROP_DEFD) {
1464 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1465 "pgroups create failure: %s\n",
1466 topo_strerror(err));
1467 return (-1);
1468 }
1469 }
1470 /*
1471 * Invoke enum entry point in the facility provider module,
1472 * which will cause the provider methods to be registered on
1473 * this node
1474 */
1475 if (fac_enum_run(mp, ntn, (const char *)provider) != 0) {
1476 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "fac_process: "
1477 "enum entry point failed for provider %s!\n",
1478 provider);
1479 goto facdone;
1480 }
1481
1482 if ((newi = tf_idata_new(mp, 0, ntn)) == NULL)
1483 goto facdone;
1484
1485 if (tf_idata_insert(&rd->rd_instances, newi) < 0)
1486 goto facdone;
1487
1488 if (pad_process(mp, rd, cn, ntn, &newi->ti_pad) < 0)
1489 goto facdone;
1490
1491 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "done with "
1492 "facility %s=%s.\n", ftype, fname);
1493
1494 xmlFree(ftype);
1495 xmlFree(fname);
1496 xmlFree(provider);
1497 }
1498
1499 return (0);
1500
1501 facdone:
1502 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "facility processing failed\n");
1503
1504 if (ftype != NULL)
1505 xmlFree(ftype);
1506 if (fname != NULL)
1507 xmlFree(fname);
1508 if (provider != NULL)
1509 xmlFree(provider);
1510 if (ntn != NULL)
1511 topo_node_unbind(ntn);
1512
1513 return (0);
1514 }
1515
1516 static int
node_process(topo_mod_t * mp,xmlNodePtr nn,tf_rdata_t * rd)1517 node_process(topo_mod_t *mp, xmlNodePtr nn, tf_rdata_t *rd)
1518 {
1519 xmlChar *str;
1520 topo_instance_t inst;
1521 tf_idata_t *newi;
1522 tnode_t *ntn;
1523 uint64_t ui;
1524 int rv = -1;
1525 int s = 0;
1526
1527 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1528 "node_process %s\n", rd->rd_name);
1529
1530 if (xmlattr_to_int(mp, nn, Instance, &ui) < 0)
1531 goto nodedone;
1532 inst = (topo_instance_t)ui;
1533
1534 if ((str = xmlGetProp(nn, (xmlChar *)Static)) != NULL) {
1535 if (xmlStrcmp(str, (xmlChar *)True) == 0)
1536 s = 1;
1537 xmlFree(str);
1538 }
1539
1540 if (s == 0) {
1541 if (topo_mod_enumerate(rd->rd_mod, rd->rd_pn,
1542 rd->rd_finfo->tf_scheme, rd->rd_name, inst, inst,
1543 s == 1 ? &s : NULL) < 0)
1544 goto nodedone;
1545 }
1546 ntn = topo_node_lookup(rd->rd_pn, rd->rd_name, inst);
1547
1548 if (ntn == NULL) {
1549
1550 /*
1551 * If this is a static node declaration, we can
1552 * ignore the lookup failure and continue
1553 * processing. Otherwise, something
1554 * went wrong during enumeration
1555 */
1556 if (s == 1)
1557 rv = 0;
1558 goto nodedone;
1559 }
1560 if ((newi = tf_idata_new(mp, inst, ntn)) == NULL) {
1561 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1562 "node_process: tf_idata_new failed.\n");
1563 goto nodedone;
1564 }
1565 if (tf_idata_insert(&rd->rd_instances, newi) < 0) {
1566 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1567 "node_process: tf_idata_insert failed.\n");
1568 goto nodedone;
1569 }
1570 if (pad_process(mp, rd, nn, ntn, &newi->ti_pad) < 0)
1571 goto nodedone;
1572 if (fac_process(mp, nn, rd, ntn) < 0)
1573 goto nodedone;
1574 rv = 0;
1575 nodedone:
1576 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "done with node %s.\n",
1577 rd->rd_name);
1578 return (rv);
1579 }
1580
1581 static tf_edata_t *
enum_attributes_process(topo_mod_t * mp,xmlNodePtr en)1582 enum_attributes_process(topo_mod_t *mp, xmlNodePtr en)
1583 {
1584 tf_edata_t *einfo;
1585 uint64_t ui;
1586
1587 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enum_attributes_process\n");
1588 if ((einfo = topo_mod_zalloc(mp, sizeof (tf_edata_t))) == NULL) {
1589 (void) topo_mod_seterrno(mp, ETOPO_NOMEM);
1590 return (NULL);
1591 }
1592 einfo->te_name = (char *)xmlGetProp(en, (xmlChar *)Name);
1593 if (einfo->te_name == NULL) {
1594 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1595 "Enumerator name attribute missing.\n");
1596 (void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
1597 goto enodedone;
1598 }
1599
1600 /*
1601 * Check for recursive enumeration
1602 */
1603 if (strcmp(einfo->te_name, mp->tm_name) == 0) {
1604 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1605 "Recursive enumeration detected for %s\n",
1606 einfo->te_name);
1607 (void) topo_mod_seterrno(mp, ETOPO_ENUM_RECURS);
1608 goto enodedone;
1609 }
1610 if (xmlattr_to_int(mp, en, Version, &ui) < 0)
1611 goto enodedone;
1612 einfo->te_vers = (int)ui;
1613
1614 return (einfo);
1615
1616 enodedone:
1617 if (einfo->te_name != NULL)
1618 xmlFree(einfo->te_name);
1619 topo_mod_free(mp, einfo, sizeof (tf_edata_t));
1620 return (NULL);
1621 }
1622
1623 static int
enum_run(topo_mod_t * mp,tf_rdata_t * rd)1624 enum_run(topo_mod_t *mp, tf_rdata_t *rd)
1625 {
1626 topo_hdl_t *thp = mp->tm_hdl;
1627 int e = -1;
1628
1629 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enum_run\n");
1630 /*
1631 * Check if the enumerator module is already loaded.
1632 * Module loading is single-threaded at this point so there's
1633 * no need to worry about the module going away or bumping the
1634 * ref count.
1635 */
1636 if ((rd->rd_mod = topo_mod_lookup(thp, rd->rd_einfo->te_name,
1637 0)) == NULL) {
1638 if ((rd->rd_mod = topo_mod_load(mp, rd->rd_einfo->te_name,
1639 rd->rd_einfo->te_vers)) == NULL) {
1640 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1641 "enum_run: mod_load of %s failed: %s.\n",
1642 rd->rd_einfo->te_name,
1643 topo_strerror(topo_mod_errno(mp)));
1644 (void) topo_hdl_seterrno(thp, topo_mod_errno(mp));
1645 return (e);
1646 }
1647 }
1648 /*
1649 * We're live, so let's enumerate.
1650 */
1651 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enumerate request. (%s)\n",
1652 rd->rd_einfo->te_name);
1653 e = topo_mod_enumerate(rd->rd_mod, rd->rd_pn, rd->rd_einfo->te_name,
1654 rd->rd_name, rd->rd_min, rd->rd_max, NULL);
1655 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "back from enumeration. %d\n",
1656 e);
1657 if (e != 0) {
1658 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1659 "Enumeration failed (%s)\n",
1660 topo_strerror(topo_mod_errno(rd->rd_mod)));
1661 (void) topo_hdl_seterrno(thp, EMOD_PARTIAL_ENUM);
1662 return (topo_mod_seterrno(mp, EMOD_PARTIAL_ENUM));
1663 }
1664 return (e);
1665 }
1666
1667 static int
fac_enum_run(topo_mod_t * mp,tnode_t * node,const char * name)1668 fac_enum_run(topo_mod_t *mp, tnode_t *node, const char *name)
1669 {
1670 topo_hdl_t *thp = mp->tm_hdl;
1671 topo_mod_t *fmod;
1672 int e = -1;
1673
1674 topo_dprintf(thp, TOPO_DBG_XML, "fac_enum_run\n");
1675 /*
1676 * Check if the enumerator module is already loaded.
1677 * Module loading is single-threaded at this point so there's
1678 * no need to worry about the module going away or bumping the
1679 * ref count.
1680 */
1681 if ((fmod = topo_mod_lookup(thp, name, 0)) == NULL) {
1682 if ((fmod = topo_mod_load(mp, name, TOPO_VERSION)) == NULL) {
1683 topo_dprintf(thp, TOPO_DBG_ERR,
1684 "fac_enum_run: mod_load of %s failed: %s.\n",
1685 name, topo_strerror(topo_mod_errno(mp)));
1686 (void) topo_hdl_seterrno(thp, topo_mod_errno(mp));
1687 return (e);
1688 }
1689 }
1690 /*
1691 * We're live, so let's enumerate.
1692 */
1693 topo_dprintf(thp, TOPO_DBG_XML, "fac enumerate request. (%s)\n", name);
1694 e = topo_mod_enumerate(fmod, node, name, name, 0, 0, NULL);
1695 topo_dprintf(thp, TOPO_DBG_XML, "back from enumeration. %d\n", e);
1696 if (e != 0) {
1697 topo_dprintf(thp, TOPO_DBG_ERR,
1698 "Facility provider enumeration failed (%s)\n",
1699 topo_strerror(topo_mod_errno(fmod)));
1700 (void) topo_hdl_seterrno(thp, EMOD_PARTIAL_ENUM);
1701 return (topo_mod_seterrno(mp, EMOD_PARTIAL_ENUM));
1702 }
1703 return (e);
1704 }
1705
1706 int
decorate_nodes(topo_mod_t * mp,tf_rdata_t * rd,xmlNodePtr pxn,tnode_t * ptn,tf_pad_t ** rpad)1707 decorate_nodes(topo_mod_t *mp, tf_rdata_t *rd, xmlNodePtr pxn, tnode_t *ptn,
1708 tf_pad_t **rpad)
1709 {
1710 tnode_t *ctn;
1711
1712 ctn = topo_child_first(ptn);
1713 while (ctn != NULL) {
1714 /* Only care about instances within the range */
1715 if (strcmp(topo_node_name(ctn), rd->rd_name) != 0) {
1716 ctn = topo_child_next(ptn, ctn);
1717 continue;
1718 }
1719 if (pad_process(mp, rd, pxn, ctn, rpad) < 0)
1720 return (-1);
1721 if (decorate_nodes(mp, rd, pxn, ctn, rpad) < 0)
1722 return (-1);
1723 ctn = topo_child_next(ptn, ctn);
1724 }
1725 return (0);
1726 }
1727
1728 int
topo_xml_range_process(topo_mod_t * mp,xmlNodePtr rn,tf_rdata_t * rd)1729 topo_xml_range_process(topo_mod_t *mp, xmlNodePtr rn, tf_rdata_t *rd)
1730 {
1731 /*
1732 * The range may have several children xmlNodes, that may
1733 * represent the enumeration method, property groups,
1734 * dependents, nodes or services.
1735 */
1736 xmlNodePtr cn, enum_node = NULL, pmap_node = NULL;
1737 xmlChar *pmap_name;
1738 tnode_t *ct;
1739 int e, ccnt = 0;
1740
1741 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_range_process\n"
1742 "process %s range beneath %s\n", rd->rd_name,
1743 topo_node_name(rd->rd_pn));
1744
1745 e = topo_node_range_create(mp,
1746 rd->rd_pn, rd->rd_name, rd->rd_min, rd->rd_max);
1747 if (e != 0 && topo_mod_errno(mp) != EMOD_NODE_DUP) {
1748 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1749 "Range create failed due to %s.\n",
1750 topo_strerror(topo_mod_errno(mp)));
1751 return (-1);
1752 }
1753
1754 /*
1755 * Before we process any of the other child xmlNodes, we iterate through
1756 * the children and looking for either enum-method or propmap elements.
1757 */
1758 for (cn = rn->xmlChildrenNode; cn != NULL; cn = cn->next)
1759 if (xmlStrcmp(cn->name, (xmlChar *)Enum_meth) == 0)
1760 enum_node = cn;
1761 else if (xmlStrcmp(cn->name, (xmlChar *)Propmap) == 0)
1762 pmap_node = cn;
1763
1764 /*
1765 * If we found an enum-method element, process it first
1766 */
1767 if (enum_node != NULL) {
1768 if ((rd->rd_einfo = enum_attributes_process(mp, enum_node))
1769 == NULL)
1770 return (-1);
1771 if (enum_run(mp, rd) < 0) {
1772 /*
1773 * Note the failure but continue on
1774 */
1775 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1776 "Enumeration failed.\n");
1777 }
1778 }
1779
1780 /*
1781 * Next, check if a propmap element was found and if so, load it in
1782 * and parse it.
1783 */
1784 if (pmap_node != NULL) {
1785 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "found a propmap "
1786 "element\n");
1787 if ((pmap_name = xmlGetProp(pmap_node, (xmlChar *)Name))
1788 == NULL) {
1789 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1790 "propmap element missing name attribute.\n");
1791 } else {
1792 if (topo_file_load(mp, rd->rd_pn,
1793 (const char *)pmap_name,
1794 rd->rd_finfo->tf_scheme, 1) < 0) {
1795
1796 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1797 "topo_xml_range_process: topo_file_load"
1798 "failed: %s.\n",
1799 topo_strerror(topo_mod_errno(mp)));
1800 }
1801 xmlFree(pmap_name);
1802 }
1803 }
1804
1805 /* Now look for nodes, i.e., hard instances */
1806 for (cn = rn->xmlChildrenNode; cn != NULL; cn = cn->next) {
1807 if (xmlStrcmp(cn->name, (xmlChar *)Node) == 0) {
1808 if (node_process(mp, cn, rd) < 0) {
1809 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1810 "node processing failed: %s.\n",
1811 topo_strerror(topo_mod_errno(mp)));
1812 return (topo_mod_seterrno(mp,
1813 EMOD_PARTIAL_ENUM));
1814 }
1815 ccnt++;
1816 }
1817 }
1818
1819 /*
1820 * Finally, process the property groups and dependents
1821 *
1822 * If the TF_PROPMAP flag is set for the XML file we're currently
1823 * processing, then this XML file was loaded via propmap. In that case
1824 * we call a special routine to recursively apply the propgroup settings
1825 * to all of nodes in this range
1826 */
1827 if (rd->rd_finfo->tf_flags & TF_PROPMAP)
1828 (void) decorate_nodes(mp, rd, rn, rd->rd_pn, &rd->rd_pad);
1829 else {
1830 ct = topo_child_first(rd->rd_pn);
1831 while (ct != NULL) {
1832 /* Only care about instances within the range */
1833 if (strcmp(topo_node_name(ct), rd->rd_name) != 0) {
1834 ct = topo_child_next(rd->rd_pn, ct);
1835 continue;
1836 }
1837 if (pad_process(mp, rd, rn, ct, &rd->rd_pad)
1838 < 0)
1839 return (-1);
1840
1841 if (fac_process(mp, rn, rd, ct) < 0)
1842 return (-1);
1843
1844 ct = topo_child_next(rd->rd_pn, ct);
1845 ccnt++;
1846 }
1847 }
1848
1849 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_range_process: end "
1850 "range process %s\n", rd->rd_name);
1851
1852 return (0);
1853 }
1854
1855 static tf_rdata_t *
topo_xml_walk(topo_mod_t * mp,tf_info_t * xinfo,xmlNodePtr croot,tnode_t * troot)1856 topo_xml_walk(topo_mod_t *mp,
1857 tf_info_t *xinfo, xmlNodePtr croot, tnode_t *troot)
1858 {
1859 xmlNodePtr curr, def_set = NULL;
1860 tf_rdata_t *rr, *pr, *rdp;
1861 xmlChar *set;
1862 char *key;
1863 int joined_set = 0;
1864
1865 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_walk\n");
1866 rr = pr = NULL;
1867 /*
1868 * First iterate through all the XML nodes at this level to look for
1869 * set nodes.
1870 */
1871 for (curr = croot->xmlChildrenNode; curr != NULL; curr = curr->next) {
1872 if (curr->name == NULL) {
1873 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1874 "topo_xml_walk: Ignoring nameless xmlnode\n");
1875 continue;
1876 }
1877 if (xmlStrcmp(curr->name, (xmlChar *)Set) == 0) {
1878 if (joined_set)
1879 continue;
1880
1881 set = xmlGetProp(curr, (xmlChar *)Setlist);
1882
1883 key = mp->tm_hdl->th_product;
1884
1885 /*
1886 * If it's the default set then we'll store
1887 * a pointer to it so that if none of the other
1888 * sets apply to our product we can fall
1889 * back to this one.
1890 */
1891 if (strcmp((char *)set, "default") == 0)
1892 def_set = curr;
1893 else if (set_contains(mp, key, (char *)set)) {
1894 joined_set = 1;
1895 if ((rdp = topo_xml_walk(mp, xinfo, curr,
1896 troot)) == NULL) {
1897 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1898 "topo_xml_walk: failed1\n");
1899 } else {
1900 if (pr == NULL) {
1901 rr = pr = rdp;
1902 } else {
1903 pr->rd_next = rdp;
1904 pr = rdp;
1905 }
1906 rr->rd_cnt++;
1907 }
1908 }
1909 xmlFree(set);
1910 }
1911 }
1912 /*
1913 * If we haven't found a set that contains our product AND a default set
1914 * exists, then we'll process it.
1915 */
1916 if (!joined_set && def_set) {
1917 if ((rdp = topo_xml_walk(mp, xinfo, def_set, troot)) == NULL) {
1918 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1919 "topo_xml_walk: failed2\n");
1920 }
1921 if (pr == NULL) {
1922 rr = pr = rdp;
1923 } else {
1924 pr->rd_next = rdp;
1925 pr = rdp;
1926 }
1927 rr->rd_cnt++;
1928 }
1929 /*
1930 * Now we're interested in children xmlNodes of croot tagged
1931 * as 'ranges'. These define what topology nodes may exist, and need
1932 * to be verified.
1933 */
1934 for (curr = croot->xmlChildrenNode; curr != NULL; curr = curr->next) {
1935 if (curr->name == NULL) {
1936 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1937 "topo_xml_walk: Ignoring nameless xmlnode\n");
1938 continue;
1939 }
1940 if (xmlStrcmp(curr->name, (xmlChar *)Range) != 0)
1941 continue;
1942 if ((rdp = tf_rdata_new(mp, xinfo, curr, troot)) == NULL) {
1943 /*
1944 * Range processing error, continue walk
1945 */
1946 continue;
1947 }
1948 if (pr == NULL) {
1949 rr = pr = rdp;
1950 } else {
1951 pr->rd_next = rdp;
1952 pr = rdp;
1953 }
1954 rr->rd_cnt++;
1955 }
1956
1957 return (rr);
1958 }
1959
1960 /*
1961 * Convert parsed xml topology description into topology nodes
1962 */
1963 int
topo_xml_enum(topo_mod_t * tmp,tf_info_t * xinfo,tnode_t * troot)1964 topo_xml_enum(topo_mod_t *tmp, tf_info_t *xinfo, tnode_t *troot)
1965 {
1966 xmlNodePtr xroot;
1967
1968 topo_dprintf(tmp->tm_hdl, TOPO_DBG_XML, "topo_xml_enum\n");
1969
1970 if ((xroot = xmlDocGetRootElement(xinfo->tf_xdoc)) == NULL) {
1971 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
1972 "Couldn't get root xmlNode.\n");
1973 return (-1);
1974 }
1975 if ((xinfo->tf_rd = topo_xml_walk(tmp, xinfo, xroot, troot)) == NULL) {
1976 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
1977 "error within .xml topology: %s\n",
1978 topo_strerror(topo_mod_errno(tmp)));
1979 return (-1);
1980 }
1981 return (0);
1982 }
1983
1984 /*
1985 * Load an XML tree from filename and read it into a DOM parse tree.
1986 */
1987 static tf_info_t *
txml_file_parse(topo_mod_t * tmp,int fd,const char * filenm,const char * escheme)1988 txml_file_parse(topo_mod_t *tmp,
1989 int fd, const char *filenm, const char *escheme)
1990 {
1991 xmlValidCtxtPtr vcp;
1992 xmlNodePtr cursor;
1993 xmlDocPtr document;
1994 xmlDtdPtr dtd = NULL;
1995 xmlChar *scheme = NULL;
1996 char *dtdpath = NULL;
1997 int readflags = 0;
1998 tf_info_t *r;
1999 int e, validate = 0;
2000
2001 topo_dprintf(tmp->tm_hdl, TOPO_DBG_XML,
2002 "txml_file_parse(filenm=%s, escheme=%s)\n", filenm, escheme);
2003
2004 /*
2005 * Since topologies can XInclude other topologies, and libxml2
2006 * doesn't do DTD-based validation with XInclude, by default
2007 * we don't validate topology files. One can force
2008 * validation, though, by creating a TOPOXML_VALIDATE
2009 * environment variable and creating a TOPO_DTD environment
2010 * variable with the path to the DTD against which to validate.
2011 */
2012 if (getenv("TOPOXML_VALIDATE") != NULL) {
2013 dtdpath = getenv("TOPO_DTD");
2014 validate = 1;
2015 }
2016
2017 /*
2018 * Splat warnings and errors related to parsing the topology
2019 * file if the TOPOXML_PERROR environment variable exists.
2020 */
2021 if (getenv("TOPOXML_PERROR") == NULL)
2022 readflags = XML_PARSE_NOERROR | XML_PARSE_NOWARNING;
2023
2024 if ((document = xmlReadFd(fd, filenm, NULL, readflags)) == NULL) {
2025 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2026 "txml_file_parse: couldn't parse document.\n");
2027 return (NULL);
2028 }
2029
2030 /*
2031 * Verify that this is a document type we understand.
2032 */
2033 if ((dtd = xmlGetIntSubset(document)) == NULL) {
2034 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2035 "document has no DTD.\n");
2036 xmlFreeDoc(document);
2037 return (NULL);
2038 }
2039
2040 if (strcmp((const char *)dtd->SystemID, TOPO_DTD_PATH) != 0) {
2041 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2042 "document DTD unknown; bad topology file\n");
2043 xmlFreeDoc(document);
2044 return (NULL);
2045 }
2046
2047 if ((cursor = xmlDocGetRootElement(document)) == NULL) {
2048 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, "document is empty.\n");
2049 xmlFreeDoc(document);
2050 return (NULL);
2051 }
2052
2053 /*
2054 * Make sure we're looking at a topology description in the
2055 * expected scheme.
2056 */
2057 if (xmlStrcmp(cursor->name, (xmlChar *)Topology) != 0) {
2058 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2059 "document is not a topology description.\n");
2060 xmlFreeDoc(document);
2061 return (NULL);
2062 }
2063 if ((scheme = xmlGetProp(cursor, (xmlChar *)Scheme)) == NULL) {
2064 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2065 "topology lacks a scheme.\n");
2066 (void) topo_mod_seterrno(tmp, ETOPO_PRSR_NOATTR);
2067 xmlFreeDoc(document);
2068 return (NULL);
2069 }
2070 if (xmlStrcmp(scheme, (xmlChar *)escheme) != 0) {
2071 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2072 "topology in unrecognized scheme, %s, expecting %s\n",
2073 scheme, escheme);
2074 (void) topo_mod_seterrno(tmp, ETOPO_PRSR_BADSCH);
2075 xmlFree(scheme);
2076 xmlFreeDoc(document);
2077 return (NULL);
2078 }
2079
2080 if (dtdpath != NULL) {
2081 dtd = xmlParseDTD(NULL, (xmlChar *)dtdpath);
2082 if (dtd == NULL) {
2083 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2084 "Could not parse DTD \"%s\".\n",
2085 dtdpath);
2086 xmlFree(scheme);
2087 xmlFreeDoc(document);
2088 return (NULL);
2089 }
2090
2091 if (document->extSubset != NULL)
2092 xmlFreeDtd(document->extSubset);
2093
2094 document->extSubset = dtd;
2095 }
2096
2097 if (xmlXIncludeProcessFlags(document, XML_PARSE_XINCLUDE) == -1) {
2098 xmlFree(scheme);
2099 xmlFreeDoc(document);
2100 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2101 "couldn't handle XInclude statements in document\n");
2102 return (NULL);
2103 }
2104
2105 if (validate) {
2106 if ((vcp = xmlNewValidCtxt()) == NULL) {
2107 xmlFree(scheme);
2108 xmlFreeDoc(document);
2109 return (NULL);
2110 }
2111 vcp->warning = xmlParserValidityWarning;
2112 vcp->error = xmlParserValidityError;
2113
2114 e = xmlValidateDocument(vcp, document);
2115
2116 xmlFreeValidCtxt(vcp);
2117
2118 if (e == 0)
2119 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2120 "Document is not valid.\n");
2121 }
2122
2123 if ((r = tf_info_new(tmp, document, scheme)) == NULL) {
2124 xmlFree(scheme);
2125 xmlFreeDoc(document);
2126 return (NULL);
2127 }
2128
2129 xmlFree(scheme);
2130 scheme = NULL;
2131 return (r);
2132 }
2133
2134 tf_info_t *
topo_xml_read(topo_mod_t * tmp,const char * path,const char * escheme)2135 topo_xml_read(topo_mod_t *tmp, const char *path, const char *escheme)
2136 {
2137 int fd;
2138 tf_info_t *tip;
2139
2140 if ((fd = open(path, O_RDONLY)) < 0) {
2141 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2142 "failed to open %s for reading\n", path);
2143 return (NULL);
2144 }
2145 tip = txml_file_parse(tmp, fd, path, escheme);
2146 (void) close(fd);
2147 return (tip);
2148 }
2149