1 /*
2 * Copyright © 2009 CNRS
3 * Copyright © 2009-2020 Inria. All rights reserved.
4 * Copyright © 2009-2011 Université Bordeaux
5 * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
6 * See COPYING in top-level directory.
7 */
8
9 #include "private/autogen/config.h"
10 #include "hwloc.h"
11 #include "hwloc/plugins.h"
12 #include "private/private.h"
13 #include "private/misc.h"
14 #include "private/xml.h"
15 #include "private/debug.h"
16
17 #include <string.h>
18 #include <assert.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #ifdef HAVE_UNISTD_H
22 #include <unistd.h>
23 #endif
24
25 /*******************
26 * Import routines *
27 *******************/
28
29 struct hwloc__nolibxml_backend_data_s {
30 size_t buflen; /* size of both buffer, set during backend_init() */
31 char *buffer; /* allocated and filled during backend_init() */
32 };
33
34 typedef struct hwloc__nolibxml_import_state_data_s {
35 char *tagbuffer; /* buffer containing the next tag */
36 char *attrbuffer; /* buffer containing the next attribute of the current node */
37 const char *tagname; /* tag name of the current node */
38 int closed; /* set if the current node is auto-closing */
39 } __hwloc_attribute_may_alias * hwloc__nolibxml_import_state_data_t;
40
41 static char *
hwloc__nolibxml_import_ignore_spaces(char * buffer)42 hwloc__nolibxml_import_ignore_spaces(char *buffer)
43 {
44 return buffer + strspn(buffer, " \t\n");
45 }
46
47 static int
hwloc__nolibxml_import_next_attr(hwloc__xml_import_state_t state,char ** namep,char ** valuep)48 hwloc__nolibxml_import_next_attr(hwloc__xml_import_state_t state, char **namep, char **valuep)
49 {
50 hwloc__nolibxml_import_state_data_t nstate = (void*) state->data;
51 size_t namelen;
52 size_t len, escaped;
53 char *buffer, *value, *end;
54
55 if (!nstate->attrbuffer)
56 return -1;
57
58 /* find the beginning of an attribute */
59 buffer = hwloc__nolibxml_import_ignore_spaces(nstate->attrbuffer);
60 namelen = strspn(buffer, "abcdefghijklmnopqrstuvwxyz_");
61 if (buffer[namelen] != '=' || buffer[namelen+1] != '\"')
62 return -1;
63 buffer[namelen] = '\0';
64 *namep = buffer;
65
66 /* find the beginning of its value, and unescape it */
67 *valuep = value = buffer+namelen+2;
68 len = 0; escaped = 0;
69 while (value[len+escaped] != '\"') {
70 if (value[len+escaped] == '&') {
71 if (!strncmp(&value[1+len+escaped], "#10;", 4)) {
72 escaped += 4;
73 value[len] = '\n';
74 } else if (!strncmp(&value[1+len+escaped], "#13;", 4)) {
75 escaped += 4;
76 value[len] = '\r';
77 } else if (!strncmp(&value[1+len+escaped], "#9;", 3)) {
78 escaped += 3;
79 value[len] = '\t';
80 } else if (!strncmp(&value[1+len+escaped], "quot;", 5)) {
81 escaped += 5;
82 value[len] = '\"';
83 } else if (!strncmp(&value[1+len+escaped], "lt;", 3)) {
84 escaped += 3;
85 value[len] = '<';
86 } else if (!strncmp(&value[1+len+escaped], "gt;", 3)) {
87 escaped += 3;
88 value[len] = '>';
89 } else if (!strncmp(&value[1+len+escaped], "amp;", 4)) {
90 escaped += 4;
91 value[len] = '&';
92 } else {
93 return -1;
94 }
95 } else {
96 value[len] = value[len+escaped];
97 }
98 len++;
99 if (value[len+escaped] == '\0')
100 return -1;
101 }
102 value[len] = '\0';
103
104 /* find next attribute */
105 end = &value[len+escaped+1]; /* skip the ending " */
106 nstate->attrbuffer = hwloc__nolibxml_import_ignore_spaces(end);
107 return 0;
108 }
109
110 static int
hwloc__nolibxml_import_find_child(hwloc__xml_import_state_t state,hwloc__xml_import_state_t childstate,char ** tagp)111 hwloc__nolibxml_import_find_child(hwloc__xml_import_state_t state,
112 hwloc__xml_import_state_t childstate,
113 char **tagp)
114 {
115 hwloc__nolibxml_import_state_data_t nstate = (void*) state->data;
116 hwloc__nolibxml_import_state_data_t nchildstate = (void*) childstate->data;
117 char *buffer = nstate->tagbuffer;
118 char *end;
119 char *tag;
120 size_t namelen;
121
122 childstate->parent = state;
123 childstate->global = state->global;
124
125 /* auto-closed tags have no children */
126 if (nstate->closed)
127 return 0;
128
129 /* find the beginning of the tag */
130 buffer = hwloc__nolibxml_import_ignore_spaces(buffer);
131 if (buffer[0] != '<')
132 return -1;
133 buffer++;
134
135 /* if closing tag, return nothing and do not advance */
136 if (buffer[0] == '/')
137 return 0;
138
139 /* normal tag */
140 nchildstate->tagname = tag = buffer;
141
142 /* find the end, mark it and return it */
143 end = strchr(buffer, '>');
144 if (!end)
145 return -1;
146 end[0] = '\0';
147 nchildstate->tagbuffer = end+1;
148
149 /* handle auto-closing tags */
150 if (end[-1] == '/') {
151 nchildstate->closed = 1;
152 end[-1] = '\0';
153 } else
154 nchildstate->closed = 0;
155
156 /* find attributes */
157 namelen = strspn(buffer, "abcdefghijklmnopqrstuvwxyz1234567890_");
158
159 if (buffer[namelen] == '\0') {
160 /* no attributes */
161 nchildstate->attrbuffer = NULL;
162 *tagp = tag;
163 return 1;
164 }
165
166 if (buffer[namelen] != ' ')
167 return -1;
168
169 /* found a space, likely starting attributes */
170 buffer[namelen] = '\0';
171 nchildstate->attrbuffer = buffer+namelen+1;
172 *tagp = tag;
173 return 1;
174 }
175
176 static int
hwloc__nolibxml_import_close_tag(hwloc__xml_import_state_t state)177 hwloc__nolibxml_import_close_tag(hwloc__xml_import_state_t state)
178 {
179 hwloc__nolibxml_import_state_data_t nstate = (void*) state->data;
180 char *buffer = nstate->tagbuffer;
181 char *end;
182
183 /* auto-closed tags need nothing */
184 if (nstate->closed)
185 return 0;
186
187 /* find the beginning of the tag */
188 buffer = hwloc__nolibxml_import_ignore_spaces(buffer);
189 if (buffer[0] != '<')
190 return -1;
191 buffer++;
192
193 /* find the end, mark it and return it to the parent */
194 end = strchr(buffer, '>');
195 if (!end)
196 return -1;
197 end[0] = '\0';
198 nstate->tagbuffer = end+1;
199
200 /* if closing tag, return nothing */
201 if (buffer[0] != '/' || strcmp(buffer+1, nstate->tagname) )
202 return -1;
203 return 0;
204 }
205
206 static void
hwloc__nolibxml_import_close_child(hwloc__xml_import_state_t state)207 hwloc__nolibxml_import_close_child(hwloc__xml_import_state_t state)
208 {
209 hwloc__nolibxml_import_state_data_t nstate = (void*) state->data;
210 hwloc__nolibxml_import_state_data_t nparent = (void*) state->parent->data;
211 nparent->tagbuffer = nstate->tagbuffer;
212 }
213
214 static int
hwloc__nolibxml_import_get_content(hwloc__xml_import_state_t state,const char ** beginp,size_t expected_length)215 hwloc__nolibxml_import_get_content(hwloc__xml_import_state_t state,
216 const char **beginp, size_t expected_length)
217 {
218 hwloc__nolibxml_import_state_data_t nstate = (void*) state->data;
219 char *buffer = nstate->tagbuffer;
220 size_t length;
221 char *end;
222
223 /* auto-closed tags have no content */
224 if (nstate->closed) {
225 if (expected_length)
226 return -1;
227 *beginp = "";
228 return 0;
229 }
230
231 /* find the next tag, where the content ends */
232 end = strchr(buffer, '<');
233 if (!end)
234 return -1;
235
236 length = (size_t) (end-buffer);
237 if (length != expected_length)
238 return -1;
239 nstate->tagbuffer = end;
240 *end = '\0'; /* mark as 0-terminated for now */
241 *beginp = buffer;
242 return 1;
243 }
244
245 static void
hwloc__nolibxml_import_close_content(hwloc__xml_import_state_t state)246 hwloc__nolibxml_import_close_content(hwloc__xml_import_state_t state)
247 {
248 /* put back the '<' that we overwrote to 0-terminate the content */
249 hwloc__nolibxml_import_state_data_t nstate = (void*) state->data;
250 if (!nstate->closed)
251 *nstate->tagbuffer = '<';
252 }
253
254 static int
hwloc_nolibxml_look_init(struct hwloc_xml_backend_data_s * bdata,struct hwloc__xml_import_state_s * state)255 hwloc_nolibxml_look_init(struct hwloc_xml_backend_data_s *bdata,
256 struct hwloc__xml_import_state_s *state)
257 {
258 hwloc__nolibxml_import_state_data_t nstate = (void*) state->data;
259 struct hwloc__nolibxml_backend_data_s *nbdata = bdata->data;
260 unsigned major, minor;
261 char *end;
262 char *buffer = nbdata->buffer;
263 const char *tagname;
264
265 HWLOC_BUILD_ASSERT(sizeof(*nstate) <= sizeof(state->data));
266
267 /* skip headers */
268 while (!strncmp(buffer, "<?xml ", 6) || !strncmp(buffer, "<!DOCTYPE ", 10)) {
269 buffer = strchr(buffer, '\n');
270 if (!buffer)
271 goto failed;
272 buffer++;
273 }
274
275 /* find topology tag */
276 if (sscanf(buffer, "<topology version=\"%u.%u\">", &major, &minor) == 2) {
277 bdata->version_major = major;
278 bdata->version_minor = minor;
279 end = strchr(buffer, '>') + 1;
280 tagname = "topology";
281 } else if (!strncmp(buffer, "<topology>", 10)) {
282 bdata->version_major = 1;
283 bdata->version_minor = 0;
284 end = buffer + 10;
285 tagname = "topology";
286 } else if (!strncmp(buffer, "<root>", 6)) {
287 bdata->version_major = 0;
288 bdata->version_minor = 9;
289 end = buffer + 6;
290 tagname = "root";
291 } else
292 goto failed;
293
294 state->global->next_attr = hwloc__nolibxml_import_next_attr;
295 state->global->find_child = hwloc__nolibxml_import_find_child;
296 state->global->close_tag = hwloc__nolibxml_import_close_tag;
297 state->global->close_child = hwloc__nolibxml_import_close_child;
298 state->global->get_content = hwloc__nolibxml_import_get_content;
299 state->global->close_content = hwloc__nolibxml_import_close_content;
300 state->parent = NULL;
301 nstate->closed = 0;
302 nstate->tagbuffer = end;
303 nstate->tagname = tagname;
304 nstate->attrbuffer = NULL;
305 return 0; /* success */
306
307 failed:
308 return -1; /* failed */
309 }
310
311 /* can be called at the end of the import (to cleanup things early),
312 * or by backend_exit() if load failed for other reasons.
313 */
314 static void
hwloc_nolibxml_free_buffers(struct hwloc_xml_backend_data_s * bdata)315 hwloc_nolibxml_free_buffers(struct hwloc_xml_backend_data_s *bdata)
316 {
317 struct hwloc__nolibxml_backend_data_s *nbdata = bdata->data;
318 if (nbdata->buffer) {
319 free(nbdata->buffer);
320 nbdata->buffer = NULL;
321 }
322 }
323
324 static void
hwloc_nolibxml_look_done(struct hwloc_xml_backend_data_s * bdata,int result)325 hwloc_nolibxml_look_done(struct hwloc_xml_backend_data_s *bdata, int result)
326 {
327 hwloc_nolibxml_free_buffers(bdata);
328
329 if (result < 0 && hwloc__xml_verbose())
330 fprintf(stderr, "Failed to parse XML input with the minimalistic parser. If it was not\n"
331 "generated by hwloc, try enabling full XML support with libxml2.\n");
332 }
333
334 /********************
335 * Backend routines *
336 ********************/
337
338 static void
hwloc_nolibxml_backend_exit(struct hwloc_xml_backend_data_s * bdata)339 hwloc_nolibxml_backend_exit(struct hwloc_xml_backend_data_s *bdata)
340 {
341 struct hwloc__nolibxml_backend_data_s *nbdata = bdata->data;
342 hwloc_nolibxml_free_buffers(bdata);
343 free(nbdata);
344 }
345
346 static int
hwloc_nolibxml_read_file(const char * xmlpath,char ** bufferp,size_t * buflenp)347 hwloc_nolibxml_read_file(const char *xmlpath, char **bufferp, size_t *buflenp)
348 {
349 FILE * file;
350 size_t buflen, offset, readlen;
351 struct stat statbuf;
352 char *buffer, *tmp;
353 size_t ret;
354
355 if (!strcmp(xmlpath, "-"))
356 xmlpath = "/dev/stdin";
357
358 file = fopen(xmlpath, "r");
359 if (!file)
360 goto out;
361
362 /* find the required buffer size for regular files, or use 4k when unknown, we'll realloc later if needed */
363 buflen = 4096;
364 if (!stat(xmlpath, &statbuf))
365 if (S_ISREG(statbuf.st_mode))
366 buflen = statbuf.st_size+1; /* one additional byte so that the first fread() gets EOF too */
367
368 buffer = malloc(buflen+1); /* one more byte for the ending \0 */
369 if (!buffer)
370 goto out_with_file;
371
372 offset = 0; readlen = buflen;
373 while (1) {
374 ret = fread(buffer+offset, 1, readlen, file);
375
376 offset += ret;
377 buffer[offset] = 0;
378
379 if (ret != readlen)
380 break;
381
382 buflen *= 2;
383 tmp = realloc(buffer, buflen+1);
384 if (!tmp)
385 goto out_with_buffer;
386 buffer = tmp;
387 readlen = buflen/2;
388 }
389
390 fclose(file);
391 *bufferp = buffer;
392 *buflenp = offset+1;
393 return 0;
394
395 out_with_buffer:
396 free(buffer);
397 out_with_file:
398 fclose(file);
399 out:
400 return -1;
401 }
402
403 static int
hwloc_nolibxml_backend_init(struct hwloc_xml_backend_data_s * bdata,const char * xmlpath,const char * xmlbuffer,int xmlbuflen)404 hwloc_nolibxml_backend_init(struct hwloc_xml_backend_data_s *bdata,
405 const char *xmlpath, const char *xmlbuffer, int xmlbuflen)
406 {
407 struct hwloc__nolibxml_backend_data_s *nbdata = malloc(sizeof(*nbdata));
408
409 if (!nbdata)
410 goto out;
411 bdata->data = nbdata;
412
413 if (xmlbuffer) {
414 nbdata->buffer = malloc(xmlbuflen+1);
415 if (!nbdata->buffer)
416 goto out_with_nbdata;
417 nbdata->buflen = xmlbuflen+1;
418 memcpy(nbdata->buffer, xmlbuffer, xmlbuflen);
419 nbdata->buffer[xmlbuflen] = '\0';
420
421 } else {
422 int err = hwloc_nolibxml_read_file(xmlpath, &nbdata->buffer, &nbdata->buflen);
423 if (err < 0)
424 goto out_with_nbdata;
425 }
426
427 bdata->look_init = hwloc_nolibxml_look_init;
428 bdata->look_done = hwloc_nolibxml_look_done;
429 bdata->backend_exit = hwloc_nolibxml_backend_exit;
430 return 0;
431
432 out_with_nbdata:
433 free(nbdata);
434 out:
435 return -1;
436 }
437
438 static int
hwloc_nolibxml_import_diff(struct hwloc__xml_import_state_s * state,const char * xmlpath,const char * xmlbuffer,int xmlbuflen,hwloc_topology_diff_t * firstdiffp,char ** refnamep)439 hwloc_nolibxml_import_diff(struct hwloc__xml_import_state_s *state,
440 const char *xmlpath, const char *xmlbuffer, int xmlbuflen,
441 hwloc_topology_diff_t *firstdiffp, char **refnamep)
442 {
443 hwloc__nolibxml_import_state_data_t nstate = (void*) state->data;
444 struct hwloc__xml_import_state_s childstate;
445 char *refname = NULL;
446 char *buffer, *tmp, *tag;
447 size_t buflen;
448 int ret;
449
450 HWLOC_BUILD_ASSERT(sizeof(*nstate) <= sizeof(state->data));
451
452 if (xmlbuffer) {
453 buffer = malloc(xmlbuflen);
454 if (!buffer)
455 goto out;
456 memcpy(buffer, xmlbuffer, xmlbuflen);
457 buflen = xmlbuflen;
458
459 } else {
460 ret = hwloc_nolibxml_read_file(xmlpath, &buffer, &buflen);
461 if (ret < 0)
462 goto out;
463 }
464
465 /* skip headers */
466 tmp = buffer;
467 while (!strncmp(tmp, "<?xml ", 6) || !strncmp(tmp, "<!DOCTYPE ", 10)) {
468 tmp = strchr(tmp, '\n');
469 if (!tmp)
470 goto out_with_buffer;
471 tmp++;
472 }
473
474 state->global->next_attr = hwloc__nolibxml_import_next_attr;
475 state->global->find_child = hwloc__nolibxml_import_find_child;
476 state->global->close_tag = hwloc__nolibxml_import_close_tag;
477 state->global->close_child = hwloc__nolibxml_import_close_child;
478 state->global->get_content = hwloc__nolibxml_import_get_content;
479 state->global->close_content = hwloc__nolibxml_import_close_content;
480 state->parent = NULL;
481 nstate->closed = 0;
482 nstate->tagbuffer = tmp;
483 nstate->tagname = NULL;
484 nstate->attrbuffer = NULL;
485
486 /* find root */
487 ret = hwloc__nolibxml_import_find_child(state, &childstate, &tag);
488 if (ret < 0)
489 goto out_with_buffer;
490 if (!tag || strcmp(tag, "topologydiff"))
491 goto out_with_buffer;
492
493 while (1) {
494 char *attrname, *attrvalue;
495 if (hwloc__nolibxml_import_next_attr(&childstate, &attrname, &attrvalue) < 0)
496 break;
497 if (!strcmp(attrname, "refname")) {
498 free(refname);
499 refname = strdup(attrvalue);
500 } else
501 goto out_with_buffer;
502 }
503
504 ret = hwloc__xml_import_diff(&childstate, firstdiffp);
505 if (refnamep && !ret)
506 *refnamep = refname;
507 else
508 free(refname);
509
510 free(buffer);
511 return ret;
512
513 out_with_buffer:
514 free(buffer);
515 free(refname);
516 out:
517 return -1;
518 }
519
520 /*******************
521 * Export routines *
522 *******************/
523
524 typedef struct hwloc__nolibxml_export_state_data_s {
525 char *buffer; /* (moving) buffer where to write */
526 size_t written; /* how many bytes were written (or would have be written if not truncated) */
527 size_t remaining; /* how many bytes are still available in the buffer */
528 unsigned indent; /* indentation level for the next line */
529 unsigned nr_children;
530 unsigned has_content;
531 } __hwloc_attribute_may_alias * hwloc__nolibxml_export_state_data_t;
532
533 static void
hwloc__nolibxml_export_update_buffer(hwloc__nolibxml_export_state_data_t ndata,int res)534 hwloc__nolibxml_export_update_buffer(hwloc__nolibxml_export_state_data_t ndata, int res)
535 {
536 if (res >= 0) {
537 ndata->written += res;
538 if (res >= (int) ndata->remaining)
539 res = ndata->remaining>0 ? (int)ndata->remaining-1 : 0;
540 ndata->buffer += res;
541 ndata->remaining -= res;
542 }
543 }
544
545 static char *
hwloc__nolibxml_export_escape_string(const char * src)546 hwloc__nolibxml_export_escape_string(const char *src)
547 {
548 size_t fulllen, sublen;
549 char *escaped, *dst;
550
551 fulllen = strlen(src);
552
553 sublen = strcspn(src, "\n\r\t\"<>&");
554 if (sublen == fulllen)
555 return NULL; /* nothing to escape */
556
557 escaped = malloc(fulllen*6+1); /* escaped chars are replaced by at most 6 char */
558 dst = escaped;
559
560 memcpy(dst, src, sublen);
561 src += sublen;
562 dst += sublen;
563
564 while (*src) {
565 int replen;
566 switch (*src) {
567 case '\n': strcpy(dst, " "); replen=5; break;
568 case '\r': strcpy(dst, " "); replen=5; break;
569 case '\t': strcpy(dst, "	"); replen=4; break;
570 case '\"': strcpy(dst, """); replen=6; break;
571 case '<': strcpy(dst, "<"); replen=4; break;
572 case '>': strcpy(dst, ">"); replen=4; break;
573 case '&': strcpy(dst, "&"); replen=5; break;
574 default: replen=0; break;
575 }
576 dst+=replen; src++;
577
578 sublen = strcspn(src, "\n\r\t\"<>&");
579 memcpy(dst, src, sublen);
580 src += sublen;
581 dst += sublen;
582 }
583
584 *dst = 0;
585 return escaped;
586 }
587
588 static void
hwloc__nolibxml_export_new_child(hwloc__xml_export_state_t parentstate,hwloc__xml_export_state_t state,const char * name)589 hwloc__nolibxml_export_new_child(hwloc__xml_export_state_t parentstate,
590 hwloc__xml_export_state_t state,
591 const char *name)
592 {
593 hwloc__nolibxml_export_state_data_t npdata = (void *) parentstate->data;
594 hwloc__nolibxml_export_state_data_t ndata = (void *) state->data;
595 int res;
596
597 assert(!npdata->has_content);
598 if (!npdata->nr_children) {
599 res = hwloc_snprintf(npdata->buffer, npdata->remaining, ">\n");
600 hwloc__nolibxml_export_update_buffer(npdata, res);
601 }
602 npdata->nr_children++;
603
604 state->parent = parentstate;
605 state->new_child = parentstate->new_child;
606 state->new_prop = parentstate->new_prop;
607 state->add_content = parentstate->add_content;
608 state->end_object = parentstate->end_object;
609 state->global = parentstate->global;
610
611 ndata->buffer = npdata->buffer;
612 ndata->written = npdata->written;
613 ndata->remaining = npdata->remaining;
614 ndata->indent = npdata->indent + 2;
615
616 ndata->nr_children = 0;
617 ndata->has_content = 0;
618
619 res = hwloc_snprintf(ndata->buffer, ndata->remaining, "%*s<%s", (int) npdata->indent, "", name);
620 hwloc__nolibxml_export_update_buffer(ndata, res);
621 }
622
623 static void
hwloc__nolibxml_export_new_prop(hwloc__xml_export_state_t state,const char * name,const char * value)624 hwloc__nolibxml_export_new_prop(hwloc__xml_export_state_t state, const char *name, const char *value)
625 {
626 hwloc__nolibxml_export_state_data_t ndata = (void *) state->data;
627 char *escaped = hwloc__nolibxml_export_escape_string(value);
628 int res = hwloc_snprintf(ndata->buffer, ndata->remaining, " %s=\"%s\"", name, escaped ? (const char *) escaped : value);
629 hwloc__nolibxml_export_update_buffer(ndata, res);
630 free(escaped);
631 }
632
633 static void
hwloc__nolibxml_export_end_object(hwloc__xml_export_state_t state,const char * name)634 hwloc__nolibxml_export_end_object(hwloc__xml_export_state_t state, const char *name)
635 {
636 hwloc__nolibxml_export_state_data_t ndata = (void *) state->data;
637 hwloc__nolibxml_export_state_data_t npdata = (void *) state->parent->data;
638 int res;
639
640 assert (!(ndata->has_content && ndata->nr_children));
641 if (ndata->has_content) {
642 res = hwloc_snprintf(ndata->buffer, ndata->remaining, "</%s>\n", name);
643 } else if (ndata->nr_children) {
644 res = hwloc_snprintf(ndata->buffer, ndata->remaining, "%*s</%s>\n", (int) npdata->indent, "", name);
645 } else {
646 res = hwloc_snprintf(ndata->buffer, ndata->remaining, "/>\n");
647 }
648 hwloc__nolibxml_export_update_buffer(ndata, res);
649
650 npdata->buffer = ndata->buffer;
651 npdata->written = ndata->written;
652 npdata->remaining = ndata->remaining;
653 }
654
655 static void
hwloc__nolibxml_export_add_content(hwloc__xml_export_state_t state,const char * buffer,size_t length __hwloc_attribute_unused)656 hwloc__nolibxml_export_add_content(hwloc__xml_export_state_t state, const char *buffer, size_t length __hwloc_attribute_unused)
657 {
658 hwloc__nolibxml_export_state_data_t ndata = (void *) state->data;
659 int res;
660
661 assert(!ndata->nr_children);
662 if (!ndata->has_content) {
663 res = hwloc_snprintf(ndata->buffer, ndata->remaining, ">");
664 hwloc__nolibxml_export_update_buffer(ndata, res);
665 }
666 ndata->has_content = 1;
667
668 res = hwloc_snprintf(ndata->buffer, ndata->remaining, "%s", buffer);
669 hwloc__nolibxml_export_update_buffer(ndata, res);
670 }
671
672 static size_t
hwloc___nolibxml_prepare_export(hwloc_topology_t topology,struct hwloc__xml_export_data_s * edata,char * xmlbuffer,int buflen,unsigned long flags)673 hwloc___nolibxml_prepare_export(hwloc_topology_t topology, struct hwloc__xml_export_data_s *edata,
674 char *xmlbuffer, int buflen, unsigned long flags)
675 {
676 struct hwloc__xml_export_state_s state, childstate;
677 hwloc__nolibxml_export_state_data_t ndata = (void *) &state.data;
678 int v1export = flags & HWLOC_TOPOLOGY_EXPORT_XML_FLAG_V1;
679 int res;
680
681 HWLOC_BUILD_ASSERT(sizeof(*ndata) <= sizeof(state.data));
682
683 state.new_child = hwloc__nolibxml_export_new_child;
684 state.new_prop = hwloc__nolibxml_export_new_prop;
685 state.add_content = hwloc__nolibxml_export_add_content;
686 state.end_object = hwloc__nolibxml_export_end_object;
687 state.global = edata;
688
689 ndata->indent = 0;
690 ndata->written = 0;
691 ndata->buffer = xmlbuffer;
692 ndata->remaining = buflen;
693
694 ndata->nr_children = 1; /* don't close a non-existing previous tag when opening the topology tag */
695 ndata->has_content = 0;
696
697 res = hwloc_snprintf(ndata->buffer, ndata->remaining,
698 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
699 "<!DOCTYPE topology SYSTEM \"%s\">\n", v1export ? "hwloc.dtd" : "hwloc2.dtd");
700 hwloc__nolibxml_export_update_buffer(ndata, res);
701 hwloc__nolibxml_export_new_child(&state, &childstate, "topology");
702 if (!(flags & HWLOC_TOPOLOGY_EXPORT_XML_FLAG_V1))
703 hwloc__nolibxml_export_new_prop(&childstate, "version", "2.0");
704 hwloc__xml_export_topology (&childstate, topology, flags);
705 hwloc__nolibxml_export_end_object(&childstate, "topology");
706
707 return ndata->written+1; /* ending \0 */
708 }
709
710 static int
hwloc_nolibxml_export_buffer(hwloc_topology_t topology,struct hwloc__xml_export_data_s * edata,char ** bufferp,int * buflenp,unsigned long flags)711 hwloc_nolibxml_export_buffer(hwloc_topology_t topology, struct hwloc__xml_export_data_s *edata,
712 char **bufferp, int *buflenp, unsigned long flags)
713 {
714 char *buffer;
715 size_t bufferlen, res;
716
717 bufferlen = 16384; /* random guess for large enough default */
718 buffer = malloc(bufferlen);
719 if (!buffer)
720 return -1;
721 res = hwloc___nolibxml_prepare_export(topology, edata, buffer, (int)bufferlen, flags);
722
723 if (res > bufferlen) {
724 char *tmp = realloc(buffer, res);
725 if (!tmp) {
726 free(buffer);
727 return -1;
728 }
729 buffer = tmp;
730 hwloc___nolibxml_prepare_export(topology, edata, buffer, (int)res, flags);
731 }
732
733 *bufferp = buffer;
734 *buflenp = (int)res;
735 return 0;
736 }
737
738 static int
hwloc_nolibxml_export_file(hwloc_topology_t topology,struct hwloc__xml_export_data_s * edata,const char * filename,unsigned long flags)739 hwloc_nolibxml_export_file(hwloc_topology_t topology, struct hwloc__xml_export_data_s *edata,
740 const char *filename, unsigned long flags)
741 {
742 FILE *file;
743 char *buffer;
744 int bufferlen;
745 int ret;
746
747 ret = hwloc_nolibxml_export_buffer(topology, edata, &buffer, &bufferlen, flags);
748 if (ret < 0)
749 return -1;
750
751 if (!strcmp(filename, "-")) {
752 file = stdout;
753 } else {
754 file = fopen(filename, "w");
755 if (!file) {
756 free(buffer);
757 return -1;
758 }
759 }
760
761 ret = (int)fwrite(buffer, 1, bufferlen-1 /* don't write the ending \0 */, file);
762 if (ret == bufferlen-1) {
763 ret = 0;
764 } else {
765 errno = ferror(file);
766 ret = -1;
767 }
768
769 free(buffer);
770
771 if (file != stdout)
772 fclose(file);
773 return ret;
774 }
775
776 static size_t
hwloc___nolibxml_prepare_export_diff(hwloc_topology_diff_t diff,const char * refname,char * xmlbuffer,int buflen)777 hwloc___nolibxml_prepare_export_diff(hwloc_topology_diff_t diff, const char *refname, char *xmlbuffer, int buflen)
778 {
779 struct hwloc__xml_export_state_s state, childstate;
780 hwloc__nolibxml_export_state_data_t ndata = (void *) &state.data;
781 int res;
782
783 HWLOC_BUILD_ASSERT(sizeof(*ndata) <= sizeof(state.data));
784
785 state.new_child = hwloc__nolibxml_export_new_child;
786 state.new_prop = hwloc__nolibxml_export_new_prop;
787 state.add_content = hwloc__nolibxml_export_add_content;
788 state.end_object = hwloc__nolibxml_export_end_object;
789 state.global = NULL;
790
791 ndata->indent = 0;
792 ndata->written = 0;
793 ndata->buffer = xmlbuffer;
794 ndata->remaining = buflen;
795
796 ndata->nr_children = 1; /* don't close a non-existing previous tag when opening the topology tag */
797 ndata->has_content = 0;
798
799 res = hwloc_snprintf(ndata->buffer, ndata->remaining,
800 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
801 "<!DOCTYPE topologydiff SYSTEM \"hwloc2-diff.dtd\">\n");
802 hwloc__nolibxml_export_update_buffer(ndata, res);
803 hwloc__nolibxml_export_new_child(&state, &childstate, "topologydiff");
804 if (refname)
805 hwloc__nolibxml_export_new_prop(&childstate, "refname", refname);
806 hwloc__xml_export_diff (&childstate, diff);
807 hwloc__nolibxml_export_end_object(&childstate, "topologydiff");
808
809 return ndata->written+1;
810 }
811
812 static int
hwloc_nolibxml_export_diff_buffer(hwloc_topology_diff_t diff,const char * refname,char ** bufferp,int * buflenp)813 hwloc_nolibxml_export_diff_buffer(hwloc_topology_diff_t diff, const char *refname, char **bufferp, int *buflenp)
814 {
815 char *buffer;
816 size_t bufferlen, res;
817
818 bufferlen = 16384; /* random guess for large enough default */
819 buffer = malloc(bufferlen);
820 if (!buffer)
821 return -1;
822 res = hwloc___nolibxml_prepare_export_diff(diff, refname, buffer, (int)bufferlen);
823
824 if (res > bufferlen) {
825 char *tmp = realloc(buffer, res);
826 if (!tmp) {
827 free(buffer);
828 return -1;
829 }
830 buffer = tmp;
831 hwloc___nolibxml_prepare_export_diff(diff, refname, buffer, (int)res);
832 }
833
834 *bufferp = buffer;
835 *buflenp = (int)res;
836 return 0;
837 }
838
839 static int
hwloc_nolibxml_export_diff_file(hwloc_topology_diff_t diff,const char * refname,const char * filename)840 hwloc_nolibxml_export_diff_file(hwloc_topology_diff_t diff, const char *refname, const char *filename)
841 {
842 FILE *file;
843 char *buffer;
844 int bufferlen;
845 int ret;
846
847 ret = hwloc_nolibxml_export_diff_buffer(diff, refname, &buffer, &bufferlen);
848 if (ret < 0)
849 return -1;
850
851 if (!strcmp(filename, "-")) {
852 file = stdout;
853 } else {
854 file = fopen(filename, "w");
855 if (!file) {
856 free(buffer);
857 return -1;
858 }
859 }
860
861 ret = (int)fwrite(buffer, 1, bufferlen-1 /* don't write the ending \0 */, file);
862 if (ret == bufferlen-1) {
863 ret = 0;
864 } else {
865 errno = ferror(file);
866 ret = -1;
867 }
868
869 free(buffer);
870
871 if (file != stdout)
872 fclose(file);
873 return ret;
874 }
875
876 static void
hwloc_nolibxml_free_buffer(void * xmlbuffer)877 hwloc_nolibxml_free_buffer(void *xmlbuffer)
878 {
879 free(xmlbuffer);
880 }
881
882 /*************
883 * Callbacks *
884 *************/
885
886 static struct hwloc_xml_callbacks hwloc_xml_nolibxml_callbacks = {
887 hwloc_nolibxml_backend_init,
888 hwloc_nolibxml_export_file,
889 hwloc_nolibxml_export_buffer,
890 hwloc_nolibxml_free_buffer,
891 hwloc_nolibxml_import_diff,
892 hwloc_nolibxml_export_diff_file,
893 hwloc_nolibxml_export_diff_buffer
894 };
895
896 static struct hwloc_xml_component hwloc_nolibxml_xml_component = {
897 &hwloc_xml_nolibxml_callbacks,
898 NULL
899 };
900
901 const struct hwloc_component hwloc_xml_nolibxml_component = {
902 HWLOC_COMPONENT_ABI,
903 NULL, NULL,
904 HWLOC_COMPONENT_TYPE_XML,
905 0,
906 &hwloc_nolibxml_xml_component
907 };
908