1 /*- 2 * Copyright (c) 2003 Poul-Henning Kamp 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The names of the authors may not be used to endorse or promote 14 * products derived from this software without specific prior written 15 * permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD$ 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 <fcntl.h> 39 #include <ctype.h> 40 #include <sys/stat.h> 41 #include <sys/mman.h> 42 #include <sys/queue.h> 43 #include <sys/sbuf.h> 44 #include <sys/sysctl.h> 45 #include <err.h> 46 #include <bsdxml.h> 47 #include <libgeom.h> 48 49 struct mystate { 50 struct gmesh *mesh; 51 struct gclass *class; 52 struct ggeom *geom; 53 struct gprovider *provider; 54 struct gconsumer *consumer; 55 int level; 56 struct sbuf *sbuf[20]; 57 struct gconf *config; 58 unsigned nident; 59 }; 60 61 static void * 62 internalize_ident(struct mystate *mt, const char *element, const char *str) 63 { 64 struct gident *gip; 65 unsigned i; 66 67 if (mt->nident != 0 && mt->mesh->lg_ident == NULL) { 68 warn("Cannot continue due to previous memory exhaustion."); 69 return (NULL); 70 } 71 72 for (i = 0; i < mt->nident; i++) { 73 if (strcmp(mt->mesh->lg_ident[i].lg_id, str) != 0) 74 continue; 75 return ((void *)(uintptr_t)(i + 1)); 76 } 77 78 i = mt->nident; 79 mt->nident++; 80 mt->mesh->lg_ident = reallocf(mt->mesh->lg_ident, (mt->nident + 1) * sizeof mt->mesh->lg_ident[0]); 81 if (mt->mesh->lg_ident == NULL) { 82 warn("Cannot allocate memory during processing of '%s' " 83 "element for identifier '%s'", element, str); 84 return (NULL); 85 } 86 87 gip = &mt->mesh->lg_ident[i]; 88 gip->lg_id = strdup(str); 89 if (gip->lg_id == NULL) { 90 free(mt->mesh->lg_ident); 91 mt->mesh->lg_ident = NULL; 92 warn("Cannot allocate memory during processing of '%s' " 93 "element for identifier '%s'", element, str); 94 return (NULL); 95 } 96 gip->lg_ptr = NULL; 97 gip->lg_what = ISUNRESOLVED; 98 99 /* Terminator entry. */ 100 gip = &mt->mesh->lg_ident[i + 1]; 101 gip->lg_id = NULL; 102 gip->lg_ptr = NULL; 103 gip->lg_what = ISUNRESOLVED; 104 105 return ((void *)(uintptr_t)(i + 1)); 106 } 107 108 static void 109 StartElement(void *userData, const char *name, const char **attr) 110 { 111 struct mystate *mt; 112 void *id; 113 void *ref; 114 int i; 115 116 mt = userData; 117 mt->level++; 118 mt->sbuf[mt->level] = sbuf_new_auto(); 119 id = NULL; 120 ref = NULL; 121 for (i = 0; attr[i] != NULL; i += 2) { 122 if (!strcmp(attr[i], "id")) { 123 id = internalize_ident(mt, name, attr[i + 1]); 124 } else if (!strcmp(attr[i], "ref")) { 125 ref = internalize_ident(mt, name, attr[i + 1]); 126 } else 127 printf("%*.*s[%s = %s]\n", 128 mt->level + 1, mt->level + 1, "", 129 attr[i], attr[i + 1]); 130 } 131 if (!strcmp(name, "class") && mt->class == NULL) { 132 mt->class = calloc(1, sizeof *mt->class); 133 if (mt->class == NULL) { 134 warn("Cannot allocate memory during processing of '%s' " 135 "element", name); 136 return; 137 } 138 mt->class->lg_id = id; 139 LIST_INSERT_HEAD(&mt->mesh->lg_class, mt->class, lg_class); 140 LIST_INIT(&mt->class->lg_geom); 141 LIST_INIT(&mt->class->lg_config); 142 return; 143 } 144 if (!strcmp(name, "geom") && mt->geom == NULL) { 145 mt->geom = calloc(1, sizeof *mt->geom); 146 if (mt->geom == NULL) { 147 warn("Cannot allocate memory during processing of '%s' " 148 "element", name); 149 return; 150 } 151 mt->geom->lg_id = id; 152 LIST_INSERT_HEAD(&mt->class->lg_geom, mt->geom, lg_geom); 153 LIST_INIT(&mt->geom->lg_provider); 154 LIST_INIT(&mt->geom->lg_consumer); 155 LIST_INIT(&mt->geom->lg_config); 156 return; 157 } 158 if (!strcmp(name, "class") && mt->geom != NULL) { 159 mt->geom->lg_class = ref; 160 return; 161 } 162 if (!strcmp(name, "consumer") && mt->consumer == NULL) { 163 mt->consumer = calloc(1, sizeof *mt->consumer); 164 if (mt->consumer == NULL) { 165 warn("Cannot allocate memory during processing of '%s' " 166 "element", name); 167 return; 168 } 169 mt->consumer->lg_id = id; 170 LIST_INSERT_HEAD(&mt->geom->lg_consumer, mt->consumer, 171 lg_consumer); 172 LIST_INIT(&mt->consumer->lg_config); 173 return; 174 } 175 if (!strcmp(name, "geom") && mt->consumer != NULL) { 176 mt->consumer->lg_geom = ref; 177 return; 178 } 179 if (!strcmp(name, "provider") && mt->consumer != NULL) { 180 mt->consumer->lg_provider = ref; 181 return; 182 } 183 if (!strcmp(name, "provider") && mt->provider == NULL) { 184 mt->provider = calloc(1, sizeof *mt->provider); 185 if (mt->provider == NULL) { 186 warn("Cannot allocate memory during processing of '%s' " 187 "element", name); 188 return; 189 } 190 mt->provider->lg_id = id; 191 LIST_INSERT_HEAD(&mt->geom->lg_provider, mt->provider, 192 lg_provider); 193 LIST_INIT(&mt->provider->lg_consumers); 194 LIST_INIT(&mt->provider->lg_config); 195 return; 196 } 197 if (!strcmp(name, "geom") && mt->provider != NULL) { 198 mt->provider->lg_geom = ref; 199 return; 200 } 201 if (!strcmp(name, "config")) { 202 if (mt->provider != NULL) { 203 mt->config = &mt->provider->lg_config; 204 return; 205 } 206 if (mt->consumer != NULL) { 207 mt->config = &mt->consumer->lg_config; 208 return; 209 } 210 if (mt->geom != NULL) { 211 mt->config = &mt->geom->lg_config; 212 return; 213 } 214 if (mt->class != NULL) { 215 mt->config = &mt->class->lg_config; 216 return; 217 } 218 } 219 } 220 221 static void 222 EndElement(void *userData, const char *name) 223 { 224 struct mystate *mt; 225 struct gconfig *gc; 226 char *p; 227 228 mt = userData; 229 sbuf_finish(mt->sbuf[mt->level]); 230 p = strdup(sbuf_data(mt->sbuf[mt->level])); 231 if (p == NULL) { 232 warn("Cannot allocate memory during processing of '%s' " 233 "element", name); 234 return; 235 } 236 sbuf_delete(mt->sbuf[mt->level]); 237 mt->sbuf[mt->level] = NULL; 238 mt->level--; 239 if (strlen(p) == 0) { 240 free(p); 241 p = NULL; 242 } 243 244 if (!strcmp(name, "name")) { 245 if (mt->provider != NULL) { 246 mt->provider->lg_name = p; 247 return; 248 } else if (mt->geom != NULL) { 249 mt->geom->lg_name = p; 250 return; 251 } else if (mt->class != NULL) { 252 mt->class->lg_name = p; 253 return; 254 } 255 } 256 if (!strcmp(name, "rank") && mt->geom != NULL) { 257 mt->geom->lg_rank = strtoul(p, NULL, 0); 258 free(p); 259 return; 260 } 261 if (!strcmp(name, "mode") && mt->provider != NULL) { 262 mt->provider->lg_mode = p; 263 return; 264 } 265 if (!strcmp(name, "mode") && mt->consumer != NULL) { 266 mt->consumer->lg_mode = p; 267 return; 268 } 269 if (!strcmp(name, "mediasize") && mt->provider != NULL) { 270 mt->provider->lg_mediasize = strtoumax(p, NULL, 0); 271 free(p); 272 return; 273 } 274 if (!strcmp(name, "sectorsize") && mt->provider != NULL) { 275 mt->provider->lg_sectorsize = strtoul(p, NULL, 0); 276 free(p); 277 return; 278 } 279 if (!strcmp(name, "stripesize") && mt->provider != NULL) { 280 mt->provider->lg_stripesize = strtoumax(p, NULL, 0); 281 free(p); 282 return; 283 } 284 if (!strcmp(name, "stripeoffset") && mt->provider != NULL) { 285 mt->provider->lg_stripeoffset = strtoumax(p, NULL, 0); 286 free(p); 287 return; 288 } 289 290 if (!strcmp(name, "config")) { 291 mt->config = NULL; 292 return; 293 } 294 295 if (mt->config != NULL) { 296 gc = calloc(1, sizeof *gc); 297 if (gc == NULL) { 298 warn("Cannot allocate memory during processing of '%s' " 299 "element", name); 300 return; 301 } 302 gc->lg_name = strdup(name); 303 if (gc->lg_name == NULL) { 304 warn("Cannot allocate memory during processing of '%s' " 305 "element", name); 306 return; 307 } 308 gc->lg_val = p; 309 LIST_INSERT_HEAD(mt->config, gc, lg_config); 310 return; 311 } 312 313 if (p != NULL) { 314 printf("Unexpected XML: name=%s data=\"%s\"\n", name, p); 315 free(p); 316 } 317 318 if (!strcmp(name, "consumer") && mt->consumer != NULL) { 319 mt->consumer = NULL; 320 return; 321 } 322 if (!strcmp(name, "provider") && mt->provider != NULL) { 323 mt->provider = NULL; 324 return; 325 } 326 if (!strcmp(name, "geom") && mt->consumer != NULL) { 327 return; 328 } 329 if (!strcmp(name, "geom") && mt->provider != NULL) { 330 return; 331 } 332 if (!strcmp(name, "geom") && mt->geom != NULL) { 333 mt->geom = NULL; 334 return; 335 } 336 if (!strcmp(name, "class") && mt->geom != NULL) { 337 return; 338 } 339 if (!strcmp(name, "class") && mt->class != NULL) { 340 mt->class = NULL; 341 return; 342 } 343 } 344 345 static void 346 CharData(void *userData , const XML_Char *s , int len) 347 { 348 struct mystate *mt; 349 const char *b, *e; 350 351 mt = userData; 352 353 b = s; 354 e = s + len - 1; 355 while (isspace(*b) && b < e) 356 b++; 357 while (isspace(*e) && e > b) 358 e--; 359 if (e != b || (*b && !isspace(*b))) 360 sbuf_bcat(mt->sbuf[mt->level], b, e - b + 1); 361 } 362 363 struct gident * 364 geom_lookupid(struct gmesh *gmp, const void *id) 365 { 366 unsigned i; 367 368 if (gmp->lg_ident == NULL) 369 return (NULL); 370 371 for (i = 0; gmp->lg_ident[i].lg_id != NULL; i++) { 372 if (i + 1 != (unsigned)(uintptr_t)id) 373 continue; 374 return (&gmp->lg_ident[i]); 375 } 376 return (NULL); 377 } 378 379 int 380 geom_xml2tree(struct gmesh *gmp, char *p) 381 { 382 XML_Parser parser; 383 struct mystate *mt; 384 struct gclass *cl; 385 struct ggeom *ge; 386 struct gprovider *pr; 387 struct gconsumer *co; 388 struct gident *gip; 389 int i; 390 391 memset(gmp, 0, sizeof *gmp); 392 LIST_INIT(&gmp->lg_class); 393 parser = XML_ParserCreate(NULL); 394 if (parser == NULL) 395 return (ENOMEM); 396 mt = calloc(1, sizeof *mt); 397 if (mt == NULL) { 398 XML_ParserFree(parser); 399 return (ENOMEM); 400 } 401 mt->mesh = gmp; 402 XML_SetUserData(parser, mt); 403 XML_SetElementHandler(parser, StartElement, EndElement); 404 XML_SetCharacterDataHandler(parser, CharData); 405 i = XML_Parse(parser, p, strlen(p), 1); 406 XML_ParserFree(parser); 407 if (i != 1) { 408 free(mt); 409 return (-1); 410 } 411 if (gmp->lg_ident == NULL && mt->nident != 0) { 412 free(mt); 413 return (ENOMEM); 414 } 415 free(mt); 416 /* Collect all identifiers */ 417 LIST_FOREACH(cl, &gmp->lg_class, lg_class) { 418 gip = geom_lookupid(gmp, cl->lg_id); 419 gip->lg_ptr = cl; 420 gip->lg_what = ISCLASS; 421 422 LIST_FOREACH(ge, &cl->lg_geom, lg_geom) { 423 gip = geom_lookupid(gmp, ge->lg_id); 424 gip->lg_ptr = ge; 425 gip->lg_what = ISGEOM; 426 LIST_FOREACH(pr, &ge->lg_provider, lg_provider) { 427 gip = geom_lookupid(gmp, pr->lg_id); 428 gip->lg_ptr = pr; 429 gip->lg_what = ISPROVIDER; 430 } 431 LIST_FOREACH(co, &ge->lg_consumer, lg_consumer) { 432 gip = geom_lookupid(gmp, co->lg_id); 433 gip->lg_ptr = co; 434 gip->lg_what = ISCONSUMER; 435 } 436 } 437 } 438 /* Substitute all identifiers */ 439 LIST_FOREACH(cl, &gmp->lg_class, lg_class) { 440 LIST_FOREACH(ge, &cl->lg_geom, lg_geom) { 441 ge->lg_class = 442 geom_lookupid(gmp, ge->lg_class)->lg_ptr; 443 LIST_FOREACH(pr, &ge->lg_provider, lg_provider) { 444 pr->lg_geom = 445 geom_lookupid(gmp, pr->lg_geom)->lg_ptr; 446 } 447 LIST_FOREACH(co, &ge->lg_consumer, lg_consumer) { 448 co->lg_geom = 449 geom_lookupid(gmp, co->lg_geom)->lg_ptr; 450 if (co->lg_provider != NULL) { 451 co->lg_provider = 452 geom_lookupid(gmp, 453 co->lg_provider)->lg_ptr; 454 LIST_INSERT_HEAD( 455 &co->lg_provider->lg_consumers, 456 co, lg_consumers); 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 static void 479 delete_config(struct gconf *gp) 480 { 481 struct gconfig *cf; 482 483 for (;;) { 484 cf = LIST_FIRST(gp); 485 if (cf == NULL) 486 return; 487 LIST_REMOVE(cf, lg_config); 488 free(cf->lg_name); 489 free(cf->lg_val); 490 free(cf); 491 } 492 } 493 494 void 495 geom_deletetree(struct gmesh *gmp) 496 { 497 struct gclass *cl; 498 struct ggeom *ge; 499 struct gprovider *pr; 500 struct gconsumer *co; 501 unsigned i; 502 503 for (i = 0; gmp->lg_ident[i].lg_id != NULL; i++) 504 free(gmp->lg_ident[i].lg_id); 505 free(gmp->lg_ident); 506 gmp->lg_ident = NULL; 507 for (;;) { 508 cl = LIST_FIRST(&gmp->lg_class); 509 if (cl == NULL) 510 break; 511 LIST_REMOVE(cl, lg_class); 512 delete_config(&cl->lg_config); 513 if (cl->lg_name) free(cl->lg_name); 514 for (;;) { 515 ge = LIST_FIRST(&cl->lg_geom); 516 if (ge == NULL) 517 break; 518 LIST_REMOVE(ge, lg_geom); 519 delete_config(&ge->lg_config); 520 if (ge->lg_name) free(ge->lg_name); 521 for (;;) { 522 pr = LIST_FIRST(&ge->lg_provider); 523 if (pr == NULL) 524 break; 525 LIST_REMOVE(pr, lg_provider); 526 delete_config(&pr->lg_config); 527 if (pr->lg_name) free(pr->lg_name); 528 if (pr->lg_mode) free(pr->lg_mode); 529 free(pr); 530 } 531 for (;;) { 532 co = LIST_FIRST(&ge->lg_consumer); 533 if (co == NULL) 534 break; 535 LIST_REMOVE(co, lg_consumer); 536 delete_config(&co->lg_config); 537 if (co->lg_mode) free(co->lg_mode); 538 free(co); 539 } 540 free(ge); 541 } 542 free(cl); 543 } 544 } 545