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