geom_xml2tree.c revision 110603
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 110603 2003-02-10 00:11:43Z phk $
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(NULL, NULL, 0, SBUF_AUTOEXTEND);
72	id = NULL;
73	for (i = 0; attr[i] != NULL; i += 2) {
74		if (!strcmp(attr[i], "id")) {
75			id = (void *)strtoul(attr[i + 1], NULL, 0);
76			mt->nident++;
77		} else if (!strcmp(attr[i], "ref")) {
78			ref = (void *)strtoul(attr[i + 1], NULL, 0);
79		} else
80			printf("%*.*s[%s = %s]\n",
81			    mt->level + 1, mt->level + 1, "",
82			    attr[i], attr[i + 1]);
83	}
84	if (!strcmp(name, "class") && mt->class == NULL) {
85		mt->class = calloc(1, sizeof *mt->class);
86		mt->class->id = id;
87		LIST_INSERT_HEAD(&mt->mesh->class, mt->class, class);
88		LIST_INIT(&mt->class->geom);
89		LIST_INIT(&mt->class->config);
90		return;
91	}
92	if (!strcmp(name, "geom") && mt->geom == NULL) {
93		mt->geom = calloc(1, sizeof *mt->geom);
94		mt->geom->id = id;
95		LIST_INSERT_HEAD(&mt->class->geom, mt->geom, geom);
96		LIST_INIT(&mt->geom->provider);
97		LIST_INIT(&mt->geom->consumer);
98		LIST_INIT(&mt->geom->config);
99		return;
100	}
101	if (!strcmp(name, "class") && mt->geom != NULL) {
102		mt->geom->class = ref;
103		return;
104	}
105	if (!strcmp(name, "consumer") && mt->consumer == NULL) {
106		mt->consumer = calloc(1, sizeof *mt->consumer);
107		mt->consumer->id = id;
108		LIST_INSERT_HEAD(&mt->geom->consumer, mt->consumer, consumer);
109		LIST_INIT(&mt->consumer->config);
110		return;
111	}
112	if (!strcmp(name, "geom") && mt->consumer != NULL) {
113		mt->consumer->geom = ref;
114		return;
115	}
116	if (!strcmp(name, "provider") && mt->consumer != NULL) {
117		mt->consumer->provider = ref;
118		return;
119	}
120	if (!strcmp(name, "provider") && mt->provider == NULL) {
121		mt->provider = calloc(1, sizeof *mt->provider);
122		mt->provider->id = id;
123		LIST_INSERT_HEAD(&mt->geom->provider, mt->provider, provider);
124		LIST_INIT(&mt->provider->consumers);
125		LIST_INIT(&mt->provider->config);
126		return;
127	}
128	if (!strcmp(name, "geom") && mt->provider != NULL) {
129		mt->provider->geom = ref;
130		return;
131	}
132	if (!strcmp(name, "config")) {
133		if (mt->provider != NULL) {
134			mt->config = &mt->provider->config;
135			return;
136		}
137		if (mt->consumer != NULL) {
138			mt->config = &mt->consumer->config;
139			return;
140		}
141		if (mt->geom != NULL) {
142			mt->config = &mt->geom->config;
143			return;
144		}
145		if (mt->class != NULL) {
146			mt->config = &mt->class->config;
147			return;
148		}
149	}
150}
151
152static void
153EndElement(void *userData, const char *name)
154{
155	struct mystate *mt;
156	struct gconfig *gc;
157	char *p;
158
159	mt = userData;
160	sbuf_finish(mt->sbuf[mt->level]);
161	p = strdup(sbuf_data(mt->sbuf[mt->level]));
162	sbuf_delete(mt->sbuf[mt->level]);
163	mt->sbuf[mt->level] = NULL;
164	mt->level--;
165	if (strlen(p) == 0) {
166		free(p);
167		p = NULL;
168	}
169
170	if (!strcmp(name, "name")) {
171		if (mt->provider != NULL) {
172			mt->provider->name = p;
173			return;
174		} else if (mt->geom != NULL) {
175			mt->geom->name = p;
176			return;
177		} else if (mt->class != NULL) {
178			mt->class->name = p;
179			return;
180		}
181	}
182	if (!strcmp(name, "rank") && mt->geom != NULL) {
183		mt->geom->rank = strtoul(p, NULL, 0);
184		free(p);
185		return;
186	}
187	if (!strcmp(name, "mode") && mt->provider != NULL) {
188		mt->provider->mode = p;
189		return;
190	}
191	if (!strcmp(name, "mode") && mt->consumer != NULL) {
192		mt->consumer->mode = p;
193		return;
194	}
195	if (!strcmp(name, "mediasize") && mt->provider != NULL) {
196		mt->provider->mediasize = strtoumax(p, NULL, 0);
197		free(p);
198		return;
199	}
200	if (!strcmp(name, "sectorsize") && mt->provider != NULL) {
201		mt->provider->sectorsize = strtoul(p, NULL, 0);
202		free(p);
203		return;
204	}
205
206	if (!strcmp(name, "config")) {
207		mt->config = NULL;
208		return;
209	}
210
211	if (mt->config != NULL) {
212		gc = calloc(sizeof *gc, 1);
213		gc->name = strdup(name);
214		gc->val = p;
215		LIST_INSERT_HEAD(mt->config, gc, config);
216		return;
217	}
218
219	if (p != NULL) {
220printf("<<<%s>>>\n", p);
221		free(p);
222	}
223
224	if (!strcmp(name, "consumer") && mt->consumer != NULL) {
225		mt->consumer = NULL;
226		return;
227	}
228	if (!strcmp(name, "provider") && mt->provider != NULL) {
229		mt->provider = NULL;
230		return;
231	}
232	if (!strcmp(name, "geom") && mt->consumer != NULL) {
233		return;
234	}
235	if (!strcmp(name, "geom") && mt->provider != NULL) {
236		return;
237	}
238	if (!strcmp(name, "geom") && mt->geom != NULL) {
239		mt->geom = NULL;
240		return;
241	}
242	if (!strcmp(name, "class") && mt->geom != NULL) {
243		return;
244	}
245	if (!strcmp(name, "class") && mt->class != NULL) {
246		mt->class = NULL;
247		return;
248	}
249}
250
251static void
252CharData(void *userData , const XML_Char *s , int len)
253{
254	struct mystate *mt;
255	const char *b, *e;
256
257	mt = userData;
258
259	b = s;
260	e = s + len - 1;
261	while (isspace(*b) && b < e)
262		b++;
263	while (isspace(*e) && e > b)
264		e--;
265	if (e != b || (*b && !isspace(*b)))
266		sbuf_bcat(mt->sbuf[mt->level], b, e - b + 1);
267}
268
269struct gident *
270geom_lookupid(struct gmesh *gmp, void *id)
271{
272	struct gident *gip;
273
274	for (gip = gmp->ident; gip->id != NULL; gip++)
275		if (gip->id == id)
276			return (gip);
277	return (NULL);
278}
279
280int
281geom_xml2tree(struct gmesh *gmp, char *p)
282{
283	XML_Parser parser;
284	struct mystate *mt;
285	struct gclass *cl;
286	struct ggeom *ge;
287	struct gprovider *pr;
288	struct gconsumer *co;
289	int i;
290
291	memset(gmp, 0, sizeof *gmp);
292	LIST_INIT(&gmp->class);
293	parser = XML_ParserCreate(NULL);
294	mt = calloc(1, sizeof *mt);
295	if (mt == NULL)
296		return (ENOMEM);
297	mt->mesh = gmp;
298	XML_SetUserData(parser, mt);
299	XML_SetElementHandler(parser, StartElement, EndElement);
300	XML_SetCharacterDataHandler(parser, CharData);
301	i = XML_Parse(parser, p, strlen(p), 1);
302	if (i != 1)
303		return (-1);
304	XML_ParserFree(parser);
305	gmp->ident = calloc(sizeof *gmp->ident, mt->nident + 1);
306	if (gmp->ident == NULL)
307		return (ENOMEM);
308	free(mt);
309	i = 0;
310	/* Collect all identifiers */
311	LIST_FOREACH(cl, &gmp->class, class) {
312		gmp->ident[i].id = cl->id;
313		gmp->ident[i].ptr = cl;
314		gmp->ident[i].what = ISCLASS;
315		i++;
316		LIST_FOREACH(ge, &cl->geom, geom) {
317			gmp->ident[i].id = ge->id;
318			gmp->ident[i].ptr = ge;
319			gmp->ident[i].what = ISGEOM;
320			i++;
321			LIST_FOREACH(pr, &ge->provider, provider) {
322				gmp->ident[i].id = pr->id;
323				gmp->ident[i].ptr = pr;
324				gmp->ident[i].what = ISPROVIDER;
325				i++;
326			}
327			LIST_FOREACH(co, &ge->consumer, consumer) {
328				gmp->ident[i].id = co->id;
329				gmp->ident[i].ptr = co;
330				gmp->ident[i].what = ISCONSUMER;
331				i++;
332			}
333		}
334	}
335	/* Substitute all identifiers */
336	LIST_FOREACH(cl, &gmp->class, class) {
337		LIST_FOREACH(ge, &cl->geom, geom) {
338			ge->class = geom_lookupid(gmp, ge->class)->ptr;
339			LIST_FOREACH(pr, &ge->provider, provider) {
340				pr->geom = geom_lookupid(gmp, pr->geom)->ptr;
341			}
342			LIST_FOREACH(co, &ge->consumer, consumer) {
343				co->geom = geom_lookupid(gmp, co->geom)->ptr;
344				if (co->provider != NULL)
345					co->provider =
346					    geom_lookupid(gmp, co->provider)->ptr;
347			}
348		}
349	}
350	return (0);
351}
352
353int
354geom_gettree(struct gmesh *gmp)
355{
356	char *p;
357	int error;
358
359	p = geom_getxml();
360	error = geom_xml2tree(gmp, p);
361	free(p);
362	return (error);
363}
364
365static void
366delete_config(struct gconf *gp)
367{
368	struct gconfig *cf;
369
370	for (;;) {
371		cf = LIST_FIRST(gp);
372		if (cf == NULL)
373			return;
374		LIST_REMOVE(cf, config);
375		free(cf->name);
376		free(cf->val);
377		free(cf);
378	}
379}
380
381void
382geom_deletetree(struct gmesh *gmp)
383{
384	struct gclass *cl;
385	struct ggeom *ge;
386	struct gprovider *pr;
387	struct gconsumer *co;
388
389	free(gmp->ident);
390	gmp->ident = NULL;
391	for (;;) {
392		cl = LIST_FIRST(&gmp->class);
393		if (cl == NULL)
394			break;
395		LIST_REMOVE(cl, class);
396		delete_config(&cl->config);
397		if (cl->name) free(cl->name);
398		for (;;) {
399			ge = LIST_FIRST(&cl->geom);
400			if (ge == NULL)
401				break;
402			LIST_REMOVE(ge, geom);
403			delete_config(&ge->config);
404			if (ge->name) free(ge->name);
405			for (;;) {
406				pr = LIST_FIRST(&ge->provider);
407				if (pr == NULL)
408					break;
409				LIST_REMOVE(pr, provider);
410				delete_config(&pr->config);
411				if (pr->name) free(pr->name);
412				if (pr->mode) free(pr->mode);
413				free(pr);
414			}
415			for (;;) {
416				co = LIST_FIRST(&ge->consumer);
417				if (co == NULL)
418					break;
419				LIST_REMOVE(co, consumer);
420				delete_config(&co->config);
421				if (co->mode) free(co->mode);
422				free(co);
423			}
424			free(ge);
425		}
426		free(cl);
427	}
428}
429