1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <strings.h> 28 #include <stdio.h> 29 #include <unistd.h> 30 #include <stdlib.h> 31 #include <strings.h> 32 #include <note.h> 33 #include <errno.h> 34 #include <sys/mdesc.h> 35 #include <sys/mdesc_impl.h> 36 #include <sys/sysmacros.h> 37 #include "mdesc_mutable.h" 38 39 static void md_free_prop(mmd_t *mdp, md_prop_t *propp); 40 static void md_free_string(mmd_t *mdp, md_string_t *msp); 41 static void md_free_data_block(mmd_t *mdp, md_data_block_t *mdbp); 42 43 static uint32_t 44 md_byte_hash(uint8_t *bp, int len) 45 { 46 uint32_t hash = 0; 47 int i; 48 49 for (i = 0; i < len; i++) { 50 /* 5 bit rotation */ 51 hash = (hash >> 27) | (hash << 5) | bp[i]; 52 } 53 54 return (hash); 55 } 56 57 static md_string_t * 58 md_find_string(mmd_t *mdp, char *strp, uint32_t *hashp) 59 { 60 md_string_t *msp; 61 uint32_t hash; 62 63 hash = md_byte_hash((uint8_t *)strp, strlen(strp)); 64 65 if (hashp != NULL) 66 *hashp = hash; 67 68 CHAIN_ITER(mdp->string_list, msp) { 69 if (msp->hash == hash && strcmp(msp->strp, strp) == 0) 70 return (msp); 71 } 72 73 return (NULL); 74 } 75 76 static md_string_t * 77 md_new_string(mmd_t *mdp, char *strp) 78 { 79 md_string_t *msp; 80 uint32_t hash; 81 82 msp = md_find_string(mdp, strp, &hash); 83 if (msp == NULL) { 84 msp = calloc(1, sizeof (md_string_t)); 85 if (msp == NULL) 86 return (NULL); 87 msp->strp = strdup(strp); 88 if (msp->strp == NULL) { 89 free(msp); 90 return (NULL); 91 } 92 msp->size = strlen(strp) + 1; 93 msp->hash = hash; 94 msp->ref_cnt = 0; 95 msp->build_offset = MD_OFFSET_UNDEF; 96 CHAIN_ADD(mdp->string_list, msp); 97 } 98 msp->ref_cnt++; 99 100 return (msp); 101 } 102 103 static md_data_block_t * 104 md_find_data_block(mmd_t *mdp, uint8_t *datap, int len, uint32_t *hashp) 105 { 106 md_data_block_t *dbp; 107 uint32_t hash; 108 109 hash = md_byte_hash(datap, len); 110 111 if (hashp != NULL) 112 *hashp = hash; 113 114 CHAIN_ITER(mdp->data_block_list, dbp) { 115 if (dbp->size == len && 116 dbp->hash == hash && bcmp(dbp->datap, datap, len) == 0) 117 return (dbp); 118 } 119 120 return (NULL); 121 } 122 123 static md_data_block_t * 124 md_new_data_block(mmd_t *mdp, uint8_t *bufp, int len) 125 { 126 md_data_block_t *dbp; 127 uint32_t hash; 128 129 dbp = md_find_data_block(mdp, bufp, len, &hash); 130 if (dbp == NULL) { 131 dbp = calloc(1, sizeof (md_data_block_t)); 132 if (dbp == NULL) 133 return (NULL); 134 dbp->datap = malloc(len); 135 if (dbp->datap == NULL) { 136 free(dbp); 137 return (NULL); 138 } 139 (void) memcpy(dbp->datap, bufp, len); 140 dbp->size = len; 141 dbp->hash = hash; 142 dbp->ref_cnt = 0; 143 dbp->build_offset = MD_OFFSET_UNDEF; 144 CHAIN_ADD(mdp->data_block_list, dbp); 145 } 146 dbp->ref_cnt++; 147 148 return (dbp); 149 } 150 151 md_node_t * 152 md_new_node(mmd_t *mdp, char *sp) 153 { 154 md_node_t *nodep; 155 156 nodep = calloc(1, sizeof (md_node_t)); 157 if (nodep == NULL) 158 return (NULL); 159 nodep->typep = md_new_string(mdp, sp); 160 if (nodep->typep == NULL) { 161 free(nodep); 162 return (NULL); 163 } 164 CHAIN_ADD(mdp->node_list, nodep); 165 166 return (nodep); 167 } 168 169 static md_prop_t * 170 md_new_property(mmd_t *mdp, md_node_t *nodep, uint8_t type, char *sp) 171 { 172 md_prop_t *propp; 173 174 propp = calloc(1, sizeof (md_prop_t)); 175 if (propp == NULL) 176 return (NULL); 177 propp->type = type; 178 propp->sp = md_new_string(mdp, sp); 179 if (propp->sp == NULL) { 180 free(propp); 181 return (NULL); 182 } 183 184 CHAIN_ADD(nodep->prop_list, propp); 185 186 return (propp); 187 } 188 189 int 190 md_add_value_property(mmd_t *mdp, md_node_t *nodep, char *sp, uint64_t value) 191 { 192 md_prop_t *propp; 193 194 propp = md_new_property(mdp, nodep, MDET_PROP_VAL, sp); 195 if (propp == NULL) 196 return (ENOMEM); 197 propp->d.value = value; 198 return (0); 199 } 200 201 int 202 md_add_string_property(mmd_t *mdp, md_node_t *nodep, char *sp, char *bufp) 203 { 204 md_prop_t *propp; 205 md_data_block_t *dbp; 206 207 dbp = md_new_data_block(mdp, (uint8_t *)bufp, strlen(bufp) + 1); 208 if (dbp == NULL) 209 return (ENOMEM); 210 propp = md_new_property(mdp, nodep, MDET_PROP_STR, sp); 211 if (propp == NULL) { 212 md_free_data_block(mdp, dbp); 213 return (ENOMEM); 214 } 215 propp->d.dbp = dbp; 216 return (0); 217 } 218 219 int 220 md_add_data_property(mmd_t *mdp, md_node_t *nodep, char *sp, int len, 221 uint8_t *bufp) 222 { 223 md_prop_t *propp; 224 md_data_block_t *dbp; 225 226 dbp = md_new_data_block(mdp, bufp, len); 227 if (dbp == NULL) 228 return (ENOMEM); 229 230 propp = md_new_property(mdp, nodep, MDET_PROP_DAT, sp); 231 if (propp == NULL) { 232 md_free_data_block(mdp, dbp); 233 return (ENOMEM); 234 } 235 propp->d.dbp = dbp; 236 return (0); 237 } 238 239 static int 240 md_add_arc_property(mmd_t *mdp, md_node_t *nodep, char *arcnamep, 241 md_node_t *tgtnodep) 242 { 243 md_prop_t *propp; 244 245 propp = md_new_property(mdp, nodep, MDET_PROP_ARC, arcnamep); 246 if (propp == NULL) 247 return (ENOMEM); 248 propp->d.arc.is_ptr = B_TRUE; 249 propp->d.arc.val.nodep = tgtnodep; 250 return (0); 251 } 252 253 md_node_t * 254 md_link_new_node(mmd_t *mdp, char *nodenamep, md_node_t *parentnodep, 255 char *linktonewp, char *linkbackp) 256 { 257 md_node_t *nodep; 258 259 nodep = md_new_node(mdp, nodenamep); 260 if (nodep == NULL) 261 return (NULL); 262 263 ASSERT(linktonewp != NULL); 264 ASSERT(parentnodep != NULL && !parentnodep->deleted); 265 266 if (md_add_arc_property(mdp, parentnodep, linktonewp, nodep) != 0) { 267 return (NULL); 268 } 269 270 if (linkbackp != NULL) { 271 if (md_add_arc_property(mdp, 272 nodep, linkbackp, parentnodep) != 0) { 273 return (NULL); 274 } 275 } 276 277 return (nodep); 278 } 279 280 void 281 md_destroy(mmd_t *mdp) 282 { 283 md_node_t *nodep; 284 285 for (nodep = CHAIN_START(mdp->node_list); nodep != NULL; ) { 286 md_node_t *tmp_nodep; 287 288 tmp_nodep = nodep->nextp; 289 md_free_node(mdp, nodep); 290 291 nodep = tmp_nodep; 292 } 293 294 /* should have deleted all the string refs by here */ 295 ASSERT(CHAIN_LENGTH(mdp->string_list) == 0); 296 free(mdp); 297 } 298 299 void 300 md_free_node(mmd_t *mdp, md_node_t *nodep) 301 { 302 md_prop_t *propp; 303 304 if (nodep->typep != NULL) 305 md_free_string(mdp, nodep->typep); 306 307 for (propp = CHAIN_START(nodep->prop_list); propp != NULL; ) { 308 md_prop_t *tmp_propp; 309 310 tmp_propp = propp->nextp; 311 md_free_prop(mdp, propp); 312 313 propp = tmp_propp; 314 } 315 316 free(nodep); 317 } 318 319 static void 320 md_free_prop(mmd_t *mdp, md_prop_t *propp) 321 { 322 if (propp->sp != NULL) 323 md_free_string(mdp, propp->sp); 324 325 switch (propp->type) { 326 case MDET_PROP_VAL: 327 break; 328 329 case MDET_PROP_ARC: 330 break; 331 332 case MDET_PROP_STR: 333 case MDET_PROP_DAT: 334 md_free_data_block(mdp, propp->d.dbp); 335 break; 336 337 default: 338 ASSERT(B_FALSE); 339 } 340 341 free(propp); 342 } 343 344 static void 345 md_free_string(mmd_t *mdp, md_string_t *msp) 346 { 347 ASSERT(msp->ref_cnt > 0); 348 349 msp->ref_cnt--; 350 351 if (msp->ref_cnt == 0) { 352 free(msp->strp); 353 mdp->string_list.startp = msp->nextp; 354 free(msp); 355 } 356 } 357 358 static void 359 md_free_data_block(mmd_t *mdp, md_data_block_t *mdbp) 360 { 361 ASSERT(mdbp->ref_cnt > 0); 362 363 mdbp->ref_cnt--; 364 365 if (mdbp->ref_cnt == 0) { 366 free(mdbp->datap); 367 mdp->data_block_list.startp = mdbp->nextp; 368 free(mdbp); 369 } 370 } 371 372 mmd_t * 373 md_new_md(void) 374 { 375 return ((mmd_t *)calloc(1, sizeof (mmd_t))); 376 } 377 378 static void 379 md_fix_name(md_element_t *mdep, md_prop_t *propp) 380 { 381 mdep->name_len = htomd8(propp->sp->size - 1); 382 mdep->name_offset = htomd32(propp->sp->build_offset); 383 } 384 385 void 386 create_mde(md_element_t *mdep, int type, md_node_t *nodep, md_prop_t *propp) 387 { 388 (void) memset(mdep, 0, MD_ELEMENT_SIZE); 389 mdep->tag = htomd8(type); 390 391 switch (type) { 392 case MDET_NODE: 393 mdep->d.prop_idx = htomd32(nodep->next_index); 394 mdep->name_len = htomd8(nodep->typep->size - 1); 395 mdep->name_offset = htomd32(nodep->typep->build_offset); 396 break; 397 398 case MDET_PROP_ARC: 399 ASSERT(propp->d.arc.is_ptr); 400 mdep->d.prop_idx = htomd64(propp->d.arc.val.nodep->build_index); 401 md_fix_name(mdep, propp); 402 break; 403 404 case MDET_PROP_VAL: 405 mdep->d.prop_val = htomd64(propp->d.value); 406 md_fix_name(mdep, propp); 407 break; 408 409 case MDET_PROP_STR: 410 case MDET_PROP_DAT: 411 mdep->d.prop_data.offset = htomd32(propp->d.dbp->build_offset); 412 mdep->d.prop_data.len = htomd32(propp->d.dbp->size); 413 md_fix_name(mdep, propp); 414 break; 415 416 case MDET_NULL: 417 case MDET_NODE_END: 418 case MDET_LIST_END: 419 break; 420 421 default: 422 ASSERT(B_FALSE); 423 } 424 } 425 426 int 427 md_gen_bin(mmd_t *mdp, uint8_t **bufvalp) 428 { 429 uint32_t offset; 430 md_node_t *nodep; 431 md_data_block_t *mdbp; 432 md_string_t *msp; 433 md_header_t *mdhp; 434 md_element_t *mdep; 435 uint32_t strings_size; 436 uint32_t data_block_size; 437 int total_size; 438 uint8_t *bufferp; 439 uint8_t *string_bufferp; 440 uint8_t *data_block_bufferp; 441 442 /* 443 * Skip through strings to compute offsets. 444 */ 445 offset = 0; 446 for (msp = CHAIN_START(mdp->string_list); msp != NULL; 447 msp = msp->nextp) { 448 msp->build_offset = offset; 449 offset += msp->size; 450 } 451 strings_size = P2ROUNDUP(offset, MD_ALIGNMENT_SIZE); 452 453 /* 454 * Skip through data blocks to compute offsets. 455 */ 456 457 offset = 0; 458 for (mdbp = CHAIN_START(mdp->data_block_list); mdbp != NULL; 459 mdbp = mdbp->nextp) { 460 mdbp->build_offset = offset; 461 offset += mdbp->size; 462 offset = P2ROUNDUP(offset, MD_ALIGNMENT_SIZE); 463 } 464 data_block_size = P2ROUNDUP(offset, MD_ALIGNMENT_SIZE); 465 466 /* 467 * Compute the MD elements required to build the element list. 468 * For each node there is a node start and end, and one 469 * element for each property. 470 */ 471 472 offset = 0; 473 for (nodep = CHAIN_START(mdp->node_list); nodep != NULL; 474 nodep = nodep->nextp) { 475 nodep->build_index = offset; 476 offset += 2 + CHAIN_LENGTH(nodep->prop_list); 477 nodep->next_index = offset; 478 } 479 offset += 1; /* add the LIST_END element */ 480 481 total_size = MD_HEADER_SIZE + offset * MD_ELEMENT_SIZE + 482 strings_size + data_block_size; 483 484 /* 485 * Allocate output buffer. 486 */ 487 488 bufferp = calloc(total_size, sizeof (uint8_t)); 489 if (bufferp == NULL) 490 return (0); 491 492 /* LINTED */ 493 mdhp = (md_header_t *)bufferp; 494 495 string_bufferp = bufferp + MD_HEADER_SIZE + offset * MD_ELEMENT_SIZE; 496 data_block_bufferp = string_bufferp + strings_size; 497 498 mdhp->transport_version = htomd32(MD_TRANSPORT_VERSION); 499 mdhp->node_blk_sz = htomd32(offset * MD_ELEMENT_SIZE); 500 mdhp->name_blk_sz = htomd32(strings_size); 501 mdhp->data_blk_sz = htomd32(data_block_size); 502 503 /* 504 * Build the element list. 505 * For each node there is a node start and end, and one 506 * element for each property. 507 */ 508 509 offset = 0; 510 /* LINTED */ 511 mdep = (md_element_t *)(bufferp + MD_HEADER_SIZE); 512 for (nodep = CHAIN_START(mdp->node_list); nodep != NULL; 513 nodep = nodep->nextp) { 514 md_prop_t *propp; 515 516 create_mde(mdep, MDET_NODE, nodep, NULL); 517 mdep++; 518 519 for (propp = CHAIN_START(nodep->prop_list); propp != NULL; 520 propp = propp->nextp) { 521 create_mde(mdep, propp->type, nodep, propp); 522 mdep++; 523 } 524 525 create_mde(mdep, MDET_NODE_END, NULL, NULL); 526 mdep++; 527 } 528 529 create_mde(mdep, MDET_LIST_END, NULL, NULL); 530 mdep++; 531 532 /* 533 * Quick sanity check. 534 */ 535 536 ASSERT(((uint8_t *)mdep) == ((uint8_t *)string_bufferp)); 537 538 /* 539 * Skip through strings and stash them.. 540 */ 541 542 offset = 0; 543 for (msp = CHAIN_START(mdp->string_list); msp != NULL; 544 msp = msp->nextp) { 545 (void) memcpy(string_bufferp + msp->build_offset, msp->strp, 546 msp->size); 547 } 548 549 /* 550 * Skip through data blocks and stash them. 551 */ 552 553 offset = 0; 554 for (mdbp = CHAIN_START(mdp->data_block_list); mdbp != NULL; 555 mdbp = mdbp->nextp) { 556 (void) memcpy(data_block_bufferp + mdbp->build_offset, 557 mdbp->datap, mdbp->size); 558 } 559 560 *bufvalp = bufferp; 561 return (total_size); 562 } 563