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