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