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