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 int 362 geom_xml2tree(struct gmesh *gmp, char *p) 363 { 364 XML_Parser parser; 365 struct mystate *mt; 366 struct gclass *cl; 367 struct ggeom *ge; 368 struct gprovider *pr; 369 struct gconsumer *co; 370 int error, i; 371 372 memset(gmp, 0, sizeof *gmp); 373 LIST_INIT(&gmp->lg_class); 374 parser = XML_ParserCreate(NULL); 375 if (parser == NULL) 376 return (ENOMEM); 377 mt = calloc(1, sizeof *mt); 378 if (mt == NULL) { 379 XML_ParserFree(parser); 380 return (ENOMEM); 381 } 382 mt->mesh = gmp; 383 mt->parser = parser; 384 error = 0; 385 XML_SetUserData(parser, mt); 386 XML_SetElementHandler(parser, StartElement, EndElement); 387 XML_SetCharacterDataHandler(parser, CharData); 388 i = XML_Parse(parser, p, strlen(p), 1); 389 if (mt->error != 0) 390 error = mt->error; 391 else if (i != 1) { 392 error = XML_GetErrorCode(parser) == XML_ERROR_NO_MEMORY ? 393 ENOMEM : EILSEQ; 394 } 395 XML_ParserFree(parser); 396 if (error != 0) { 397 free(mt); 398 return (error); 399 } 400 gmp->lg_ident = calloc(sizeof *gmp->lg_ident, mt->nident + 1); 401 free(mt); 402 if (gmp->lg_ident == NULL) 403 return (ENOMEM); 404 i = 0; 405 /* Collect all identifiers */ 406 LIST_FOREACH(cl, &gmp->lg_class, lg_class) { 407 gmp->lg_ident[i].lg_id = cl->lg_id; 408 gmp->lg_ident[i].lg_ptr = cl; 409 gmp->lg_ident[i].lg_what = ISCLASS; 410 i++; 411 LIST_FOREACH(ge, &cl->lg_geom, lg_geom) { 412 gmp->lg_ident[i].lg_id = ge->lg_id; 413 gmp->lg_ident[i].lg_ptr = ge; 414 gmp->lg_ident[i].lg_what = ISGEOM; 415 i++; 416 LIST_FOREACH(pr, &ge->lg_provider, lg_provider) { 417 gmp->lg_ident[i].lg_id = pr->lg_id; 418 gmp->lg_ident[i].lg_ptr = pr; 419 gmp->lg_ident[i].lg_what = ISPROVIDER; 420 i++; 421 } 422 LIST_FOREACH(co, &ge->lg_consumer, lg_consumer) { 423 gmp->lg_ident[i].lg_id = co->lg_id; 424 gmp->lg_ident[i].lg_ptr = co; 425 gmp->lg_ident[i].lg_what = ISCONSUMER; 426 i++; 427 } 428 } 429 } 430 /* Substitute all identifiers */ 431 LIST_FOREACH(cl, &gmp->lg_class, lg_class) { 432 LIST_FOREACH(ge, &cl->lg_geom, lg_geom) { 433 ge->lg_class = 434 geom_lookupid(gmp, ge->lg_class)->lg_ptr; 435 LIST_FOREACH(pr, &ge->lg_provider, lg_provider) { 436 pr->lg_geom = 437 geom_lookupid(gmp, pr->lg_geom)->lg_ptr; 438 } 439 LIST_FOREACH(co, &ge->lg_consumer, lg_consumer) { 440 co->lg_geom = 441 geom_lookupid(gmp, co->lg_geom)->lg_ptr; 442 if (co->lg_provider != NULL) { 443 co->lg_provider = 444 geom_lookupid(gmp, 445 co->lg_provider)->lg_ptr; 446 LIST_INSERT_HEAD( 447 &co->lg_provider->lg_consumers, 448 co, lg_consumers); 449 } 450 } 451 } 452 } 453 return (0); 454 } 455 456 int 457 geom_gettree(struct gmesh *gmp) 458 { 459 char *p; 460 int error; 461 462 p = geom_getxml(); 463 if (p == NULL) 464 return (errno); 465 error = geom_xml2tree(gmp, p); 466 free(p); 467 return (error); 468 } 469 470 static void 471 delete_config(struct gconf *gp) 472 { 473 struct gconfig *cf; 474 475 for (;;) { 476 cf = LIST_FIRST(gp); 477 if (cf == NULL) 478 return; 479 LIST_REMOVE(cf, lg_config); 480 free(cf->lg_name); 481 free(cf->lg_val); 482 free(cf); 483 } 484 } 485 486 void 487 geom_deletetree(struct gmesh *gmp) 488 { 489 struct gclass *cl; 490 struct ggeom *ge; 491 struct gprovider *pr; 492 struct gconsumer *co; 493 494 free(gmp->lg_ident); 495 gmp->lg_ident = NULL; 496 for (;;) { 497 cl = LIST_FIRST(&gmp->lg_class); 498 if (cl == NULL) 499 break; 500 LIST_REMOVE(cl, lg_class); 501 delete_config(&cl->lg_config); 502 if (cl->lg_name) free(cl->lg_name); 503 for (;;) { 504 ge = LIST_FIRST(&cl->lg_geom); 505 if (ge == NULL) 506 break; 507 LIST_REMOVE(ge, lg_geom); 508 delete_config(&ge->lg_config); 509 if (ge->lg_name) free(ge->lg_name); 510 for (;;) { 511 pr = LIST_FIRST(&ge->lg_provider); 512 if (pr == NULL) 513 break; 514 LIST_REMOVE(pr, lg_provider); 515 delete_config(&pr->lg_config); 516 if (pr->lg_name) free(pr->lg_name); 517 if (pr->lg_mode) free(pr->lg_mode); 518 free(pr); 519 } 520 for (;;) { 521 co = LIST_FIRST(&ge->lg_consumer); 522 if (co == NULL) 523 break; 524 LIST_REMOVE(co, lg_consumer); 525 delete_config(&co->lg_config); 526 if (co->lg_mode) free(co->lg_mode); 527 free(co); 528 } 529 free(ge); 530 } 531 free(cl); 532 } 533 } 534