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