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