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