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 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 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 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 * 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 * 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 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(sizeof *gmp->lg_ident, mt->nident + 1); 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 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 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 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 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