1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause-FreeBSD
3 *
4 * Copyright (c) 2003 Poul-Henning Kamp
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The names of the authors may not be used to endorse or promote
16 * products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * $FreeBSD: stable/12/lib/libgeom/geom_xml2tree.c 370203 2021-07-27 17:42:04Z asomers $
32 */
33
34 #include <stdio.h>
35 #include <inttypes.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unistd.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <ctype.h>
42 #include <sys/stat.h>
43 #include <sys/mman.h>
44 #include <sys/queue.h>
45 #include <sys/sbuf.h>
46 #include <sys/sysctl.h>
47 #include <err.h>
48 #include <bsdxml.h>
49 #include <libgeom.h>
50
51 struct mystate {
52 struct gmesh *mesh;
53 struct gclass *class;
54 struct ggeom *geom;
55 struct gprovider *provider;
56 struct gconsumer *consumer;
57 int level;
58 struct sbuf *sbuf[20];
59 struct gconf *config;
60 int nident;
61 XML_Parser parser;
62 int error;
63 };
64
65 static void
StartElement(void * userData,const char * name,const char ** attr)66 StartElement(void *userData, const char *name, const char **attr)
67 {
68 struct mystate *mt;
69 void *id;
70 void *ref;
71 int i;
72
73 mt = userData;
74 mt->level++;
75 mt->sbuf[mt->level] = sbuf_new_auto();
76 id = NULL;
77 ref = NULL;
78 for (i = 0; attr[i] != NULL; i += 2) {
79 if (!strcmp(attr[i], "id")) {
80 id = (void *)strtoul(attr[i + 1], NULL, 0);
81 mt->nident++;
82 } else if (!strcmp(attr[i], "ref")) {
83 ref = (void *)strtoul(attr[i + 1], NULL, 0);
84 } else
85 printf("%*.*s[%s = %s]\n",
86 mt->level + 1, mt->level + 1, "",
87 attr[i], attr[i + 1]);
88 }
89 if (!strcmp(name, "class") && mt->class == NULL) {
90 mt->class = calloc(1, sizeof *mt->class);
91 if (mt->class == NULL) {
92 mt->error = errno;
93 XML_StopParser(mt->parser, 0);
94 warn("Cannot allocate memory during processing of '%s' "
95 "element", name);
96 return;
97 }
98 mt->class->lg_id = id;
99 LIST_INSERT_HEAD(&mt->mesh->lg_class, mt->class, lg_class);
100 LIST_INIT(&mt->class->lg_geom);
101 LIST_INIT(&mt->class->lg_config);
102 return;
103 }
104 if (!strcmp(name, "geom") && mt->geom == NULL) {
105 mt->geom = calloc(1, sizeof *mt->geom);
106 if (mt->geom == NULL) {
107 mt->error = errno;
108 XML_StopParser(mt->parser, 0);
109 warn("Cannot allocate memory during processing of '%s' "
110 "element", name);
111 return;
112 }
113 mt->geom->lg_id = id;
114 LIST_INSERT_HEAD(&mt->class->lg_geom, mt->geom, lg_geom);
115 LIST_INIT(&mt->geom->lg_provider);
116 LIST_INIT(&mt->geom->lg_consumer);
117 LIST_INIT(&mt->geom->lg_config);
118 return;
119 }
120 if (!strcmp(name, "class") && mt->geom != NULL) {
121 mt->geom->lg_class = ref;
122 return;
123 }
124 if (!strcmp(name, "consumer") && mt->consumer == NULL) {
125 mt->consumer = calloc(1, sizeof *mt->consumer);
126 if (mt->consumer == NULL) {
127 mt->error = errno;
128 XML_StopParser(mt->parser, 0);
129 warn("Cannot allocate memory during processing of '%s' "
130 "element", name);
131 return;
132 }
133 mt->consumer->lg_id = id;
134 LIST_INSERT_HEAD(&mt->geom->lg_consumer, mt->consumer,
135 lg_consumer);
136 LIST_INIT(&mt->consumer->lg_config);
137 return;
138 }
139 if (!strcmp(name, "geom") && mt->consumer != NULL) {
140 mt->consumer->lg_geom = ref;
141 return;
142 }
143 if (!strcmp(name, "provider") && mt->consumer != NULL) {
144 mt->consumer->lg_provider = ref;
145 return;
146 }
147 if (!strcmp(name, "provider") && mt->provider == NULL) {
148 mt->provider = calloc(1, sizeof *mt->provider);
149 if (mt->provider == NULL) {
150 mt->error = errno;
151 XML_StopParser(mt->parser, 0);
152 warn("Cannot allocate memory during processing of '%s' "
153 "element", name);
154 return;
155 }
156 mt->provider->lg_id = id;
157 LIST_INSERT_HEAD(&mt->geom->lg_provider, mt->provider,
158 lg_provider);
159 LIST_INIT(&mt->provider->lg_consumers);
160 LIST_INIT(&mt->provider->lg_config);
161 return;
162 }
163 if (!strcmp(name, "geom") && mt->provider != NULL) {
164 mt->provider->lg_geom = ref;
165 return;
166 }
167 if (!strcmp(name, "config")) {
168 if (mt->provider != NULL) {
169 mt->config = &mt->provider->lg_config;
170 return;
171 }
172 if (mt->consumer != NULL) {
173 mt->config = &mt->consumer->lg_config;
174 return;
175 }
176 if (mt->geom != NULL) {
177 mt->config = &mt->geom->lg_config;
178 return;
179 }
180 if (mt->class != NULL) {
181 mt->config = &mt->class->lg_config;
182 return;
183 }
184 }
185 }
186
187 static void
EndElement(void * userData,const char * name)188 EndElement(void *userData, const char *name)
189 {
190 struct mystate *mt;
191 struct gconf *c;
192 struct gconfig *gc;
193 char *p;
194
195 mt = userData;
196 p = NULL;
197 if (sbuf_finish(mt->sbuf[mt->level]) == 0)
198 p = strdup(sbuf_data(mt->sbuf[mt->level]));
199 sbuf_delete(mt->sbuf[mt->level]);
200 mt->sbuf[mt->level] = NULL;
201 mt->level--;
202 if (p == NULL) {
203 mt->error = errno;
204 XML_StopParser(mt->parser, 0);
205 warn("Cannot allocate memory during processing of '%s' "
206 "element", name);
207 return;
208 }
209 if (strlen(p) == 0) {
210 free(p);
211 p = NULL;
212 }
213
214 if (!strcmp(name, "name")) {
215 if (mt->provider != NULL) {
216 mt->provider->lg_name = p;
217 return;
218 } else if (mt->geom != NULL) {
219 mt->geom->lg_name = p;
220 return;
221 } else if (mt->class != NULL) {
222 mt->class->lg_name = p;
223 return;
224 }
225 }
226 if (!strcmp(name, "rank") && mt->geom != NULL) {
227 mt->geom->lg_rank = strtoul(p, NULL, 0);
228 free(p);
229 return;
230 }
231 if (!strcmp(name, "mode") && mt->provider != NULL) {
232 mt->provider->lg_mode = p;
233 return;
234 }
235 if (!strcmp(name, "mode") && mt->consumer != NULL) {
236 mt->consumer->lg_mode = p;
237 return;
238 }
239 if (!strcmp(name, "mediasize") && mt->provider != NULL) {
240 mt->provider->lg_mediasize = strtoumax(p, NULL, 0);
241 free(p);
242 return;
243 }
244 if (!strcmp(name, "sectorsize") && mt->provider != NULL) {
245 mt->provider->lg_sectorsize = strtoul(p, NULL, 0);
246 free(p);
247 return;
248 }
249 if (!strcmp(name, "stripesize") && mt->provider != NULL) {
250 mt->provider->lg_stripesize = strtoumax(p, NULL, 0);
251 free(p);
252 return;
253 }
254 if (!strcmp(name, "stripeoffset") && mt->provider != NULL) {
255 mt->provider->lg_stripeoffset = strtoumax(p, NULL, 0);
256 free(p);
257 return;
258 }
259
260 if (!strcmp(name, "config")) {
261 mt->config = NULL;
262 free(p);
263 return;
264 }
265
266 if (mt->config != NULL || (!strcmp(name, "wither") &&
267 (mt->provider != NULL || mt->geom != NULL))) {
268 if (mt->config != NULL)
269 c = mt->config;
270 else if (mt->provider != NULL)
271 c = &mt->provider->lg_config;
272 else
273 c = &mt->geom->lg_config;
274 gc = calloc(1, sizeof *gc);
275 if (gc == NULL) {
276 mt->error = errno;
277 XML_StopParser(mt->parser, 0);
278 warn("Cannot allocate memory during processing of '%s' "
279 "element", name);
280 free(p);
281 return;
282 }
283 gc->lg_name = strdup(name);
284 if (gc->lg_name == NULL) {
285 mt->error = errno;
286 XML_StopParser(mt->parser, 0);
287 warn("Cannot allocate memory during processing of '%s' "
288 "element", name);
289 free(gc);
290 free(p);
291 return;
292 }
293 gc->lg_val = p;
294 LIST_INSERT_HEAD(c, gc, lg_config);
295 return;
296 }
297
298 if (p != NULL) {
299 #if DEBUG_LIBGEOM > 0
300 printf("Unexpected XML: name=%s data=\"%s\"\n", name, p);
301 #endif
302 free(p);
303 }
304
305 if (!strcmp(name, "consumer") && mt->consumer != NULL) {
306 mt->consumer = NULL;
307 return;
308 }
309 if (!strcmp(name, "provider") && mt->provider != NULL) {
310 mt->provider = NULL;
311 return;
312 }
313 if (!strcmp(name, "geom") && mt->consumer != NULL) {
314 return;
315 }
316 if (!strcmp(name, "geom") && mt->provider != NULL) {
317 return;
318 }
319 if (!strcmp(name, "geom") && mt->geom != NULL) {
320 mt->geom = NULL;
321 return;
322 }
323 if (!strcmp(name, "class") && mt->geom != NULL) {
324 return;
325 }
326 if (!strcmp(name, "class") && mt->class != NULL) {
327 mt->class = NULL;
328 return;
329 }
330 }
331
332 static void
CharData(void * userData,const XML_Char * s,int len)333 CharData(void *userData , const XML_Char *s , int len)
334 {
335 struct mystate *mt;
336 const char *b, *e;
337
338 mt = userData;
339
340 b = s;
341 e = s + len - 1;
342 while (isspace(*b) && b < e)
343 b++;
344 while (isspace(*e) && e > b)
345 e--;
346 if (e != b || (*b && !isspace(*b)))
347 sbuf_bcat(mt->sbuf[mt->level], b, e - b + 1);
348 }
349
350 struct gident *
geom_lookupid(struct gmesh * gmp,const void * id)351 geom_lookupid(struct gmesh *gmp, const void *id)
352 {
353 struct gident *gip;
354
355 for (gip = gmp->lg_ident; gip->lg_id != NULL; gip++)
356 if (gip->lg_id == id)
357 return (gip);
358 return (NULL);
359 }
360
361 int
geom_xml2tree(struct gmesh * gmp,char * p)362 geom_xml2tree(struct gmesh *gmp, char *p)
363 {
364 XML_Parser parser;
365 struct mystate *mt;
366 struct gclass *cl;
367 struct ggeom *ge;
368 struct gprovider *pr;
369 struct gconsumer *co;
370 int error, i;
371
372 memset(gmp, 0, sizeof *gmp);
373 LIST_INIT(&gmp->lg_class);
374 parser = XML_ParserCreate(NULL);
375 if (parser == NULL)
376 return (ENOMEM);
377 mt = calloc(1, sizeof *mt);
378 if (mt == NULL) {
379 XML_ParserFree(parser);
380 return (ENOMEM);
381 }
382 mt->mesh = gmp;
383 mt->parser = parser;
384 error = 0;
385 XML_SetUserData(parser, mt);
386 XML_SetElementHandler(parser, StartElement, EndElement);
387 XML_SetCharacterDataHandler(parser, CharData);
388 i = XML_Parse(parser, p, strlen(p), 1);
389 if (mt->error != 0)
390 error = mt->error;
391 else if (i != 1) {
392 error = XML_GetErrorCode(parser) == XML_ERROR_NO_MEMORY ?
393 ENOMEM : EILSEQ;
394 }
395 XML_ParserFree(parser);
396 if (error != 0) {
397 free(mt);
398 return (error);
399 }
400 gmp->lg_ident = calloc(sizeof *gmp->lg_ident, mt->nident + 1);
401 free(mt);
402 if (gmp->lg_ident == NULL)
403 return (ENOMEM);
404 i = 0;
405 /* Collect all identifiers */
406 LIST_FOREACH(cl, &gmp->lg_class, lg_class) {
407 gmp->lg_ident[i].lg_id = cl->lg_id;
408 gmp->lg_ident[i].lg_ptr = cl;
409 gmp->lg_ident[i].lg_what = ISCLASS;
410 i++;
411 LIST_FOREACH(ge, &cl->lg_geom, lg_geom) {
412 gmp->lg_ident[i].lg_id = ge->lg_id;
413 gmp->lg_ident[i].lg_ptr = ge;
414 gmp->lg_ident[i].lg_what = ISGEOM;
415 i++;
416 LIST_FOREACH(pr, &ge->lg_provider, lg_provider) {
417 gmp->lg_ident[i].lg_id = pr->lg_id;
418 gmp->lg_ident[i].lg_ptr = pr;
419 gmp->lg_ident[i].lg_what = ISPROVIDER;
420 i++;
421 }
422 LIST_FOREACH(co, &ge->lg_consumer, lg_consumer) {
423 gmp->lg_ident[i].lg_id = co->lg_id;
424 gmp->lg_ident[i].lg_ptr = co;
425 gmp->lg_ident[i].lg_what = ISCONSUMER;
426 i++;
427 }
428 }
429 }
430 /* Substitute all identifiers */
431 LIST_FOREACH(cl, &gmp->lg_class, lg_class) {
432 LIST_FOREACH(ge, &cl->lg_geom, lg_geom) {
433 ge->lg_class =
434 geom_lookupid(gmp, ge->lg_class)->lg_ptr;
435 LIST_FOREACH(pr, &ge->lg_provider, lg_provider) {
436 pr->lg_geom =
437 geom_lookupid(gmp, pr->lg_geom)->lg_ptr;
438 }
439 LIST_FOREACH(co, &ge->lg_consumer, lg_consumer) {
440 co->lg_geom =
441 geom_lookupid(gmp, co->lg_geom)->lg_ptr;
442 if (co->lg_provider != NULL) {
443 co->lg_provider =
444 geom_lookupid(gmp,
445 co->lg_provider)->lg_ptr;
446 LIST_INSERT_HEAD(
447 &co->lg_provider->lg_consumers,
448 co, lg_consumers);
449 }
450 }
451 }
452 }
453 return (0);
454 }
455
456 int
geom_gettree(struct gmesh * gmp)457 geom_gettree(struct gmesh *gmp)
458 {
459 char *p;
460 int error;
461
462 p = geom_getxml();
463 if (p == NULL)
464 return (errno);
465 error = geom_xml2tree(gmp, p);
466 free(p);
467 return (error);
468 }
469
470 static void
delete_config(struct gconf * gp)471 delete_config(struct gconf *gp)
472 {
473 struct gconfig *cf;
474
475 for (;;) {
476 cf = LIST_FIRST(gp);
477 if (cf == NULL)
478 return;
479 LIST_REMOVE(cf, lg_config);
480 free(cf->lg_name);
481 free(cf->lg_val);
482 free(cf);
483 }
484 }
485
486 void
geom_deletetree(struct gmesh * gmp)487 geom_deletetree(struct gmesh *gmp)
488 {
489 struct gclass *cl;
490 struct ggeom *ge;
491 struct gprovider *pr;
492 struct gconsumer *co;
493
494 free(gmp->lg_ident);
495 gmp->lg_ident = NULL;
496 for (;;) {
497 cl = LIST_FIRST(&gmp->lg_class);
498 if (cl == NULL)
499 break;
500 LIST_REMOVE(cl, lg_class);
501 delete_config(&cl->lg_config);
502 if (cl->lg_name) free(cl->lg_name);
503 for (;;) {
504 ge = LIST_FIRST(&cl->lg_geom);
505 if (ge == NULL)
506 break;
507 LIST_REMOVE(ge, lg_geom);
508 delete_config(&ge->lg_config);
509 if (ge->lg_name) free(ge->lg_name);
510 for (;;) {
511 pr = LIST_FIRST(&ge->lg_provider);
512 if (pr == NULL)
513 break;
514 LIST_REMOVE(pr, lg_provider);
515 delete_config(&pr->lg_config);
516 if (pr->lg_name) free(pr->lg_name);
517 if (pr->lg_mode) free(pr->lg_mode);
518 free(pr);
519 }
520 for (;;) {
521 co = LIST_FIRST(&ge->lg_consumer);
522 if (co == NULL)
523 break;
524 LIST_REMOVE(co, lg_consumer);
525 delete_config(&co->lg_config);
526 if (co->lg_mode) free(co->lg_mode);
527 free(co);
528 }
529 free(ge);
530 }
531 free(cl);
532 }
533 }
534