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