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