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