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