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