geom_xml2tree.c revision 181463
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 181463 2008-08-09 11:14:05Z des $
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
234	if (!strcmp(name, "config")) {
235		mt->config = NULL;
236		return;
237	}
238
239	if (mt->config != NULL) {
240		gc = calloc(1, sizeof *gc);
241		if (gc == NULL) {
242			warn("Cannot allocate memory during processing of '%s' "
243			    "element", name);
244			return;
245		}
246		gc->lg_name = strdup(name);
247		if (gc->lg_name == NULL) {
248			warn("Cannot allocate memory during processing of '%s' "
249			    "element", name);
250			return;
251		}
252		gc->lg_val = p;
253		LIST_INSERT_HEAD(mt->config, gc, lg_config);
254		return;
255	}
256
257	if (p != NULL) {
258		printf("Unexpected XML: name=%s data=\"%s\"\n", name, p);
259		free(p);
260	}
261
262	if (!strcmp(name, "consumer") && mt->consumer != NULL) {
263		mt->consumer = NULL;
264		return;
265	}
266	if (!strcmp(name, "provider") && mt->provider != NULL) {
267		mt->provider = NULL;
268		return;
269	}
270	if (!strcmp(name, "geom") && mt->consumer != NULL) {
271		return;
272	}
273	if (!strcmp(name, "geom") && mt->provider != NULL) {
274		return;
275	}
276	if (!strcmp(name, "geom") && mt->geom != NULL) {
277		mt->geom = NULL;
278		return;
279	}
280	if (!strcmp(name, "class") && mt->geom != NULL) {
281		return;
282	}
283	if (!strcmp(name, "class") && mt->class != NULL) {
284		mt->class = NULL;
285		return;
286	}
287}
288
289static void
290CharData(void *userData , const XML_Char *s , int len)
291{
292	struct mystate *mt;
293	const char *b, *e;
294
295	mt = userData;
296
297	b = s;
298	e = s + len - 1;
299	while (isspace(*b) && b < e)
300		b++;
301	while (isspace(*e) && e > b)
302		e--;
303	if (e != b || (*b && !isspace(*b)))
304		sbuf_bcat(mt->sbuf[mt->level], b, e - b + 1);
305}
306
307struct gident *
308geom_lookupid(struct gmesh *gmp, const void *id)
309{
310	struct gident *gip;
311
312	for (gip = gmp->lg_ident; gip->lg_id != NULL; gip++)
313		if (gip->lg_id == id)
314			return (gip);
315	return (NULL);
316}
317
318int
319geom_xml2tree(struct gmesh *gmp, char *p)
320{
321	XML_Parser parser;
322	struct mystate *mt;
323	struct gclass *cl;
324	struct ggeom *ge;
325	struct gprovider *pr;
326	struct gconsumer *co;
327	int i;
328
329	memset(gmp, 0, sizeof *gmp);
330	LIST_INIT(&gmp->lg_class);
331	parser = XML_ParserCreate(NULL);
332	mt = calloc(1, sizeof *mt);
333	if (mt == NULL)
334		return (ENOMEM);
335	mt->mesh = gmp;
336	XML_SetUserData(parser, mt);
337	XML_SetElementHandler(parser, StartElement, EndElement);
338	XML_SetCharacterDataHandler(parser, CharData);
339	i = XML_Parse(parser, p, strlen(p), 1);
340	if (i != 1)
341		return (-1);
342	XML_ParserFree(parser);
343	gmp->lg_ident = calloc(sizeof *gmp->lg_ident, mt->nident + 1);
344	if (gmp->lg_ident == NULL)
345		return (ENOMEM);
346	free(mt);
347	i = 0;
348	/* Collect all identifiers */
349	LIST_FOREACH(cl, &gmp->lg_class, lg_class) {
350		gmp->lg_ident[i].lg_id = cl->lg_id;
351		gmp->lg_ident[i].lg_ptr = cl;
352		gmp->lg_ident[i].lg_what = ISCLASS;
353		i++;
354		LIST_FOREACH(ge, &cl->lg_geom, lg_geom) {
355			gmp->lg_ident[i].lg_id = ge->lg_id;
356			gmp->lg_ident[i].lg_ptr = ge;
357			gmp->lg_ident[i].lg_what = ISGEOM;
358			i++;
359			LIST_FOREACH(pr, &ge->lg_provider, lg_provider) {
360				gmp->lg_ident[i].lg_id = pr->lg_id;
361				gmp->lg_ident[i].lg_ptr = pr;
362				gmp->lg_ident[i].lg_what = ISPROVIDER;
363				i++;
364			}
365			LIST_FOREACH(co, &ge->lg_consumer, lg_consumer) {
366				gmp->lg_ident[i].lg_id = co->lg_id;
367				gmp->lg_ident[i].lg_ptr = co;
368				gmp->lg_ident[i].lg_what = ISCONSUMER;
369				i++;
370			}
371		}
372	}
373	/* Substitute all identifiers */
374	LIST_FOREACH(cl, &gmp->lg_class, lg_class) {
375		LIST_FOREACH(ge, &cl->lg_geom, lg_geom) {
376			ge->lg_class =
377			    geom_lookupid(gmp, ge->lg_class)->lg_ptr;
378			LIST_FOREACH(pr, &ge->lg_provider, lg_provider) {
379				pr->lg_geom =
380				    geom_lookupid(gmp, pr->lg_geom)->lg_ptr;
381			}
382			LIST_FOREACH(co, &ge->lg_consumer, lg_consumer) {
383				co->lg_geom =
384				    geom_lookupid(gmp, co->lg_geom)->lg_ptr;
385				if (co->lg_provider != NULL) {
386					co->lg_provider =
387					    geom_lookupid(gmp,
388						co->lg_provider)->lg_ptr;
389					LIST_INSERT_HEAD(
390					    &co->lg_provider->lg_consumers,
391					    co, lg_consumers);
392				}
393			}
394		}
395	}
396	return (0);
397}
398
399int
400geom_gettree(struct gmesh *gmp)
401{
402	char *p;
403	int error;
404
405	p = geom_getxml();
406	if (p == NULL)
407		return (errno);
408	error = geom_xml2tree(gmp, p);
409	free(p);
410	return (error);
411}
412
413static void
414delete_config(struct gconf *gp)
415{
416	struct gconfig *cf;
417
418	for (;;) {
419		cf = LIST_FIRST(gp);
420		if (cf == NULL)
421			return;
422		LIST_REMOVE(cf, lg_config);
423		free(cf->lg_name);
424		free(cf->lg_val);
425		free(cf);
426	}
427}
428
429void
430geom_deletetree(struct gmesh *gmp)
431{
432	struct gclass *cl;
433	struct ggeom *ge;
434	struct gprovider *pr;
435	struct gconsumer *co;
436
437	free(gmp->lg_ident);
438	gmp->lg_ident = NULL;
439	for (;;) {
440		cl = LIST_FIRST(&gmp->lg_class);
441		if (cl == NULL)
442			break;
443		LIST_REMOVE(cl, lg_class);
444		delete_config(&cl->lg_config);
445		if (cl->lg_name) free(cl->lg_name);
446		for (;;) {
447			ge = LIST_FIRST(&cl->lg_geom);
448			if (ge == NULL)
449				break;
450			LIST_REMOVE(ge, lg_geom);
451			delete_config(&ge->lg_config);
452			if (ge->lg_name) free(ge->lg_name);
453			for (;;) {
454				pr = LIST_FIRST(&ge->lg_provider);
455				if (pr == NULL)
456					break;
457				LIST_REMOVE(pr, lg_provider);
458				delete_config(&pr->lg_config);
459				if (pr->lg_name) free(pr->lg_name);
460				if (pr->lg_mode) free(pr->lg_mode);
461				free(pr);
462			}
463			for (;;) {
464				co = LIST_FIRST(&ge->lg_consumer);
465				if (co == NULL)
466					break;
467				LIST_REMOVE(co, lg_consumer);
468				delete_config(&co->lg_config);
469				if (co->lg_mode) free(co->lg_mode);
470				free(co);
471			}
472			free(ge);
473		}
474		free(cl);
475	}
476}
477