geom_xml2tree.c revision 281303
1214478Srpaulo/*-
2190203Srpaulo * Copyright (c) 2003 Poul-Henning Kamp
3190203Srpaulo * All rights reserved.
4190203Srpaulo *
5190203Srpaulo * Redistribution and use in source and binary forms, with or without
6190203Srpaulo * modification, are permitted provided that the following conditions
7190203Srpaulo * are met:
8190203Srpaulo * 1. Redistributions of source code must retain the above copyright
9190203Srpaulo *    notice, this list of conditions and the following disclaimer.
10190203Srpaulo * 2. Redistributions in binary form must reproduce the above copyright
11190203Srpaulo *    notice, this list of conditions and the following disclaimer in the
12190203Srpaulo *    documentation and/or other materials provided with the distribution.
13190203Srpaulo * 3. The names of the authors may not be used to endorse or promote
14190203Srpaulo *    products derived from this software without specific prior written
15190203Srpaulo *    permission.
16190203Srpaulo *
17190203Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18190203Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19190203Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20190203Srpaulo * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21190203Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22190203Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23190203Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24190203Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25190203Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26190203Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27190203Srpaulo * SUCH DAMAGE.
28190203Srpaulo *
29190203Srpaulo * $FreeBSD: stable/10/lib/libgeom/geom_xml2tree.c 281303 2015-04-09 10:10:05Z mav $
30190203Srpaulo */
31190203Srpaulo
32190203Srpaulo#include <stdio.h>
33190203Srpaulo#include <inttypes.h>
34190203Srpaulo#include <stdlib.h>
35190203Srpaulo#include <string.h>
36190203Srpaulo#include <unistd.h>
37190203Srpaulo#include <errno.h>
38190203Srpaulo#include <fcntl.h>
39190203Srpaulo#include <ctype.h>
40190203Srpaulo#include <sys/stat.h>
41190203Srpaulo#include <sys/mman.h>
42190203Srpaulo#include <sys/queue.h>
43190203Srpaulo#include <sys/sbuf.h>
44190203Srpaulo#include <sys/sysctl.h>
45190203Srpaulo#include <err.h>
46190203Srpaulo#include <bsdxml.h>
47190203Srpaulo#include <libgeom.h>
48190203Srpaulo
49190203Srpaulostruct mystate {
50190203Srpaulo	struct gmesh		*mesh;
51190203Srpaulo	struct gclass		*class;
52190203Srpaulo	struct ggeom		*geom;
53190203Srpaulo	struct gprovider	*provider;
54190203Srpaulo	struct gconsumer	*consumer;
55190203Srpaulo	int			level;
56190203Srpaulo	struct sbuf		*sbuf[20];
57190203Srpaulo	struct gconf		*config;
58190203Srpaulo	int			nident;
59190203Srpaulo	XML_Parser		parser;
60190203Srpaulo	int			error;
61190203Srpaulo};
62190203Srpaulo
63190203Srpaulostatic void
64190203SrpauloStartElement(void *userData, const char *name, const char **attr)
65190203Srpaulo{
66190203Srpaulo	struct mystate *mt;
67190203Srpaulo	void *id;
68190203Srpaulo	void *ref;
69190203Srpaulo	int i;
70190203Srpaulo
71190203Srpaulo	mt = userData;
72190203Srpaulo	mt->level++;
73190203Srpaulo	mt->sbuf[mt->level] = sbuf_new_auto();
74190203Srpaulo	id = NULL;
75190203Srpaulo	ref = NULL;
76190203Srpaulo	for (i = 0; attr[i] != NULL; i += 2) {
77190203Srpaulo		if (!strcmp(attr[i], "id")) {
78190203Srpaulo			id = (void *)strtoul(attr[i + 1], NULL, 0);
79190203Srpaulo			mt->nident++;
80190203Srpaulo		} else if (!strcmp(attr[i], "ref")) {
81190203Srpaulo			ref = (void *)strtoul(attr[i + 1], NULL, 0);
82190203Srpaulo		} else
83190203Srpaulo			printf("%*.*s[%s = %s]\n",
84190203Srpaulo			    mt->level + 1, mt->level + 1, "",
85190203Srpaulo			    attr[i], attr[i + 1]);
86190203Srpaulo	}
87190203Srpaulo	if (!strcmp(name, "class") && mt->class == NULL) {
88190203Srpaulo		mt->class = calloc(1, sizeof *mt->class);
89190203Srpaulo		if (mt->class == NULL) {
90190203Srpaulo			mt->error = errno;
91190203Srpaulo			XML_StopParser(mt->parser, 0);
92190203Srpaulo			warn("Cannot allocate memory during processing of '%s' "
93190203Srpaulo			    "element", name);
94190203Srpaulo			return;
95190203Srpaulo		}
96190203Srpaulo		mt->class->lg_id = id;
97190203Srpaulo		LIST_INSERT_HEAD(&mt->mesh->lg_class, mt->class, lg_class);
98190203Srpaulo		LIST_INIT(&mt->class->lg_geom);
99190203Srpaulo		LIST_INIT(&mt->class->lg_config);
100190203Srpaulo		return;
101190203Srpaulo	}
102190203Srpaulo	if (!strcmp(name, "geom") && mt->geom == NULL) {
103190203Srpaulo		mt->geom = calloc(1, sizeof *mt->geom);
104190203Srpaulo		if (mt->geom == NULL) {
105190203Srpaulo			mt->error = errno;
106190203Srpaulo			XML_StopParser(mt->parser, 0);
107190203Srpaulo			warn("Cannot allocate memory during processing of '%s' "
108190203Srpaulo			    "element", name);
109190203Srpaulo			return;
110190203Srpaulo		}
111190203Srpaulo		mt->geom->lg_id = id;
112190203Srpaulo		LIST_INSERT_HEAD(&mt->class->lg_geom, mt->geom, lg_geom);
113190203Srpaulo		LIST_INIT(&mt->geom->lg_provider);
114190203Srpaulo		LIST_INIT(&mt->geom->lg_consumer);
115190203Srpaulo		LIST_INIT(&mt->geom->lg_config);
116190203Srpaulo		return;
117190203Srpaulo	}
118190203Srpaulo	if (!strcmp(name, "class") && mt->geom != NULL) {
119190203Srpaulo		mt->geom->lg_class = ref;
120190203Srpaulo		return;
121190203Srpaulo	}
122190203Srpaulo	if (!strcmp(name, "consumer") && mt->consumer == NULL) {
123190203Srpaulo		mt->consumer = calloc(1, sizeof *mt->consumer);
124190203Srpaulo		if (mt->consumer == NULL) {
125190203Srpaulo			mt->error = errno;
126190203Srpaulo			XML_StopParser(mt->parser, 0);
127190203Srpaulo			warn("Cannot allocate memory during processing of '%s' "
128190203Srpaulo			    "element", name);
129190203Srpaulo			return;
130190203Srpaulo		}
131190203Srpaulo		mt->consumer->lg_id = id;
132190203Srpaulo		LIST_INSERT_HEAD(&mt->geom->lg_consumer, mt->consumer,
133190203Srpaulo		    lg_consumer);
134190203Srpaulo		LIST_INIT(&mt->consumer->lg_config);
135190203Srpaulo		return;
136190203Srpaulo	}
137190203Srpaulo	if (!strcmp(name, "geom") && mt->consumer != NULL) {
138190203Srpaulo		mt->consumer->lg_geom = ref;
139190203Srpaulo		return;
140190203Srpaulo	}
141190203Srpaulo	if (!strcmp(name, "provider") && mt->consumer != NULL) {
142190203Srpaulo		mt->consumer->lg_provider = ref;
143190203Srpaulo		return;
144190203Srpaulo	}
145190203Srpaulo	if (!strcmp(name, "provider") && mt->provider == NULL) {
146190203Srpaulo		mt->provider = calloc(1, sizeof *mt->provider);
147190203Srpaulo		if (mt->provider == NULL) {
148190203Srpaulo			mt->error = errno;
149190203Srpaulo			XML_StopParser(mt->parser, 0);
150190203Srpaulo			warn("Cannot allocate memory during processing of '%s' "
151190203Srpaulo			    "element", name);
152190203Srpaulo			return;
153190203Srpaulo		}
154190203Srpaulo		mt->provider->lg_id = id;
155190203Srpaulo		LIST_INSERT_HEAD(&mt->geom->lg_provider, mt->provider,
156190203Srpaulo		    lg_provider);
157190203Srpaulo		LIST_INIT(&mt->provider->lg_consumers);
158190203Srpaulo		LIST_INIT(&mt->provider->lg_config);
159190203Srpaulo		return;
160190203Srpaulo	}
161190203Srpaulo	if (!strcmp(name, "geom") && mt->provider != NULL) {
162190203Srpaulo		mt->provider->lg_geom = ref;
163190203Srpaulo		return;
164190203Srpaulo	}
165190203Srpaulo	if (!strcmp(name, "config")) {
166190203Srpaulo		if (mt->provider != NULL) {
167190203Srpaulo			mt->config = &mt->provider->lg_config;
168190203Srpaulo			return;
169190203Srpaulo		}
170190203Srpaulo		if (mt->consumer != NULL) {
171190203Srpaulo			mt->config = &mt->consumer->lg_config;
172190203Srpaulo			return;
173190203Srpaulo		}
174190203Srpaulo		if (mt->geom != NULL) {
175190203Srpaulo			mt->config = &mt->geom->lg_config;
176190203Srpaulo			return;
177190203Srpaulo		}
178190203Srpaulo		if (mt->class != NULL) {
179190203Srpaulo			mt->config = &mt->class->lg_config;
180190203Srpaulo			return;
181190203Srpaulo		}
182190203Srpaulo	}
183190203Srpaulo}
184190203Srpaulo
185190203Srpaulostatic void
186190203SrpauloEndElement(void *userData, const char *name)
187190203Srpaulo{
188190203Srpaulo	struct mystate *mt;
189190203Srpaulo	struct gconf *c;
190190203Srpaulo	struct gconfig *gc;
191190203Srpaulo	char *p;
192190203Srpaulo
193190203Srpaulo	mt = userData;
194190203Srpaulo	p = NULL;
195190203Srpaulo	if (sbuf_finish(mt->sbuf[mt->level]) == 0)
196190203Srpaulo		p = strdup(sbuf_data(mt->sbuf[mt->level]));
197190203Srpaulo	sbuf_delete(mt->sbuf[mt->level]);
198190203Srpaulo	mt->sbuf[mt->level] = NULL;
199190203Srpaulo	mt->level--;
200190203Srpaulo	if (p == NULL) {
201190203Srpaulo		mt->error = errno;
202190203Srpaulo		XML_StopParser(mt->parser, 0);
203190203Srpaulo		warn("Cannot allocate memory during processing of '%s' "
204190203Srpaulo		    "element", name);
205190203Srpaulo		return;
206190203Srpaulo	}
207190203Srpaulo	if (strlen(p) == 0) {
208190203Srpaulo		free(p);
209190203Srpaulo		p = NULL;
210190203Srpaulo	}
211190203Srpaulo
212190203Srpaulo	if (!strcmp(name, "name")) {
213190203Srpaulo		if (mt->provider != NULL) {
214190203Srpaulo			mt->provider->lg_name = p;
215190203Srpaulo			return;
216190203Srpaulo		} else if (mt->geom != NULL) {
217190203Srpaulo			mt->geom->lg_name = p;
218190203Srpaulo			return;
219190203Srpaulo		} else if (mt->class != NULL) {
220190203Srpaulo			mt->class->lg_name = p;
221190203Srpaulo			return;
222190203Srpaulo		}
223190203Srpaulo	}
224214478Srpaulo	if (!strcmp(name, "rank") && mt->geom != NULL) {
225190203Srpaulo		mt->geom->lg_rank = strtoul(p, NULL, 0);
226190203Srpaulo		free(p);
227190203Srpaulo		return;
228190203Srpaulo	}
229190203Srpaulo	if (!strcmp(name, "mode") && mt->provider != NULL) {
230190203Srpaulo		mt->provider->lg_mode = p;
231190203Srpaulo		return;
232190203Srpaulo	}
233190203Srpaulo	if (!strcmp(name, "mode") && mt->consumer != NULL) {
234190203Srpaulo		mt->consumer->lg_mode = p;
235190203Srpaulo		return;
236190203Srpaulo	}
237190203Srpaulo	if (!strcmp(name, "mediasize") && mt->provider != NULL) {
238190203Srpaulo		mt->provider->lg_mediasize = strtoumax(p, NULL, 0);
239190203Srpaulo		free(p);
240190203Srpaulo		return;
241190203Srpaulo	}
242190203Srpaulo	if (!strcmp(name, "sectorsize") && mt->provider != NULL) {
243190203Srpaulo		mt->provider->lg_sectorsize = strtoul(p, NULL, 0);
244190203Srpaulo		free(p);
245190203Srpaulo		return;
246190203Srpaulo	}
247190203Srpaulo	if (!strcmp(name, "stripesize") && mt->provider != NULL) {
248190203Srpaulo		mt->provider->lg_stripesize = strtoumax(p, NULL, 0);
249190203Srpaulo		free(p);
250190203Srpaulo		return;
251190203Srpaulo	}
252190203Srpaulo	if (!strcmp(name, "stripeoffset") && mt->provider != NULL) {
253190203Srpaulo		mt->provider->lg_stripeoffset = strtoumax(p, NULL, 0);
254190203Srpaulo		free(p);
255190203Srpaulo		return;
256	}
257
258	if (!strcmp(name, "config")) {
259		mt->config = NULL;
260		return;
261	}
262
263	if (mt->config != NULL || (!strcmp(name, "wither") &&
264	    (mt->provider != NULL || mt->geom != NULL))) {
265		if (mt->config != NULL)
266			c = mt->config;
267		else if (mt->provider != NULL)
268			c = &mt->provider->lg_config;
269		else
270			c = &mt->geom->lg_config;
271		gc = calloc(1, sizeof *gc);
272		if (gc == NULL) {
273			mt->error = errno;
274			XML_StopParser(mt->parser, 0);
275			warn("Cannot allocate memory during processing of '%s' "
276			    "element", name);
277			return;
278		}
279		gc->lg_name = strdup(name);
280		if (gc->lg_name == NULL) {
281			free(gc);
282			mt->error = errno;
283			XML_StopParser(mt->parser, 0);
284			warn("Cannot allocate memory during processing of '%s' "
285			    "element", name);
286			return;
287		}
288		gc->lg_val = p ? p : strdup("1");
289		LIST_INSERT_HEAD(c, gc, lg_config);
290		return;
291	}
292
293	if (p != NULL) {
294#if DEBUG_LIBGEOM > 0
295		printf("Unexpected XML: name=%s data=\"%s\"\n", name, p);
296#endif
297		free(p);
298	}
299
300	if (!strcmp(name, "consumer") && mt->consumer != NULL) {
301		mt->consumer = NULL;
302		return;
303	}
304	if (!strcmp(name, "provider") && mt->provider != NULL) {
305		mt->provider = NULL;
306		return;
307	}
308	if (!strcmp(name, "geom") && mt->consumer != NULL) {
309		return;
310	}
311	if (!strcmp(name, "geom") && mt->provider != NULL) {
312		return;
313	}
314	if (!strcmp(name, "geom") && mt->geom != NULL) {
315		mt->geom = NULL;
316		return;
317	}
318	if (!strcmp(name, "class") && mt->geom != NULL) {
319		return;
320	}
321	if (!strcmp(name, "class") && mt->class != NULL) {
322		mt->class = NULL;
323		return;
324	}
325}
326
327static void
328CharData(void *userData , const XML_Char *s , int len)
329{
330	struct mystate *mt;
331	const char *b, *e;
332
333	mt = userData;
334
335	b = s;
336	e = s + len - 1;
337	while (isspace(*b) && b < e)
338		b++;
339	while (isspace(*e) && e > b)
340		e--;
341	if (e != b || (*b && !isspace(*b)))
342		sbuf_bcat(mt->sbuf[mt->level], b, e - b + 1);
343}
344
345struct gident *
346geom_lookupid(struct gmesh *gmp, const void *id)
347{
348	struct gident *gip;
349
350	for (gip = gmp->lg_ident; gip->lg_id != NULL; gip++)
351		if (gip->lg_id == id)
352			return (gip);
353	return (NULL);
354}
355
356int
357geom_xml2tree(struct gmesh *gmp, char *p)
358{
359	XML_Parser parser;
360	struct mystate *mt;
361	struct gclass *cl;
362	struct ggeom *ge;
363	struct gprovider *pr;
364	struct gconsumer *co;
365	int error, i;
366
367	memset(gmp, 0, sizeof *gmp);
368	LIST_INIT(&gmp->lg_class);
369	parser = XML_ParserCreate(NULL);
370	if (parser == NULL)
371		return (ENOMEM);
372	mt = calloc(1, sizeof *mt);
373	if (mt == NULL) {
374		XML_ParserFree(parser);
375		return (ENOMEM);
376	}
377	mt->mesh = gmp;
378	mt->parser = parser;
379	error = 0;
380	XML_SetUserData(parser, mt);
381	XML_SetElementHandler(parser, StartElement, EndElement);
382	XML_SetCharacterDataHandler(parser, CharData);
383	i = XML_Parse(parser, p, strlen(p), 1);
384	if (mt->error != 0)
385		error = mt->error;
386	else if (i != 1) {
387		error = XML_GetErrorCode(parser) == XML_ERROR_NO_MEMORY ?
388		    ENOMEM : EILSEQ;
389	}
390	XML_ParserFree(parser);
391	if (error != 0) {
392		free(mt);
393		return (error);
394	}
395	gmp->lg_ident = calloc(sizeof *gmp->lg_ident, mt->nident + 1);
396	free(mt);
397	if (gmp->lg_ident == NULL)
398		return (ENOMEM);
399	i = 0;
400	/* Collect all identifiers */
401	LIST_FOREACH(cl, &gmp->lg_class, lg_class) {
402		gmp->lg_ident[i].lg_id = cl->lg_id;
403		gmp->lg_ident[i].lg_ptr = cl;
404		gmp->lg_ident[i].lg_what = ISCLASS;
405		i++;
406		LIST_FOREACH(ge, &cl->lg_geom, lg_geom) {
407			gmp->lg_ident[i].lg_id = ge->lg_id;
408			gmp->lg_ident[i].lg_ptr = ge;
409			gmp->lg_ident[i].lg_what = ISGEOM;
410			i++;
411			LIST_FOREACH(pr, &ge->lg_provider, lg_provider) {
412				gmp->lg_ident[i].lg_id = pr->lg_id;
413				gmp->lg_ident[i].lg_ptr = pr;
414				gmp->lg_ident[i].lg_what = ISPROVIDER;
415				i++;
416			}
417			LIST_FOREACH(co, &ge->lg_consumer, lg_consumer) {
418				gmp->lg_ident[i].lg_id = co->lg_id;
419				gmp->lg_ident[i].lg_ptr = co;
420				gmp->lg_ident[i].lg_what = ISCONSUMER;
421				i++;
422			}
423		}
424	}
425	/* Substitute all identifiers */
426	LIST_FOREACH(cl, &gmp->lg_class, lg_class) {
427		LIST_FOREACH(ge, &cl->lg_geom, lg_geom) {
428			ge->lg_class =
429			    geom_lookupid(gmp, ge->lg_class)->lg_ptr;
430			LIST_FOREACH(pr, &ge->lg_provider, lg_provider) {
431				pr->lg_geom =
432				    geom_lookupid(gmp, pr->lg_geom)->lg_ptr;
433			}
434			LIST_FOREACH(co, &ge->lg_consumer, lg_consumer) {
435				co->lg_geom =
436				    geom_lookupid(gmp, co->lg_geom)->lg_ptr;
437				if (co->lg_provider != NULL) {
438					co->lg_provider =
439					    geom_lookupid(gmp,
440						co->lg_provider)->lg_ptr;
441					LIST_INSERT_HEAD(
442					    &co->lg_provider->lg_consumers,
443					    co, lg_consumers);
444				}
445			}
446		}
447	}
448	return (0);
449}
450
451int
452geom_gettree(struct gmesh *gmp)
453{
454	char *p;
455	int error;
456
457	p = geom_getxml();
458	if (p == NULL)
459		return (errno);
460	error = geom_xml2tree(gmp, p);
461	free(p);
462	return (error);
463}
464
465static void
466delete_config(struct gconf *gp)
467{
468	struct gconfig *cf;
469
470	for (;;) {
471		cf = LIST_FIRST(gp);
472		if (cf == NULL)
473			return;
474		LIST_REMOVE(cf, lg_config);
475		free(cf->lg_name);
476		free(cf->lg_val);
477		free(cf);
478	}
479}
480
481void
482geom_deletetree(struct gmesh *gmp)
483{
484	struct gclass *cl;
485	struct ggeom *ge;
486	struct gprovider *pr;
487	struct gconsumer *co;
488
489	free(gmp->lg_ident);
490	gmp->lg_ident = NULL;
491	for (;;) {
492		cl = LIST_FIRST(&gmp->lg_class);
493		if (cl == NULL)
494			break;
495		LIST_REMOVE(cl, lg_class);
496		delete_config(&cl->lg_config);
497		if (cl->lg_name) free(cl->lg_name);
498		for (;;) {
499			ge = LIST_FIRST(&cl->lg_geom);
500			if (ge == NULL)
501				break;
502			LIST_REMOVE(ge, lg_geom);
503			delete_config(&ge->lg_config);
504			if (ge->lg_name) free(ge->lg_name);
505			for (;;) {
506				pr = LIST_FIRST(&ge->lg_provider);
507				if (pr == NULL)
508					break;
509				LIST_REMOVE(pr, lg_provider);
510				delete_config(&pr->lg_config);
511				if (pr->lg_name) free(pr->lg_name);
512				if (pr->lg_mode) free(pr->lg_mode);
513				free(pr);
514			}
515			for (;;) {
516				co = LIST_FIRST(&ge->lg_consumer);
517				if (co == NULL)
518					break;
519				LIST_REMOVE(co, lg_consumer);
520				delete_config(&co->lg_config);
521				if (co->lg_mode) free(co->lg_mode);
522				free(co);
523			}
524			free(ge);
525		}
526		free(cl);
527	}
528}
529