xref: /freebsd/lib/libgeom/geom_xml2tree.c (revision 729362425c09cf6b362366aabc6fb547eee8035a)
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$
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 
49 struct 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 
61 static void
62 StartElement(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 
152 static void
153 EndElement(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) {
220 		printf("Unexpected XML: name=%s data=\"%s\"\n", name, 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 
251 static void
252 CharData(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 
269 struct gident *
270 geom_lookupid(struct gmesh *gmp, const 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 
280 int
281 geom_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 
353 int
354 geom_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 
365 static void
366 delete_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 
381 void
382 geom_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