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