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