This source file includes following definitions.
- hwloc_libxml2_error_callback
- hwloc_libxml2_init_once
- hwloc_libxml2_cleanup
- hwloc__libxml_import_next_attr
- hwloc__libxml_import_find_child
- hwloc__libxml_import_close_tag
- hwloc__libxml_import_close_child
- hwloc__libxml_import_get_content
- hwloc__libxml_import_close_content
- hwloc_libxml_look_init
- hwloc_libxml_free_buffers
- hwloc_libxml_look_done
- hwloc_libxml_import_diff
- hwloc_libxml_backend_exit
- hwloc_libxml_backend_init
- hwloc__libxml_export_new_child
- hwloc__libxml_export_new_prop
- hwloc__libxml_export_end_object
- hwloc__libxml_export_add_content
- hwloc__libxml2_prepare_export
- hwloc_libxml_export_file
- hwloc_libxml_export_buffer
- hwloc__libxml2_prepare_export_diff
- hwloc_libxml_export_diff_file
- hwloc_libxml_export_diff_buffer
- hwloc_libxml_free_buffer
- hwloc_xml_libxml_component_init
1
2
3
4
5
6
7
8
9 #include <private/autogen/config.h>
10 #include <hwloc.h>
11 #include <hwloc/plugins.h>
12
13
14 #include <private/xml.h>
15 #include <private/debug.h>
16 #include <private/misc.h>
17
18 #include <libxml/parser.h>
19 #include <libxml/tree.h>
20
21
22
23
24
25 static void hwloc_libxml2_error_callback(void * ctx __hwloc_attribute_unused, const char * msg __hwloc_attribute_unused, ...) { }
26
27
28 static int hwloc_libxml2_needs_cleanup = 0;
29
30 static void
31 hwloc_libxml2_init_once(void)
32 {
33 static int checked = 0;
34 if (!checked) {
35
36 xmlSetGenericErrorFunc(NULL, hwloc__xml_verbose() ? xmlGenericError : hwloc_libxml2_error_callback);
37
38 if (getenv("HWLOC_LIBXML_CLEANUP"))
39 hwloc_libxml2_needs_cleanup = 1;
40 checked = 1;
41 }
42 }
43
44 static void
45 hwloc_libxml2_cleanup(void)
46 {
47 if (hwloc_libxml2_needs_cleanup) {
48 xmlCleanupParser();
49 }
50 }
51
52
53
54
55
56 typedef struct hwloc__libxml_import_state_data_s {
57 xmlNode *node;
58 xmlNode *child;
59 xmlAttr *attr;
60 } __hwloc_attribute_may_alias * hwloc__libxml_import_state_data_t;
61
62 static int
63 hwloc__libxml_import_next_attr(hwloc__xml_import_state_t state, char **namep, char **valuep)
64 {
65 hwloc__libxml_import_state_data_t lstate = (void*) state->data;
66
67 xmlAttr *attr;
68 if (lstate->attr)
69 attr = lstate->attr->next;
70 else
71 attr = lstate->node->properties;
72 for (; attr; attr = attr->next)
73 if (attr->type == XML_ATTRIBUTE_NODE) {
74
75 xmlNode *subnode;
76 for (subnode = attr->children; subnode; subnode = subnode->next) {
77 if (subnode->type == XML_TEXT_NODE) {
78 if (subnode->content) {
79 *namep = (char *) attr->name;
80 *valuep = (char *) subnode->content;
81 lstate->attr = attr;
82 return 0;
83 }
84 } else {
85 if (hwloc__xml_verbose())
86 fprintf(stderr, "%s: ignoring unexpected xml attr node type %u\n",
87 state->global->msgprefix, subnode->type);
88 }
89 }
90 } else {
91 if (hwloc__xml_verbose())
92 fprintf(stderr, "%s: ignoring unexpected xml attr type %u\n",
93 state->global->msgprefix, attr->type);
94 }
95 return -1;
96 }
97
98 static int
99 hwloc__libxml_import_find_child(hwloc__xml_import_state_t state,
100 hwloc__xml_import_state_t childstate,
101 char **tagp)
102 {
103 hwloc__libxml_import_state_data_t lstate = (void*) state->data;
104 hwloc__libxml_import_state_data_t lchildstate = (void*) childstate->data;
105 xmlNode *child;
106 childstate->parent = state;
107 childstate->global = state->global;
108 if (!lstate->child)
109
110 return 0;
111
112 child = lstate->child;
113 if (child->type == XML_ELEMENT_NODE) {
114 lstate->child = child->next;
115 lchildstate->node = child;
116 lchildstate->child = child->children;
117 lchildstate->attr = NULL;
118 *tagp = (char*) child->name;
119 return 1;
120 } else if (child->type == XML_TEXT_NODE) {
121 if (child->content && child->content[0] != '\0' && child->content[0] != '\n')
122 if (hwloc__xml_verbose())
123 fprintf(stderr, "%s: ignoring object text content %s\n",
124 state->global->msgprefix, (const char*) child->content);
125 } else if (child->type != XML_COMMENT_NODE) {
126 if (hwloc__xml_verbose())
127 fprintf(stderr, "%s: ignoring unexpected xml node type %u\n",
128 state->global->msgprefix, child->type);
129 }
130
131 return 0;
132 }
133
134 static int
135 hwloc__libxml_import_close_tag(hwloc__xml_import_state_t state __hwloc_attribute_unused)
136 {
137 return 0;
138 }
139
140 static void
141 hwloc__libxml_import_close_child(hwloc__xml_import_state_t state __hwloc_attribute_unused)
142 {
143
144 }
145
146 static int
147 hwloc__libxml_import_get_content(hwloc__xml_import_state_t state,
148 char **beginp, size_t expected_length)
149 {
150 hwloc__libxml_import_state_data_t lstate = (void*) state->data;
151 xmlNode *child;
152 size_t length;
153
154 child = lstate->node->children;
155 if (!child || child->type != XML_TEXT_NODE) {
156 if (expected_length)
157 return -1;
158 *beginp = (char *) "";
159 return 0;
160 }
161
162 length = strlen((char *) child->content);
163 if (length != expected_length)
164 return -1;
165 *beginp = (char *) child->content;
166 return 1;
167 }
168
169 static void
170 hwloc__libxml_import_close_content(hwloc__xml_import_state_t state __hwloc_attribute_unused)
171 {
172
173 }
174
175 static int
176 hwloc_libxml_look_init(struct hwloc_xml_backend_data_s *bdata,
177 struct hwloc__xml_import_state_s *state)
178 {
179 hwloc__libxml_import_state_data_t lstate = (void*) state->data;
180 xmlNodePtr root_node;
181 xmlDtdPtr dtd;
182
183 HWLOC_BUILD_ASSERT(sizeof(*lstate) <= sizeof(state->data));
184
185 dtd = xmlGetIntSubset((xmlDocPtr) bdata->data);
186 if (!dtd) {
187 if (hwloc__xml_verbose())
188 fprintf(stderr, "%s: Loading XML topology without DTD\n",
189 state->global->msgprefix);
190 } else if (strcmp((char *) dtd->SystemID, "hwloc.dtd")
191 && strcmp((char *) dtd->SystemID, "hwloc2.dtd")) {
192 if (hwloc__xml_verbose())
193 fprintf(stderr, "%s: Loading XML topology with wrong DTD SystemID (%s instead of %s)\n",
194 state->global->msgprefix, (char *) dtd->SystemID, "hwloc.dtd or hwloc2.dtd");
195 }
196
197 root_node = xmlDocGetRootElement((xmlDocPtr) bdata->data);
198
199 if (!strcmp((const char *) root_node->name, "root")) {
200 bdata->version_major = 0;
201 bdata->version_minor = 9;
202 } else if (!strcmp((const char *) root_node->name, "topology")) {
203 unsigned major, minor;
204 xmlChar *version = xmlGetProp(root_node, (xmlChar*) "version");
205 if (version && sscanf((const char *)version, "%u.%u", &major, &minor) == 2) {
206 bdata->version_major = major;
207 bdata->version_minor = minor;
208 } else {
209 bdata->version_major = 1;
210 bdata->version_minor = 0;
211 }
212 xmlFree(version);
213 } else {
214
215 if (hwloc__xml_verbose())
216 fprintf(stderr, "%s: ignoring object of class `%s' not at the top the xml hierarchy\n",
217 state->global->msgprefix, (const char *) root_node->name);
218 goto failed;
219 }
220
221 state->global->next_attr = hwloc__libxml_import_next_attr;
222 state->global->find_child = hwloc__libxml_import_find_child;
223 state->global->close_tag = hwloc__libxml_import_close_tag;
224 state->global->close_child = hwloc__libxml_import_close_child;
225 state->global->get_content = hwloc__libxml_import_get_content;
226 state->global->close_content = hwloc__libxml_import_close_content;
227 state->parent = NULL;
228 lstate->node = root_node;
229 lstate->child = root_node->children;
230 lstate->attr = NULL;
231 return 0;
232
233 failed:
234 return -1;
235 }
236
237
238
239
240 static void
241 hwloc_libxml_free_buffers(struct hwloc_xml_backend_data_s *bdata)
242 {
243 if (bdata->data) {
244 xmlFreeDoc((xmlDoc*)bdata->data);
245 bdata->data = NULL;
246 }
247 }
248
249 static void
250 hwloc_libxml_look_done(struct hwloc_xml_backend_data_s *bdata, int result __hwloc_attribute_unused)
251 {
252 hwloc_libxml_free_buffers(bdata);
253 }
254
255 static int
256 hwloc_libxml_import_diff(struct hwloc__xml_import_state_s *state, const char *xmlpath, const char *xmlbuffer, int xmlbuflen, hwloc_topology_diff_t *firstdiffp, char **refnamep)
257 {
258 hwloc__libxml_import_state_data_t lstate = (void*) state->data;
259 char *refname = NULL;
260 xmlDoc *doc = NULL;
261 xmlNode* root_node;
262 xmlDtd *dtd;
263 int ret;
264
265 HWLOC_BUILD_ASSERT(sizeof(*lstate) <= sizeof(state->data));
266
267 LIBXML_TEST_VERSION;
268 hwloc_libxml2_init_once();
269
270 errno = 0;
271
272 if (xmlpath)
273 doc = xmlReadFile(xmlpath, NULL, XML_PARSE_NOBLANKS);
274 else if (xmlbuffer)
275 doc = xmlReadMemory(xmlbuffer, xmlbuflen, "", NULL, XML_PARSE_NOBLANKS);
276
277 if (!doc) {
278 if (!errno)
279
280 errno = EINVAL;
281 hwloc_libxml2_cleanup();
282 goto out;
283 }
284
285 dtd = xmlGetIntSubset(doc);
286 if (!dtd) {
287 if (hwloc__xml_verbose())
288 fprintf(stderr, "%s: Loading XML topologydiff without DTD\n",
289 state->global->msgprefix);
290 } else if (strcmp((char *) dtd->SystemID, "hwloc2-diff.dtd")) {
291 if (hwloc__xml_verbose())
292 fprintf(stderr, "%s: Loading XML topologydiff with wrong DTD SystemID (%s instead of %s)\n",
293 state->global->msgprefix, (char *) dtd->SystemID, "hwloc2-diff.dtd");
294 }
295
296 root_node = xmlDocGetRootElement(doc);
297
298 if (strcmp((const char *) root_node->name, "topologydiff")) {
299
300 if (hwloc__xml_verbose())
301 fprintf(stderr, "%s: ignoring object of class `%s' not at the top the xml hierarchy\n",
302 state->global->msgprefix, (const char *) root_node->name);
303 goto out_with_doc;
304 }
305
306 state->global->next_attr = hwloc__libxml_import_next_attr;
307 state->global->find_child = hwloc__libxml_import_find_child;
308 state->global->close_tag = hwloc__libxml_import_close_tag;
309 state->global->close_child = hwloc__libxml_import_close_child;
310 state->global->get_content = hwloc__libxml_import_get_content;
311 state->global->close_content = hwloc__libxml_import_close_content;
312 state->parent = NULL;
313 lstate->node = root_node;
314 lstate->child = root_node->children;
315 lstate->attr = NULL;
316
317 while (1) {
318 char *attrname, *attrvalue;
319 if (state->global->next_attr(state, &attrname, &attrvalue) < 0)
320 break;
321 if (!strcmp(attrname, "refname")) {
322 free(refname);
323 refname = strdup(attrvalue);
324 } else
325 goto out_with_doc;
326 }
327
328 ret = hwloc__xml_import_diff(state, firstdiffp);
329 if (refnamep && !ret)
330 *refnamep = refname;
331 else
332 free(refname);
333
334 xmlFreeDoc(doc);
335 hwloc_libxml2_cleanup();
336 return ret;
337
338 out_with_doc:
339 free(refname);
340 xmlFreeDoc(doc);
341 hwloc_libxml2_cleanup();
342 out:
343 return -1;
344 }
345
346
347
348
349
350 static void
351 hwloc_libxml_backend_exit(struct hwloc_xml_backend_data_s *bdata)
352 {
353 hwloc_libxml_free_buffers(bdata);
354 hwloc_libxml2_cleanup();
355 }
356
357 static int
358 hwloc_libxml_backend_init(struct hwloc_xml_backend_data_s *bdata,
359 const char *xmlpath, const char *xmlbuffer, int xmlbuflen)
360 {
361 xmlDoc *doc = NULL;
362
363 LIBXML_TEST_VERSION;
364 hwloc_libxml2_init_once();
365
366 errno = 0;
367
368 if (xmlpath)
369 doc = xmlReadFile(xmlpath, NULL, XML_PARSE_NOBLANKS);
370 else if (xmlbuffer)
371 doc = xmlReadMemory(xmlbuffer, xmlbuflen, "", NULL, XML_PARSE_NOBLANKS);
372
373 if (!doc) {
374 if (!errno)
375
376 errno = EINVAL;
377 hwloc_libxml2_cleanup();
378 return -1;
379 }
380
381 bdata->look_init = hwloc_libxml_look_init;
382 bdata->look_done = hwloc_libxml_look_done;
383 bdata->backend_exit = hwloc_libxml_backend_exit;
384 bdata->data = doc;
385 return 0;
386 }
387
388
389
390
391
392 typedef struct hwloc__libxml_export_state_data_s {
393 xmlNodePtr current_node;
394 } __hwloc_attribute_may_alias * hwloc__libxml_export_state_data_t;
395
396 static void
397 hwloc__libxml_export_new_child(hwloc__xml_export_state_t parentstate,
398 hwloc__xml_export_state_t state,
399 const char *name)
400 {
401 hwloc__libxml_export_state_data_t lpdata = (void *) parentstate->data;
402 hwloc__libxml_export_state_data_t ldata = (void *) state->data;
403
404 state->parent = parentstate;
405 state->new_child = parentstate->new_child;
406 state->new_prop = parentstate->new_prop;
407 state->add_content = parentstate->add_content;
408 state->end_object = parentstate->end_object;
409 state->global = parentstate->global;
410
411 ldata->current_node = xmlNewChild(lpdata->current_node, NULL, BAD_CAST name, NULL);
412 }
413
414 static void
415 hwloc__libxml_export_new_prop(hwloc__xml_export_state_t state, const char *name, const char *value)
416 {
417 hwloc__libxml_export_state_data_t ldata = (void *) state->data;
418 xmlNewProp(ldata->current_node, BAD_CAST name, BAD_CAST value);
419 }
420
421 static void
422 hwloc__libxml_export_end_object(hwloc__xml_export_state_t state __hwloc_attribute_unused, const char *name __hwloc_attribute_unused)
423 {
424
425 }
426
427 static void
428 hwloc__libxml_export_add_content(hwloc__xml_export_state_t state, const char *buffer, size_t length)
429 {
430 hwloc__libxml_export_state_data_t ldata = (void *) state->data;
431 xmlNodeAddContentLen(ldata->current_node, BAD_CAST buffer, length);
432 }
433
434 static xmlDocPtr
435 hwloc__libxml2_prepare_export(hwloc_topology_t topology, struct hwloc__xml_export_data_s *edata,
436 unsigned long flags)
437 {
438 struct hwloc__xml_export_state_s state;
439 hwloc__libxml_export_state_data_t data = (void *) state.data;
440 int v1export = flags & HWLOC_TOPOLOGY_EXPORT_XML_FLAG_V1;
441 xmlDocPtr doc = NULL;
442 xmlNodePtr root_node = NULL;
443
444 HWLOC_BUILD_ASSERT(sizeof(*data) <= sizeof(state.data));
445
446 LIBXML_TEST_VERSION;
447 hwloc_libxml2_init_once();
448
449
450 doc = xmlNewDoc(BAD_CAST "1.0");
451 root_node = xmlNewNode(NULL, BAD_CAST "topology");
452 if (!(flags & HWLOC_TOPOLOGY_EXPORT_XML_FLAG_V1))
453 xmlNewProp(root_node, BAD_CAST "version", BAD_CAST "2.0");
454 xmlDocSetRootElement(doc, root_node);
455
456
457 (void) xmlCreateIntSubset(doc, BAD_CAST "topology", NULL, v1export ? BAD_CAST "hwloc.dtd" : BAD_CAST "hwloc2.dtd");
458
459 state.new_child = hwloc__libxml_export_new_child;
460 state.new_prop = hwloc__libxml_export_new_prop;
461 state.add_content = hwloc__libxml_export_add_content;
462 state.end_object = hwloc__libxml_export_end_object;
463 state.global = edata;
464
465 data->current_node = root_node;
466
467 hwloc__xml_export_topology (&state, topology, flags);
468
469 return doc;
470 }
471
472 static int
473 hwloc_libxml_export_file(hwloc_topology_t topology, struct hwloc__xml_export_data_s *edata,
474 const char *filename, unsigned long flags)
475 {
476 xmlDocPtr doc;
477 int ret;
478
479 errno = 0;
480
481 doc = hwloc__libxml2_prepare_export(topology, edata, flags);
482 ret = xmlSaveFormatFileEnc(filename, doc, "UTF-8", 1);
483 xmlFreeDoc(doc);
484 hwloc_libxml2_cleanup();
485
486 if (ret < 0) {
487 if (!errno)
488
489 errno = EINVAL;
490 return ret;
491 }
492 return 0;
493 }
494
495 static int
496 hwloc_libxml_export_buffer(hwloc_topology_t topology, struct hwloc__xml_export_data_s *edata,
497 char **xmlbuffer, int *buflen, unsigned long flags)
498 {
499 xmlDocPtr doc;
500
501 doc = hwloc__libxml2_prepare_export(topology, edata, flags);
502 xmlDocDumpFormatMemoryEnc(doc, (xmlChar **)xmlbuffer, buflen, "UTF-8", 1);
503 xmlFreeDoc(doc);
504 hwloc_libxml2_cleanup();
505 return 0;
506 }
507
508 static xmlDocPtr
509 hwloc__libxml2_prepare_export_diff(hwloc_topology_diff_t diff, const char *refname)
510 {
511 struct hwloc__xml_export_state_s state;
512 hwloc__libxml_export_state_data_t data = (void *) state.data;
513 xmlDocPtr doc = NULL;
514 xmlNodePtr root_node = NULL;
515
516 HWLOC_BUILD_ASSERT(sizeof(*data) <= sizeof(state.data));
517
518 LIBXML_TEST_VERSION;
519 hwloc_libxml2_init_once();
520
521
522 doc = xmlNewDoc(BAD_CAST "1.0");
523 root_node = xmlNewNode(NULL, BAD_CAST "topologydiff");
524 if (refname)
525 xmlNewProp(root_node, BAD_CAST "refname", BAD_CAST refname);
526 xmlDocSetRootElement(doc, root_node);
527
528
529 (void) xmlCreateIntSubset(doc, BAD_CAST "topologydiff", NULL, BAD_CAST "hwloc2-diff.dtd");
530
531 state.new_child = hwloc__libxml_export_new_child;
532 state.new_prop = hwloc__libxml_export_new_prop;
533 state.add_content = hwloc__libxml_export_add_content;
534 state.end_object = hwloc__libxml_export_end_object;
535
536 data->current_node = root_node;
537
538 hwloc__xml_export_diff (&state, diff);
539
540 return doc;
541 }
542
543 static int
544 hwloc_libxml_export_diff_file(hwloc_topology_diff_t diff, const char *refname, const char *filename)
545 {
546 xmlDocPtr doc;
547 int ret;
548
549 errno = 0;
550
551 doc = hwloc__libxml2_prepare_export_diff(diff, refname);
552 ret = xmlSaveFormatFileEnc(filename, doc, "UTF-8", 1);
553 xmlFreeDoc(doc);
554 hwloc_libxml2_cleanup();
555
556 if (ret < 0) {
557 if (!errno)
558
559 errno = EINVAL;
560 return ret;
561 }
562 return 0;
563 }
564
565 static int
566 hwloc_libxml_export_diff_buffer(hwloc_topology_diff_t diff, const char *refname, char **xmlbuffer, int *buflen)
567 {
568 xmlDocPtr doc;
569
570 doc = hwloc__libxml2_prepare_export_diff(diff, refname);
571 xmlDocDumpFormatMemoryEnc(doc, (xmlChar **)xmlbuffer, buflen, "UTF-8", 1);
572 xmlFreeDoc(doc);
573 hwloc_libxml2_cleanup();
574 return 0;
575 }
576
577 static void
578 hwloc_libxml_free_buffer(void *xmlbuffer)
579 {
580 xmlFree(BAD_CAST xmlbuffer);
581 }
582
583
584
585
586
587 static struct hwloc_xml_callbacks hwloc_xml_libxml_callbacks = {
588 hwloc_libxml_backend_init,
589 hwloc_libxml_export_file,
590 hwloc_libxml_export_buffer,
591 hwloc_libxml_free_buffer,
592 hwloc_libxml_import_diff,
593 hwloc_libxml_export_diff_file,
594 hwloc_libxml_export_diff_buffer
595 };
596
597 static struct hwloc_xml_component hwloc_libxml_xml_component = {
598 NULL,
599 &hwloc_xml_libxml_callbacks
600 };
601
602 static int
603 hwloc_xml_libxml_component_init(unsigned long flags)
604 {
605 if (flags)
606 return -1;
607 if (hwloc_plugin_check_namespace("xml_libxml", "hwloc__xml_verbose") < 0)
608 return -1;
609 return 0;
610 }
611
612 #ifdef HWLOC_INSIDE_PLUGIN
613 HWLOC_DECLSPEC extern const struct hwloc_component hwloc_xml_libxml_component;
614 #endif
615
616 const struct hwloc_component hwloc_xml_libxml_component = {
617 HWLOC_COMPONENT_ABI,
618 hwloc_xml_libxml_component_init, NULL,
619 HWLOC_COMPONENT_TYPE_XML,
620 0,
621 &hwloc_libxml_xml_component
622 };