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 234 if (!strcmp(name, "config")) { 235 mt->config = NULL; 236 return; 237 } 238 239 if (mt->config != NULL) { 240 gc = calloc(1, sizeof *gc); 241 if (gc == NULL) { 242 warn("Cannot allocate memory during processing of '%s' " 243 "element", name); 244 return; 245 } 246 gc->lg_name = strdup(name); 247 if (gc->lg_name == NULL) { 248 warn("Cannot allocate memory during processing of '%s' " 249 "element", name); 250 return; 251 } 252 gc->lg_val = p; 253 LIST_INSERT_HEAD(mt->config, gc, lg_config); 254 return; 255 } 256 257 if (p != NULL) { 258 printf("Unexpected XML: name=%s data=\"%s\"\n", name, p); 259 free(p); 260 } 261 262 if (!strcmp(name, "consumer") && mt->consumer != NULL) { 263 mt->consumer = NULL; 264 return; 265 } 266 if (!strcmp(name, "provider") && mt->provider != NULL) { 267 mt->provider = NULL; 268 return; 269 } 270 if (!strcmp(name, "geom") && mt->consumer != NULL) { 271 return; 272 } 273 if (!strcmp(name, "geom") && mt->provider != NULL) { 274 return; 275 } 276 if (!strcmp(name, "geom") && mt->geom != NULL) { 277 mt->geom = NULL; 278 return; 279 } 280 if (!strcmp(name, "class") && mt->geom != NULL) { 281 return; 282 } 283 if (!strcmp(name, "class") && mt->class != NULL) { 284 mt->class = NULL; 285 return; 286 } 287 } 288 289 static void 290 CharData(void *userData , const XML_Char *s , int len) 291 { 292 struct mystate *mt; 293 const char *b, *e; 294 295 mt = userData; 296 297 b = s; 298 e = s + len - 1; 299 while (isspace(*b) && b < e) 300 b++; 301 while (isspace(*e) && e > b) 302 e--; 303 if (e != b || (*b && !isspace(*b))) 304 sbuf_bcat(mt->sbuf[mt->level], b, e - b + 1); 305 } 306 307 struct gident * 308 geom_lookupid(struct gmesh *gmp, const void *id) 309 { 310 struct gident *gip; 311 312 for (gip = gmp->lg_ident; gip->lg_id != NULL; gip++) 313 if (gip->lg_id == id) 314 return (gip); 315 return (NULL); 316 } 317 318 int 319 geom_xml2tree(struct gmesh *gmp, char *p) 320 { 321 XML_Parser parser; 322 struct mystate *mt; 323 struct gclass *cl; 324 struct ggeom *ge; 325 struct gprovider *pr; 326 struct gconsumer *co; 327 int i; 328 329 memset(gmp, 0, sizeof *gmp); 330 LIST_INIT(&gmp->lg_class); 331 parser = XML_ParserCreate(NULL); 332 mt = calloc(1, sizeof *mt); 333 if (mt == NULL) 334 return (ENOMEM); 335 mt->mesh = gmp; 336 XML_SetUserData(parser, mt); 337 XML_SetElementHandler(parser, StartElement, EndElement); 338 XML_SetCharacterDataHandler(parser, CharData); 339 i = XML_Parse(parser, p, strlen(p), 1); 340 if (i != 1) 341 return (-1); 342 XML_ParserFree(parser); 343 gmp->lg_ident = calloc(sizeof *gmp->lg_ident, mt->nident + 1); 344 if (gmp->lg_ident == NULL) 345 return (ENOMEM); 346 free(mt); 347 i = 0; 348 /* Collect all identifiers */ 349 LIST_FOREACH(cl, &gmp->lg_class, lg_class) { 350 gmp->lg_ident[i].lg_id = cl->lg_id; 351 gmp->lg_ident[i].lg_ptr = cl; 352 gmp->lg_ident[i].lg_what = ISCLASS; 353 i++; 354 LIST_FOREACH(ge, &cl->lg_geom, lg_geom) { 355 gmp->lg_ident[i].lg_id = ge->lg_id; 356 gmp->lg_ident[i].lg_ptr = ge; 357 gmp->lg_ident[i].lg_what = ISGEOM; 358 i++; 359 LIST_FOREACH(pr, &ge->lg_provider, lg_provider) { 360 gmp->lg_ident[i].lg_id = pr->lg_id; 361 gmp->lg_ident[i].lg_ptr = pr; 362 gmp->lg_ident[i].lg_what = ISPROVIDER; 363 i++; 364 } 365 LIST_FOREACH(co, &ge->lg_consumer, lg_consumer) { 366 gmp->lg_ident[i].lg_id = co->lg_id; 367 gmp->lg_ident[i].lg_ptr = co; 368 gmp->lg_ident[i].lg_what = ISCONSUMER; 369 i++; 370 } 371 } 372 } 373 /* Substitute all identifiers */ 374 LIST_FOREACH(cl, &gmp->lg_class, lg_class) { 375 LIST_FOREACH(ge, &cl->lg_geom, lg_geom) { 376 ge->lg_class = 377 geom_lookupid(gmp, ge->lg_class)->lg_ptr; 378 LIST_FOREACH(pr, &ge->lg_provider, lg_provider) { 379 pr->lg_geom = 380 geom_lookupid(gmp, pr->lg_geom)->lg_ptr; 381 } 382 LIST_FOREACH(co, &ge->lg_consumer, lg_consumer) { 383 co->lg_geom = 384 geom_lookupid(gmp, co->lg_geom)->lg_ptr; 385 if (co->lg_provider != NULL) { 386 co->lg_provider = 387 geom_lookupid(gmp, 388 co->lg_provider)->lg_ptr; 389 LIST_INSERT_HEAD( 390 &co->lg_provider->lg_consumers, 391 co, lg_consumers); 392 } 393 } 394 } 395 } 396 return (0); 397 } 398 399 int 400 geom_gettree(struct gmesh *gmp) 401 { 402 char *p; 403 int error; 404 405 p = geom_getxml(); 406 if (p == NULL) 407 return (errno); 408 error = geom_xml2tree(gmp, p); 409 free(p); 410 return (error); 411 } 412 413 static void 414 delete_config(struct gconf *gp) 415 { 416 struct gconfig *cf; 417 418 for (;;) { 419 cf = LIST_FIRST(gp); 420 if (cf == NULL) 421 return; 422 LIST_REMOVE(cf, lg_config); 423 free(cf->lg_name); 424 free(cf->lg_val); 425 free(cf); 426 } 427 } 428 429 void 430 geom_deletetree(struct gmesh *gmp) 431 { 432 struct gclass *cl; 433 struct ggeom *ge; 434 struct gprovider *pr; 435 struct gconsumer *co; 436 437 free(gmp->lg_ident); 438 gmp->lg_ident = NULL; 439 for (;;) { 440 cl = LIST_FIRST(&gmp->lg_class); 441 if (cl == NULL) 442 break; 443 LIST_REMOVE(cl, lg_class); 444 delete_config(&cl->lg_config); 445 if (cl->lg_name) free(cl->lg_name); 446 for (;;) { 447 ge = LIST_FIRST(&cl->lg_geom); 448 if (ge == NULL) 449 break; 450 LIST_REMOVE(ge, lg_geom); 451 delete_config(&ge->lg_config); 452 if (ge->lg_name) free(ge->lg_name); 453 for (;;) { 454 pr = LIST_FIRST(&ge->lg_provider); 455 if (pr == NULL) 456 break; 457 LIST_REMOVE(pr, lg_provider); 458 delete_config(&pr->lg_config); 459 if (pr->lg_name) free(pr->lg_name); 460 if (pr->lg_mode) free(pr->lg_mode); 461 free(pr); 462 } 463 for (;;) { 464 co = LIST_FIRST(&ge->lg_consumer); 465 if (co == NULL) 466 break; 467 LIST_REMOVE(co, lg_consumer); 468 delete_config(&co->lg_config); 469 if (co->lg_mode) free(co->lg_mode); 470 free(co); 471 } 472 free(ge); 473 } 474 free(cl); 475 } 476 } 477