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 mt = calloc(1, sizeof *mt); 343 if (mt == NULL) 344 return (ENOMEM); 345 mt->mesh = gmp; 346 XML_SetUserData(parser, mt); 347 XML_SetElementHandler(parser, StartElement, EndElement); 348 XML_SetCharacterDataHandler(parser, CharData); 349 i = XML_Parse(parser, p, strlen(p), 1); 350 if (i != 1) 351 return (-1); 352 XML_ParserFree(parser); 353 gmp->lg_ident = calloc(sizeof *gmp->lg_ident, mt->nident + 1); 354 if (gmp->lg_ident == NULL) 355 return (ENOMEM); 356 free(mt); 357 i = 0; 358 /* Collect all identifiers */ 359 LIST_FOREACH(cl, &gmp->lg_class, lg_class) { 360 gmp->lg_ident[i].lg_id = cl->lg_id; 361 gmp->lg_ident[i].lg_ptr = cl; 362 gmp->lg_ident[i].lg_what = ISCLASS; 363 i++; 364 LIST_FOREACH(ge, &cl->lg_geom, lg_geom) { 365 gmp->lg_ident[i].lg_id = ge->lg_id; 366 gmp->lg_ident[i].lg_ptr = ge; 367 gmp->lg_ident[i].lg_what = ISGEOM; 368 i++; 369 LIST_FOREACH(pr, &ge->lg_provider, lg_provider) { 370 gmp->lg_ident[i].lg_id = pr->lg_id; 371 gmp->lg_ident[i].lg_ptr = pr; 372 gmp->lg_ident[i].lg_what = ISPROVIDER; 373 i++; 374 } 375 LIST_FOREACH(co, &ge->lg_consumer, lg_consumer) { 376 gmp->lg_ident[i].lg_id = co->lg_id; 377 gmp->lg_ident[i].lg_ptr = co; 378 gmp->lg_ident[i].lg_what = ISCONSUMER; 379 i++; 380 } 381 } 382 } 383 /* Substitute all identifiers */ 384 LIST_FOREACH(cl, &gmp->lg_class, lg_class) { 385 LIST_FOREACH(ge, &cl->lg_geom, lg_geom) { 386 ge->lg_class = 387 geom_lookupid(gmp, ge->lg_class)->lg_ptr; 388 LIST_FOREACH(pr, &ge->lg_provider, lg_provider) { 389 pr->lg_geom = 390 geom_lookupid(gmp, pr->lg_geom)->lg_ptr; 391 } 392 LIST_FOREACH(co, &ge->lg_consumer, lg_consumer) { 393 co->lg_geom = 394 geom_lookupid(gmp, co->lg_geom)->lg_ptr; 395 if (co->lg_provider != NULL) { 396 co->lg_provider = 397 geom_lookupid(gmp, 398 co->lg_provider)->lg_ptr; 399 LIST_INSERT_HEAD( 400 &co->lg_provider->lg_consumers, 401 co, lg_consumers); 402 } 403 } 404 } 405 } 406 return (0); 407 } 408 409 int 410 geom_gettree(struct gmesh *gmp) 411 { 412 char *p; 413 int error; 414 415 p = geom_getxml(); 416 if (p == NULL) 417 return (errno); 418 error = geom_xml2tree(gmp, p); 419 free(p); 420 return (error); 421 } 422 423 static void 424 delete_config(struct gconf *gp) 425 { 426 struct gconfig *cf; 427 428 for (;;) { 429 cf = LIST_FIRST(gp); 430 if (cf == NULL) 431 return; 432 LIST_REMOVE(cf, lg_config); 433 free(cf->lg_name); 434 free(cf->lg_val); 435 free(cf); 436 } 437 } 438 439 void 440 geom_deletetree(struct gmesh *gmp) 441 { 442 struct gclass *cl; 443 struct ggeom *ge; 444 struct gprovider *pr; 445 struct gconsumer *co; 446 447 free(gmp->lg_ident); 448 gmp->lg_ident = NULL; 449 for (;;) { 450 cl = LIST_FIRST(&gmp->lg_class); 451 if (cl == NULL) 452 break; 453 LIST_REMOVE(cl, lg_class); 454 delete_config(&cl->lg_config); 455 if (cl->lg_name) free(cl->lg_name); 456 for (;;) { 457 ge = LIST_FIRST(&cl->lg_geom); 458 if (ge == NULL) 459 break; 460 LIST_REMOVE(ge, lg_geom); 461 delete_config(&ge->lg_config); 462 if (ge->lg_name) free(ge->lg_name); 463 for (;;) { 464 pr = LIST_FIRST(&ge->lg_provider); 465 if (pr == NULL) 466 break; 467 LIST_REMOVE(pr, lg_provider); 468 delete_config(&pr->lg_config); 469 if (pr->lg_name) free(pr->lg_name); 470 if (pr->lg_mode) free(pr->lg_mode); 471 free(pr); 472 } 473 for (;;) { 474 co = LIST_FIRST(&ge->lg_consumer); 475 if (co == NULL) 476 break; 477 LIST_REMOVE(co, lg_consumer); 478 delete_config(&co->lg_config); 479 if (co->lg_mode) free(co->lg_mode); 480 free(co); 481 } 482 free(ge); 483 } 484 free(cl); 485 } 486 } 487