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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * This module implements the PTree interface and the PICL to PTree calls 31 */ 32 33 /* 34 * Note: 35 * PICL Node and Property Handles Table: 36 * A node or property in PICL tree has two handles: a ptree handle, which is 37 * used by plug-ins and the libpicltree interface, and a picl handle 38 * which is used by clients and the libpicl interface. 39 * The mapping of ptree handles to the internal PICL object (picl_obj_t) is 40 * kept in a ptree hash table (ptreetbl), and the mapping of a picl handle 41 * to its ptree handle is kept in the picl hash table (picltbl). 42 * The reader/writer lock, ptree_rwlock, is held when reading or modifying ptree 43 * hash table (ptreetbl) and/or the PICL tree structure (nodes and linkages 44 * between them). The reader/writer lock, picltbl_rwlock, is held when reading 45 * or modifying picl hash table (picltbl). 46 * 47 * The mutex, ptreehdl_lock, is used to control allocation of ptree handles. 48 * The mutex, piclhdl_lock, is used to control allocation of picl handles. 49 * 50 * The mutex, ptree_refresh_mutex, and the condition, ptree_refresh_cond, 51 * are used to synchronize PICL refreshes (ptree_refresh) and to wait/signal 52 * change in PICL tree structure. 53 * 54 * The counter, picl_hdl_hi, is the hi water mark for allocated picl handles. 55 * The counter, ptree_hdl_hi, is the hi water mark for allocated ptree handles. 56 * A stale handle error is returned for handle values below the hi water 57 * mark, and invalid handles are returned for handle values above the hi water 58 * mark or when the process id field of the handle does not match. 59 * 60 * Locking Scheme: 61 * The structure of the PICL tree is controlled by the ptree_rwlock. The 62 * properties of a node are controlled by individual node locks. The 63 * piclize-ing or unpiclize-ing of a node is controlled by picltbl_rwlock. 64 * 65 * Two-Phase Locking scheme: lock acquire phase and lock release phase. 66 * 67 * Lock Ordering: 68 * The ptree_rwlock and node locks are always acquired in the following order: 69 * lock ptree_rwlock 70 * lock node 71 * 72 * Lock Strategy: 73 * There are three locks: 74 * ptree_rwlock: a reader lock is obtained to do ptree hash table 75 * lookups and traverse tree. A writer lock is obtained 76 * when creating or destroying nodes from the ptree, 77 * or when modifying node linkages: parent, peer, child. 78 * picltbl_rwlock: a reader lock is obtained for picl hash table lookups. 79 * A writer lock is obtained when piclize-ing or 80 * unpiclize-ing nodes or properties. 81 * node_lock: This is a reader/writer lock for properties of a node. 82 * A reader lock is obtained before reading property 83 * values. A writer lock is obtained when adding or 84 * removing properties and when modifying a property value. 85 * 86 * Never hold more than one node lock at a time. 87 * 88 * Event Locking: 89 * There are two locks: 90 * evtq_lock: this lock protects the event queue. It is obtained 91 * to queue events that are posted and to unqueue 92 * events to be dispatched. 93 * evtq_cv: condition variable is protected by evtq_lock. It is 94 * used by the ptree event thread to wait for events 95 * until eventqp is not NULL. 96 * evtq_empty: condition variable protected by evtq_lock. It is 97 * used to signal when the eventq becomes empty. The 98 * reinitialization process waits on this condition. 99 * evthandler_lock: this protects the event handler list. It is obtained 100 * to add event handlers on registration and to remove 101 * event handlers on unregistration. 102 * (handler)->cv: condition variable per handler protected by 103 * evthandler_lock. It is used to wait until the 104 * event handler completes execution (execflg == 0) 105 * before unregistering the handler. 106 */ 107 108 #include <stdio.h> 109 #include <string.h> 110 #include <strings.h> 111 #include <stdlib.h> 112 #include <stdarg.h> 113 #include <alloca.h> 114 #include <assert.h> 115 #include <errno.h> 116 #include <unistd.h> 117 #include <limits.h> 118 #include <libintl.h> 119 #include <syslog.h> 120 #include <pthread.h> 121 #include <synch.h> 122 #include <setjmp.h> 123 #include <signal.h> 124 #include <dlfcn.h> 125 #include <dirent.h> 126 #include <door.h> 127 #include <time.h> 128 #include <inttypes.h> 129 #include <sys/systeminfo.h> 130 #include <sys/utsname.h> 131 #include <picl.h> 132 #include <picltree.h> 133 #include "picldefs.h" 134 #include "ptree_impl.h" 135 136 #define SO_VERS ".so.1" 137 138 static hash_t picltbl; /* client handles to picl obj */ 139 static hash_t ptreetbl; /* ptree handles to picl obj */ 140 static pthread_mutex_t ptreehdl_lock; 141 static pthread_mutex_t piclhdl_lock; 142 static pthread_mutex_t ptree_refresh_mutex; 143 static rwlock_t picltbl_rwlock; /* PICL handle table lock */ 144 static rwlock_t ptree_rwlock; /* PICL tree lock */ 145 static pthread_cond_t ptree_refresh_cond = PTHREAD_COND_INITIALIZER; 146 static uint32_t ptree_hdl_hi = 1; 147 static uint32_t picl_hdl_hi = 1; 148 static picl_obj_t *picl_root_obj = NULL; 149 static picl_nodehdl_t ptree_root_hdl = PICL_INVALID_PICLHDL; 150 static int ptree_generation = 0; 151 static pid_t picld_pid; 152 static door_cred_t picld_cred; 153 static int qempty_wait; /* evtq_empty condition waiter flag */ 154 155 static picld_plugin_reg_list_t *plugin_reg_list = NULL; 156 static picld_plugin_desc_t *plugin_desc; 157 158 static eventq_t *eventqp; /* PICL events queue */ 159 static pthread_mutex_t evtq_lock = PTHREAD_MUTEX_INITIALIZER; 160 static pthread_cond_t evtq_cv = PTHREAD_COND_INITIALIZER; 161 static pthread_cond_t evtq_empty = PTHREAD_COND_INITIALIZER; 162 static evt_handler_t *evt_handlers; /* Event handler list */ 163 static pthread_mutex_t evthandler_lock = PTHREAD_MUTEX_INITIALIZER; 164 165 /* 166 * PICL daemon verbose level 167 */ 168 int verbose_level; 169 170 171 /* 172 * Event handler free functions 173 */ 174 static void 175 free_handler(evt_handler_t *evhp) 176 { 177 if (evhp->ename) 178 free(evhp->ename); 179 (void) pthread_cond_broadcast(&evhp->cv); 180 (void) pthread_cond_destroy(&evhp->cv); 181 free(evhp); 182 } 183 184 185 /* 186 * queue_event to events queue 187 */ 188 static void 189 queue_event(eventq_t *evt) 190 { 191 eventq_t *tmpp; 192 193 evt->next = NULL; 194 if (eventqp == NULL) 195 eventqp = evt; 196 else { 197 tmpp = eventqp; 198 while (tmpp->next != NULL) 199 tmpp = tmpp->next; 200 tmpp->next = evt; 201 } 202 } 203 204 /* 205 * unqueue_event from the specified eventq 206 */ 207 static eventq_t * 208 unqueue_event(eventq_t **qp) 209 { 210 eventq_t *evtp; 211 212 evtp = *qp; 213 if (evtp != NULL) 214 *qp = evtp->next; 215 return (evtp); 216 } 217 218 /* 219 * register an event handler by adding it to the list 220 */ 221 int 222 ptree_register_handler(const char *ename, 223 void (*evt_handler)(const char *ename, const void *earg, size_t size, 224 void *cookie), void *cookie) 225 { 226 evt_handler_t *ent; 227 evt_handler_t *iter; 228 229 if (ename == NULL) 230 return (PICL_INVALIDARG); 231 232 /* 233 * Initialize event handler entry 234 */ 235 ent = malloc(sizeof (*ent)); 236 if (ent == NULL) 237 return (PICL_FAILURE); 238 ent->ename = strdup(ename); 239 if (ent->ename == NULL) { 240 free(ent); 241 return (PICL_FAILURE); 242 } 243 ent->cookie = cookie; 244 ent->evt_handler = evt_handler; 245 ent->execflg = 0; 246 ent->wakeupflg = 0; 247 (void) pthread_cond_init(&ent->cv, NULL); 248 ent->next = NULL; 249 250 /* 251 * add handler to the handler list 252 */ 253 (void) pthread_mutex_lock(&evthandler_lock); 254 if (evt_handlers == NULL) { 255 evt_handlers = ent; 256 (void) pthread_mutex_unlock(&evthandler_lock); 257 return (PICL_SUCCESS); 258 } 259 iter = evt_handlers; 260 while (iter->next != NULL) 261 iter = iter->next; 262 iter->next = ent; 263 (void) pthread_mutex_unlock(&evthandler_lock); 264 265 return (PICL_SUCCESS); 266 } 267 268 /* 269 * unregister handler 270 */ 271 void 272 ptree_unregister_handler(const char *ename, 273 void (*evt_handler)(const char *ename, const void *earg, size_t size, 274 void *cookie), void *cookie) 275 { 276 evt_handler_t *evhdlrp, **evhdlrpp; 277 278 if (ename == NULL) 279 return; 280 281 /* 282 * unlink handler from handler list 283 */ 284 (void) pthread_mutex_lock(&evthandler_lock); 285 286 retry: 287 for (evhdlrpp = &evt_handlers; (evhdlrp = *evhdlrpp) != NULL; 288 evhdlrpp = &evhdlrp->next) { 289 if ((evhdlrp->cookie != cookie) || 290 (strcmp(evhdlrp->ename, ename) != 0) || 291 (evhdlrp->evt_handler != evt_handler)) 292 continue; 293 294 /* 295 * If the handler is in execution, release the lock 296 * and wait for it to complete and retry. 297 */ 298 if (evhdlrp->execflg) { 299 evhdlrp->wakeupflg = 1; 300 (void) pthread_cond_wait(&evhdlrp->cv, 301 &evthandler_lock); 302 goto retry; 303 } 304 305 /* 306 * Unlink this handler from the linked list 307 */ 308 *evhdlrpp = evhdlrp->next; 309 free_handler(evhdlrp); 310 break; 311 } 312 313 (void) pthread_mutex_unlock(&evthandler_lock); 314 } 315 316 /* 317 * Call all registered handlers for the event 318 */ 319 static void 320 call_event_handlers(eventq_t *ev) 321 { 322 evt_handler_t *iter; 323 void (*evhandler)(const char *, const void *, size_t, void *); 324 void (*completion_handler)(char *ename, void *earg, size_t size); 325 326 (void) pthread_mutex_lock(&evthandler_lock); 327 iter = evt_handlers; 328 while (iter != NULL) { 329 if (strcmp(iter->ename, ev->ename) == 0) { 330 evhandler = iter->evt_handler; 331 iter->execflg = 1; 332 (void) pthread_mutex_unlock(&evthandler_lock); 333 if (evhandler) { 334 dbg_print(2, "ptree_evthr: Invoking evthdlr:%p" 335 " ename:%s\n", evhandler, ev->ename); 336 (*evhandler)(ev->ename, ev->earg, ev->size, 337 iter->cookie); 338 dbg_print(2, "ptree_evthr: done evthdlr:%p " 339 "ename:%s\n", evhandler, ev->ename); 340 } 341 (void) pthread_mutex_lock(&evthandler_lock); 342 iter->execflg = 0; 343 if (iter->wakeupflg) { 344 iter->wakeupflg = 0; 345 (void) pthread_cond_broadcast(&iter->cv); 346 } 347 } 348 iter = iter->next; 349 } 350 (void) pthread_mutex_unlock(&evthandler_lock); 351 if ((completion_handler = ev->completion_handler) != NULL) { 352 dbg_print(2, 353 "ptree_evthr: Invoking completion hdlr:%p ename:%s\n", 354 completion_handler, ev->ename); 355 (*completion_handler)((char *)ev->ename, (void *)ev->earg, 356 ev->size); 357 dbg_print(2, "ptree_evthr: done completion hdlr:%p ename:%s\n", 358 completion_handler, ev->ename); 359 } 360 (void) pthread_mutex_lock(&ptree_refresh_mutex); 361 ++ptree_generation; 362 (void) pthread_cond_broadcast(&ptree_refresh_cond); 363 (void) pthread_mutex_unlock(&ptree_refresh_mutex); 364 } 365 366 /* 367 * This function is called by a plug-in to post an event 368 */ 369 int 370 ptree_post_event(const char *ename, const void *earg, size_t size, 371 void (*completion_handler)(char *ename, void *earg, size_t size)) 372 { 373 eventq_t *evt; 374 375 if (ename == NULL) 376 return (PICL_INVALIDARG); 377 378 evt = malloc(sizeof (*evt)); 379 if (evt == NULL) 380 return (PICL_FAILURE); 381 evt->ename = ename; 382 evt->earg = earg; 383 evt->size = size; 384 evt->completion_handler = completion_handler; 385 386 (void) pthread_mutex_lock(&evtq_lock); 387 queue_event(evt); 388 (void) pthread_cond_broadcast(&evtq_cv); 389 (void) pthread_mutex_unlock(&evtq_lock); 390 return (PICL_SUCCESS); 391 } 392 393 /* 394 * PICLTREE event thread 395 */ 396 /*ARGSUSED*/ 397 static void * 398 ptree_event_thread(void *argp) 399 { 400 eventq_t *evt; 401 402 for (;;) { 403 (void) pthread_mutex_lock(&evtq_lock); 404 while (eventqp == NULL) { 405 /* 406 * Signal empty queue 407 */ 408 if (qempty_wait) 409 (void) pthread_cond_broadcast(&evtq_empty); 410 (void) pthread_cond_wait(&evtq_cv, &evtq_lock); 411 } 412 if ((evt = unqueue_event(&eventqp)) != NULL) { 413 (void) pthread_mutex_unlock(&evtq_lock); 414 call_event_handlers(evt); 415 free(evt); 416 } else 417 (void) pthread_mutex_unlock(&evtq_lock); 418 } 419 /*NOTREACHED*/ 420 return (NULL); 421 } 422 423 424 /* 425 * Create a new element 426 */ 427 static hash_elem_t * 428 hash_newobj(uint32_t hdl_val, void *obj_val) 429 { 430 hash_elem_t *n; 431 432 n = malloc(sizeof (*n)); 433 if (n == NULL) 434 return (NULL); 435 n->hdl = hdl_val; 436 n->hash_obj = obj_val; 437 n->next = NULL; 438 return (n); 439 } 440 441 static hash_elem_t * 442 hash_newhdl(uint32_t picl_hdl, uint32_t ptreeh) 443 { 444 hash_elem_t *n; 445 446 n = malloc(sizeof (*n)); 447 if (n == NULL) 448 return (NULL); 449 n->hdl = picl_hdl; 450 n->hash_hdl = ptreeh; 451 n->next = NULL; 452 return (n); 453 } 454 455 /* 456 * Initialize a hash table by setting all entries to NULL 457 */ 458 static int 459 hash_init(hash_t *htbl) 460 { 461 int i; 462 463 htbl->hash_size = HASH_TBL_SIZE; 464 htbl->tbl = malloc(sizeof (hash_elem_t *) * HASH_TBL_SIZE); 465 if (htbl->tbl == NULL) 466 return (-1); 467 for (i = 0; i < htbl->hash_size; ++i) 468 htbl->tbl[i] = NULL; 469 return (0); 470 } 471 472 /* 473 * Lock free function to add an entry in the hash table 474 */ 475 static int 476 hash_add_newobj(hash_t *htbl, picl_hdl_t hdl, void *pobj) 477 { 478 int indx; 479 hash_elem_t *n; 480 uint32_t hash_val = HASH_VAL(hdl); 481 482 n = hash_newobj(hash_val, pobj); 483 if (n == NULL) 484 return (-1); 485 indx = HASH_INDEX(htbl->hash_size, hash_val); 486 n->next = htbl->tbl[indx]; 487 htbl->tbl[indx] = n; 488 return (0); 489 } 490 491 static int 492 hash_add_newhdl(hash_t *htbl, picl_hdl_t piclh, picl_hdl_t ptreeh) 493 { 494 int indx; 495 hash_elem_t *n; 496 uint32_t picl_val = HASH_VAL(piclh); 497 uint32_t ptree_val = HASH_VAL(ptreeh); 498 499 n = hash_newhdl(picl_val, ptree_val); 500 if (n == NULL) 501 return (-1); 502 503 indx = HASH_INDEX(htbl->hash_size, picl_val); 504 n->next = htbl->tbl[indx]; 505 htbl->tbl[indx] = n; 506 return (0); 507 } 508 509 /* 510 * Lock free function to remove the handle from the hash table 511 * Returns -1 if element not found, 0 if successful 512 */ 513 static int 514 hash_remove(hash_t *htbl, picl_hdl_t hdl) 515 { 516 hash_elem_t *nxt; 517 hash_elem_t *cur; 518 int i; 519 uint32_t hash_val = HASH_VAL(hdl); 520 521 i = HASH_INDEX(htbl->hash_size, hash_val); 522 if (htbl->tbl[i] == NULL) 523 return (-1); 524 525 cur = htbl->tbl[i]; 526 if (cur->hdl == hash_val) { 527 htbl->tbl[i] = cur->next; 528 free(cur); 529 return (0); 530 } 531 nxt = cur->next; 532 while (nxt != NULL) { 533 if (nxt->hdl == hash_val) { 534 cur->next = nxt->next; 535 free(nxt); 536 return (0); 537 } 538 cur = nxt; 539 nxt = nxt->next; 540 } 541 return (-1); 542 } 543 544 /* 545 * Lock free function to lookup the hash table for a given handle 546 * Returns NULL if not found 547 */ 548 static void * 549 hash_lookup_obj(hash_t *htbl, picl_hdl_t hdl) 550 { 551 hash_elem_t *tmp; 552 int i; 553 uint32_t hash_val; 554 555 hash_val = HASH_VAL(hdl); 556 i = HASH_INDEX(htbl->hash_size, hash_val); 557 tmp = htbl->tbl[i]; 558 while (tmp != NULL) { 559 if (tmp->hdl == hash_val) 560 return (tmp->hash_obj); 561 tmp = tmp->next; 562 } 563 return (NULL); 564 } 565 566 static picl_hdl_t 567 hash_lookup_hdl(hash_t *htbl, picl_hdl_t hdl) 568 { 569 hash_elem_t *tmp; 570 int i; 571 uint32_t hash_val; 572 573 hash_val = HASH_VAL(hdl); 574 i = HASH_INDEX(htbl->hash_size, hash_val); 575 tmp = htbl->tbl[i]; 576 while (tmp != NULL) { 577 if (tmp->hdl == hash_val) 578 return (MAKE_HANDLE(picld_pid, tmp->hash_hdl)); 579 tmp = tmp->next; 580 } 581 return (PICL_INVALID_PICLHDL); 582 } 583 584 /* 585 * Is the PICL handle stale or invalid handle? 586 */ 587 static int 588 picl_hdl_error(picl_hdl_t hdl) 589 { 590 uint32_t hash_val = HASH_VAL(hdl); 591 pid_t pid = GET_PID(hdl); 592 int err; 593 594 (void) pthread_mutex_lock(&piclhdl_lock); 595 err = PICL_STALEHANDLE; 596 if ((pid != picld_pid) || (hash_val >= picl_hdl_hi) || 597 (hash_val == NULL)) 598 err = PICL_INVALIDHANDLE; 599 (void) pthread_mutex_unlock(&piclhdl_lock); 600 return (err); 601 } 602 603 /* 604 * Is the Ptree handle stale or invalid handle? 605 */ 606 static int 607 ptree_hdl_error(picl_hdl_t hdl) 608 { 609 uint32_t hash_val = HASH_VAL(hdl); 610 pid_t pid = GET_PID(hdl); 611 int err; 612 613 (void) pthread_mutex_lock(&ptreehdl_lock); 614 err = PICL_STALEHANDLE; 615 if ((pid != picld_pid) || (hash_val >= ptree_hdl_hi) || 616 (hash_val == NULL)) 617 err = PICL_INVALIDHANDLE; 618 (void) pthread_mutex_unlock(&ptreehdl_lock); 619 return (err); 620 } 621 622 /* 623 * For a PICL handle, return the PTree handle and the PICL object 624 * Locks and releases the PICL table. 625 */ 626 int 627 cvt_picl2ptree(picl_hdl_t hdl, picl_hdl_t *ptree_hdl) 628 { 629 picl_hdl_t tmph; 630 int err; 631 632 (void) rw_rdlock(&picltbl_rwlock); /* lock picl */ 633 tmph = hash_lookup_hdl(&picltbl, hdl); 634 if (tmph == PICL_INVALID_PICLHDL) { 635 err = picl_hdl_error(hdl); 636 (void) rw_unlock(&picltbl_rwlock); /* unlock picl */ 637 return (err); 638 } 639 *ptree_hdl = tmph; 640 (void) rw_unlock(&picltbl_rwlock); /* unlock picl */ 641 return (PICL_SUCCESS); 642 } 643 644 /* 645 * Allocate a ptree handle 646 */ 647 static picl_hdl_t 648 alloc_ptreehdl(void) 649 { 650 picl_hdl_t hdl; 651 652 (void) pthread_mutex_lock(&ptreehdl_lock); /* lock ptreehdl */ 653 hdl = MAKE_HANDLE(picld_pid, ptree_hdl_hi); 654 ++ptree_hdl_hi; 655 (void) pthread_mutex_unlock(&ptreehdl_lock); /* unlock ptreehdl */ 656 return (hdl); 657 } 658 659 /* 660 * Allocate a picl handle 661 * A PICL handle is ptree_hdl value with 1 in MSB of handle value. 662 * If a ptree handle already has 1 in MSB, then it cannot be piclized 663 * and the daemon must be restarted. 664 */ 665 static picl_hdl_t 666 alloc_piclhdl(void) 667 { 668 picl_hdl_t hdl; 669 670 (void) pthread_mutex_lock(&piclhdl_lock); /* lock piclhdl */ 671 hdl = MAKE_HANDLE(picld_pid, picl_hdl_hi); 672 ++picl_hdl_hi; 673 (void) pthread_mutex_unlock(&piclhdl_lock); /* unlock piclhdl */ 674 return (hdl); 675 } 676 677 /* 678 * Allocate and add handle to PTree hash table 679 */ 680 static void 681 alloc_and_add_to_ptree(picl_obj_t *pobj) 682 { 683 pobj->ptree_hdl = alloc_ptreehdl(); 684 (void) rw_wrlock(&ptree_rwlock); 685 (void) hash_add_newobj(&ptreetbl, pobj->ptree_hdl, pobj); 686 (void) rw_unlock(&ptree_rwlock); 687 } 688 689 /* 690 * Lock a picl node object 691 */ 692 static int 693 lock_obj(int rw, picl_obj_t *nodep) 694 { 695 if (rw == RDLOCK_NODE) 696 (void) rw_rdlock(&nodep->node_lock); 697 else if (rw == WRLOCK_NODE) 698 (void) rw_wrlock(&nodep->node_lock); 699 else 700 return (-1); 701 return (0); 702 } 703 704 /* 705 * Release the picl node object. 706 * This function may be called with a NULL object pointer. 707 */ 708 static void 709 unlock_node(picl_obj_t *nodep) 710 { 711 if (nodep == NULL) 712 return; 713 (void) rw_unlock(&nodep->node_lock); 714 } 715 716 /* 717 * This function locks the node of a property and returns the node object 718 * and the property object. 719 */ 720 static int 721 lookup_and_lock_propnode(int rw, picl_prophdl_t proph, picl_obj_t **nodep, 722 picl_obj_t **propp) 723 { 724 picl_obj_t *pobj; 725 picl_obj_t *nobj; 726 727 pobj = hash_lookup_obj(&ptreetbl, proph); 728 if (pobj == NULL) 729 return (ptree_hdl_error(proph)); 730 731 /* 732 * Get the property's or table entry's node object 733 */ 734 nobj = NULL; 735 if (pobj->obj_type == PICL_OBJ_PROP) 736 nobj = pobj->prop_node; 737 else if (pobj->obj_type == (PICL_OBJ_PROP|PICL_OBJ_TABLEENTRY)) 738 nobj = pobj->prop_table->prop_node; 739 else { 740 *propp = pobj; /* return the prop */ 741 return (PICL_NOTPROP); 742 } 743 744 if (nobj && (lock_obj(rw, nobj) < 0)) /* Lock node */ 745 return (PICL_FAILURE); 746 747 *nodep = nobj; 748 *propp = pobj; 749 750 return (PICL_SUCCESS); 751 } 752 753 /* 754 * This function locks the node of a table and returns the node object 755 * and the table object. 756 */ 757 static int 758 lookup_and_lock_tablenode(int rw, picl_prophdl_t tblh, picl_obj_t **nodep, 759 picl_obj_t **tblobj) 760 { 761 picl_obj_t *pobj; 762 picl_obj_t *nobj; 763 764 pobj = hash_lookup_obj(&ptreetbl, tblh); 765 if (pobj == NULL) 766 return (ptree_hdl_error(tblh)); 767 768 /* 769 * Get the property's or table entry's node object 770 */ 771 nobj = NULL; 772 if (pobj->obj_type != PICL_OBJ_TABLE) 773 return (PICL_NOTTABLE); 774 nobj = pobj->prop_node; 775 776 if (nobj && (lock_obj(rw, nobj) < 0)) /* Lock node */ 777 return (PICL_FAILURE); 778 779 *nodep = nobj; 780 *tblobj = pobj; 781 782 return (PICL_SUCCESS); 783 } 784 785 /* 786 * This locks the node of a table or a table entry and returns the 787 * node object and the table or table entry object 788 */ 789 static int 790 lookup_and_lock_tableprop_node(int rw, picl_prophdl_t tblproph, 791 picl_obj_t **nodep, picl_obj_t **tblpropp) 792 { 793 picl_obj_t *pobj; 794 picl_obj_t *nobj; 795 796 pobj = hash_lookup_obj(&ptreetbl, tblproph); 797 if (pobj == NULL) 798 return (ptree_hdl_error(tblproph)); 799 800 /* 801 * Get the property's or table entry's node object 802 */ 803 nobj = NULL; 804 if ((pobj->obj_type != PICL_OBJ_TABLE) && /* not a table */ 805 !(pobj->obj_type & PICL_OBJ_TABLEENTRY)) /* or an entry */ 806 return (PICL_NOTTABLE); 807 if (pobj->obj_type == PICL_OBJ_TABLE) 808 nobj = pobj->prop_node; 809 else 810 nobj = pobj->prop_table->prop_node; 811 812 if (nobj && (lock_obj(rw, nobj) < 0)) /* Lock node */ 813 return (PICL_FAILURE); 814 815 *tblpropp = pobj; 816 *nodep = nobj; 817 818 return (PICL_SUCCESS); 819 } 820 821 /* 822 * Lock the node corresponding to the given handle and return its object 823 */ 824 static int 825 lookup_and_lock_node(int rw, picl_nodehdl_t nodeh, picl_obj_t **nodep) 826 { 827 picl_obj_t *nobj; 828 829 nobj = hash_lookup_obj(&ptreetbl, nodeh); 830 if (nobj == NULL) 831 return (ptree_hdl_error(nodeh)); 832 else if (nobj->obj_type != PICL_OBJ_NODE) 833 return (PICL_NOTNODE); 834 if (lock_obj(rw, nobj) < 0) /* Lock node */ 835 return (PICL_FAILURE); 836 *nodep = nobj; 837 return (PICL_SUCCESS); 838 } 839 840 /* 841 * Is the property name a restricted property name? 842 */ 843 static int 844 picl_restricted(const char *name) 845 { 846 if (strcmp(name, PICL_PROP_CLASSNAME) == 0) 847 return (0); /* not restricted */ 848 849 if ((name[0] == '_') && (strchr(&name[1], '_') == NULL)) 850 return (1); 851 return (0); 852 } 853 854 /* 855 * Check the value size with the property size 856 * Return PICL_INVALIDARG if the size does not match exactly for strongly 857 * typed properties. 858 * For charstring reads allow sizes that match the value size 859 * For bytearray return PICL_VALUETOOBIG 860 * if the size is greater than the buffer size. 861 */ 862 static int 863 check_propsize(int op, picl_obj_t *propp, size_t sz) 864 { 865 if (propp->prop_mode & PICL_VOLATILE) { 866 if (sz != propp->prop_size) 867 return (PICL_INVALIDARG); 868 else 869 return (PICL_SUCCESS); 870 } 871 872 /* 873 * check size for non-volatile properties 874 */ 875 switch (propp->prop_type) { 876 case PICL_PTYPE_CHARSTRING: 877 if ((op == PROP_READ) && 878 (strlen(propp->prop_val) >= sz)) 879 return (PICL_VALUETOOBIG); 880 if ((op == PROP_WRITE) && (sz > propp->prop_size)) 881 return (PICL_VALUETOOBIG); 882 break; 883 case PICL_PTYPE_BYTEARRAY: 884 if (op == PROP_WRITE) { 885 if (sz > propp->prop_size) 886 return (PICL_VALUETOOBIG); 887 return (PICL_SUCCESS); /* allow small writes */ 888 } 889 /* fall through for reads */ 890 default: 891 if (propp->prop_size != sz) 892 return (PICL_INVALIDARG); 893 break; 894 } 895 return (PICL_SUCCESS); 896 } 897 898 void 899 cvt_ptree2picl(picl_hdl_t *handlep) 900 { 901 picl_obj_t *pobj; 902 903 (void) rw_rdlock(&ptree_rwlock); 904 pobj = hash_lookup_obj(&ptreetbl, *handlep); 905 if (pobj == NULL) 906 *handlep = PICL_INVALID_PICLHDL; 907 else 908 (void) memcpy(handlep, &pobj->picl_hdl, sizeof (*handlep)); 909 (void) rw_unlock(&ptree_rwlock); 910 } 911 912 /* 913 * The caller of the piclize() set of functions is assumed to hold 914 * the ptree_rwlock(). 915 */ 916 static void 917 piclize_obj(picl_obj_t *pobj) 918 { 919 (void) rw_wrlock(&picltbl_rwlock); 920 pobj->picl_hdl = alloc_piclhdl(); 921 (void) hash_add_newhdl(&picltbl, pobj->picl_hdl, pobj->ptree_hdl); 922 (void) rw_unlock(&picltbl_rwlock); 923 } 924 925 static void 926 piclize_table(picl_obj_t *tbl_obj) 927 { 928 picl_obj_t *rowp; 929 picl_obj_t *colp; 930 931 for (rowp = tbl_obj->next_row; rowp != NULL; rowp = rowp->next_col) 932 for (colp = rowp; colp != NULL; colp = colp->next_row) 933 piclize_obj(colp); 934 } 935 936 static void 937 piclize_prop(picl_obj_t *propp) 938 { 939 picl_obj_t *tbl_obj; 940 picl_prophdl_t tblh; 941 942 piclize_obj(propp); 943 if (!(propp->prop_mode & PICL_VOLATILE) && 944 (propp->prop_type == PICL_PTYPE_TABLE)) { 945 tblh = *(picl_prophdl_t *)propp->prop_val; 946 tbl_obj = hash_lookup_obj(&ptreetbl, tblh); 947 if (tbl_obj == NULL) 948 return; 949 piclize_obj(tbl_obj); 950 piclize_table(tbl_obj); 951 } 952 } 953 954 /* 955 * Function to create PICL handles for a subtree and add them to 956 * the table 957 */ 958 static void 959 piclize_node(picl_obj_t *nodep) 960 { 961 picl_obj_t *propp; 962 picl_obj_t *chdp; 963 964 piclize_obj(nodep); 965 propp = nodep->first_prop; 966 while (propp != NULL) { 967 piclize_prop(propp); 968 propp = propp->next_prop; 969 } 970 971 /* go through the children */ 972 for (chdp = nodep->child_node; chdp != NULL; chdp = chdp->sibling_node) 973 piclize_node(chdp); 974 } 975 976 /* 977 * Function to remove PICL handles 978 */ 979 static void 980 unpiclize_obj(picl_obj_t *pobj) 981 { 982 (void) rw_wrlock(&picltbl_rwlock); 983 (void) hash_remove(&picltbl, pobj->picl_hdl); 984 pobj->picl_hdl = PICL_INVALID_PICLHDL; 985 (void) rw_unlock(&picltbl_rwlock); 986 } 987 988 static void 989 unpiclize_table(picl_obj_t *tbl_obj) 990 { 991 picl_obj_t *rowp; 992 picl_obj_t *colp; 993 994 for (rowp = tbl_obj->next_row; rowp != NULL; rowp = rowp->next_col) 995 for (colp = rowp; colp != NULL; colp = colp->next_row) 996 unpiclize_obj(colp); 997 unpiclize_obj(tbl_obj); 998 } 999 1000 static void 1001 unpiclize_prop(picl_obj_t *propp) 1002 { 1003 picl_obj_t *tbl_obj; 1004 picl_prophdl_t tblh; 1005 1006 if (!IS_PICLIZED(propp)) 1007 return; 1008 unpiclize_obj(propp); 1009 if (!(propp->prop_mode & PICL_VOLATILE) && 1010 (propp->prop_type == PICL_PTYPE_TABLE)) { 1011 tblh = *(picl_prophdl_t *)propp->prop_val; 1012 tbl_obj = hash_lookup_obj(&ptreetbl, tblh); 1013 unpiclize_table(tbl_obj); 1014 } 1015 } 1016 1017 /* 1018 * Function to remove PICL handles for a subtree and its 1019 * properties 1020 */ 1021 static void 1022 unpiclize_node(picl_obj_t *nodep) 1023 { 1024 picl_obj_t *propp; 1025 picl_obj_t *chdp; 1026 1027 1028 if (!IS_PICLIZED(nodep)) 1029 return; 1030 1031 unpiclize_obj(nodep); 1032 propp = nodep->first_prop; 1033 while (propp != NULL) { 1034 unpiclize_prop(propp); 1035 propp = propp->next_prop; 1036 } 1037 1038 /* go through the children */ 1039 for (chdp = nodep->child_node; chdp != NULL; chdp = chdp->sibling_node) 1040 unpiclize_node(chdp); 1041 } 1042 1043 1044 /* 1045 * The caller holds the lock on the ptree_lock when calling this. 1046 * If ret is not NULL then this function returns the referenced object. 1047 */ 1048 static int 1049 lookup_verify_ref_prop(picl_obj_t *propp, picl_obj_t **ret) 1050 { 1051 picl_nodehdl_t refh; 1052 picl_obj_t *refobj; 1053 1054 refh = *(picl_nodehdl_t *)propp->prop_val; 1055 refobj = hash_lookup_obj(&ptreetbl, refh); 1056 if (refobj == NULL) 1057 return (ptree_hdl_error(refh)); 1058 else if (refobj->obj_type != PICL_OBJ_NODE) 1059 return (PICL_INVREFERENCE); 1060 if (ret) 1061 *ret = refobj; 1062 return (PICL_SUCCESS); 1063 } 1064 1065 /* 1066 * The caller holds the lock on ptree_lock when calling this. 1067 * If ret is not NULL, then this function returns the table object 1068 */ 1069 static int 1070 lookup_verify_table_prop(picl_obj_t *propp, picl_obj_t **ret) 1071 { 1072 picl_prophdl_t tblh; 1073 picl_obj_t *tbl_obj; 1074 1075 tblh = *(picl_prophdl_t *)propp->prop_val; 1076 tbl_obj = hash_lookup_obj(&ptreetbl, tblh); 1077 if (tbl_obj == NULL) 1078 return (ptree_hdl_error(tblh)); 1079 else if (!(tbl_obj->obj_type & PICL_OBJ_TABLE)) 1080 return (PICL_NOTTABLE); 1081 if (ret) 1082 *ret = tbl_obj; 1083 return (PICL_SUCCESS); 1084 } 1085 1086 static int 1087 lookup_verify_prop_handle(picl_prophdl_t proph, picl_obj_t **ret) 1088 { 1089 picl_obj_t *propp; 1090 1091 propp = hash_lookup_obj(&ptreetbl, proph); 1092 if (propp == NULL) 1093 return (ptree_hdl_error(proph)); 1094 else if (!(propp->obj_type & PICL_OBJ_PROP)) 1095 return (PICL_NOTPROP); 1096 if (ret) 1097 *ret = propp; 1098 return (PICL_SUCCESS); 1099 } 1100 1101 static int 1102 lookup_verify_node_handle(picl_nodehdl_t nodeh, picl_obj_t **ret) 1103 { 1104 picl_obj_t *nodep; 1105 1106 nodep = hash_lookup_obj(&ptreetbl, nodeh); 1107 if (nodep == NULL) 1108 return (ptree_hdl_error(nodeh)); 1109 else if (nodep->obj_type != PICL_OBJ_NODE) 1110 return (PICL_NOTNODE); 1111 if (ret) 1112 *ret = nodep; 1113 return (PICL_SUCCESS); 1114 } 1115 1116 static int 1117 lookup_prop_by_name(picl_obj_t *nodep, const char *pname, picl_obj_t **ret) 1118 { 1119 picl_obj_t *propp; 1120 1121 if (strcmp(pname, PICL_PROP_PARENT) == 0) { 1122 if (nodep->parent_node == NULL) 1123 return (PICL_PROPNOTFOUND); 1124 else 1125 return (PICL_SUCCESS); 1126 } 1127 if (strcmp(pname, PICL_PROP_CHILD) == 0) { 1128 if (nodep->child_node == NULL) 1129 return (PICL_PROPNOTFOUND); 1130 else 1131 return (PICL_SUCCESS); 1132 } 1133 if (strcmp(pname, PICL_PROP_PEER) == 0) { 1134 if (nodep->sibling_node == NULL) 1135 return (PICL_PROPNOTFOUND); 1136 else 1137 return (PICL_SUCCESS); 1138 } 1139 1140 propp = nodep->first_prop; 1141 while (propp != NULL) { 1142 if (strcmp(propp->prop_name, pname) == 0) { 1143 if (ret) 1144 *ret = propp; 1145 return (PICL_SUCCESS); 1146 } 1147 propp = propp->next_prop; 1148 } 1149 return (PICL_PROPNOTFOUND); 1150 } 1151 1152 /* 1153 * This function locks the ptree, verifies that the handle is a reference 1154 * to a node of specified class name, releases the lock 1155 */ 1156 static int 1157 check_ref_handle(picl_nodehdl_t refh, char *clname) 1158 { 1159 picl_obj_t *refobj; 1160 picl_obj_t *propp; 1161 int err; 1162 1163 (void) rw_rdlock(&ptree_rwlock); /* Lock ptree */ 1164 refobj = hash_lookup_obj(&ptreetbl, refh); 1165 if ((refobj == NULL) || !(refobj->obj_type & PICL_OBJ_NODE)) { 1166 (void) rw_unlock(&ptree_rwlock); 1167 return (PICL_INVREFERENCE); 1168 } 1169 1170 err = lookup_prop_by_name(refobj, PICL_PROP_CLASSNAME, &propp); 1171 if ((err != PICL_SUCCESS) || (propp->prop_val == NULL) || 1172 (strcmp(propp->prop_val, clname) != 0)) 1173 err = PICL_INVREFERENCE; 1174 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 1175 return (err); 1176 } 1177 1178 static int 1179 check_table_handle(picl_prophdl_t tblh) 1180 { 1181 picl_obj_t *tbl_obj; 1182 int err; 1183 1184 (void) rw_rdlock(&ptree_rwlock); 1185 err = PICL_SUCCESS; 1186 tbl_obj = hash_lookup_obj(&ptreetbl, tblh); 1187 if ((tbl_obj == NULL) || !(tbl_obj->obj_type & PICL_OBJ_TABLE)) 1188 err = PICL_NOTTABLE; 1189 (void) rw_unlock(&ptree_rwlock); 1190 return (err); 1191 } 1192 1193 /* 1194 * PICLTree Interface routines for plug-in modules 1195 */ 1196 int 1197 ptree_get_root(picl_nodehdl_t *rooth) 1198 { 1199 *rooth = ptree_root_hdl; 1200 return (PICL_SUCCESS); 1201 } 1202 1203 /* 1204 * Lock free create a property object 1205 */ 1206 static int 1207 create_propobj(const ptree_propinfo_t *pinfo, const void *valbuf, 1208 picl_obj_t **pobjp) 1209 { 1210 picl_obj_t *pobj; 1211 1212 if (pinfo->version != PTREE_PROPINFO_VERSION_1) 1213 return (PICL_NOTSUPPORTED); 1214 1215 if (!(pinfo->piclinfo.accessmode & PICL_VOLATILE) && 1216 (pinfo->piclinfo.type != PICL_PTYPE_VOID) && 1217 (valbuf == NULL)) 1218 return (PICL_INVALIDARG); 1219 1220 pobj = malloc(sizeof (picl_obj_t)); 1221 if (pobj == NULL) 1222 return (PICL_FAILURE); 1223 1224 pobj->obj_type = PICL_OBJ_PROP; 1225 pobj->pinfo_ver = pinfo->version; 1226 pobj->prop_type = pinfo->piclinfo.type; 1227 pobj->prop_mode = pinfo->piclinfo.accessmode; 1228 pobj->prop_size = pinfo->piclinfo.size; 1229 (void) strcpy(pobj->prop_name, pinfo->piclinfo.name); 1230 pobj->read_func = pinfo->read; 1231 pobj->write_func = pinfo->write; 1232 1233 pobj->prop_val = NULL; 1234 if (!(pinfo->piclinfo.accessmode & PICL_VOLATILE)) { 1235 pobj->prop_val = malloc(pinfo->piclinfo.size); 1236 if (pobj->prop_val == NULL) { 1237 free(pobj); 1238 return (PICL_FAILURE); 1239 } 1240 if (pobj->prop_type == PICL_PTYPE_CHARSTRING) 1241 (void) strlcpy(pobj->prop_val, valbuf, 1242 pinfo->piclinfo.size); 1243 else 1244 (void) memcpy(pobj->prop_val, valbuf, 1245 pinfo->piclinfo.size); 1246 } 1247 pobj->prop_node = NULL; 1248 pobj->ptree_hdl = PICL_INVALID_PICLHDL; 1249 pobj->picl_hdl = PICL_INVALID_PICLHDL; 1250 pobj->next_prop = NULL; 1251 pobj->next_row = NULL; 1252 pobj->next_col = NULL; 1253 1254 *pobjp = pobj; 1255 return (PICL_SUCCESS); 1256 } 1257 1258 /* 1259 * Check for valid arguments, create a property object, 1260 * Lock ptree_rwlock, add the new property handle, release the lock 1261 * For reference properties and table properties, the handles are verified 1262 * before creating the property. 1263 */ 1264 int 1265 ptree_create_prop(const ptree_propinfo_t *pinfo, const void *valbuf, 1266 picl_prophdl_t *proph) 1267 { 1268 picl_obj_t *pobj; 1269 picl_nodehdl_t refh; 1270 picl_prophdl_t tblh; 1271 int err; 1272 char *ptr; 1273 int refflag; 1274 char classname[PICL_PROPNAMELEN_MAX]; 1275 1276 if (pinfo == NULL) 1277 return (PICL_INVALIDARG); 1278 if (pinfo->version != PTREE_PROPINFO_VERSION_1) 1279 return (PICL_NOTSUPPORTED); 1280 if (pinfo->piclinfo.size >= PICL_PROPSIZE_MAX) 1281 return (PICL_VALUETOOBIG); 1282 if (picl_restricted(pinfo->piclinfo.name)) 1283 return (PICL_RESERVEDNAME); 1284 1285 refflag = 0; 1286 if ((pinfo->piclinfo.name[0] == '_') && 1287 (strchr(&pinfo->piclinfo.name[1], '_') != NULL)) 1288 refflag = 1; 1289 1290 if (pinfo->piclinfo.type == PICL_PTYPE_REFERENCE) { 1291 if (refflag == 0) 1292 return (PICL_INVREFERENCE); 1293 /* 1294 * check valid reference handle for non-volatiles 1295 */ 1296 if (!(pinfo->piclinfo.accessmode & PICL_VOLATILE)) { 1297 if (valbuf == NULL) 1298 return (PICL_INVREFERENCE); 1299 if (pinfo->piclinfo.size != sizeof (picl_nodehdl_t)) 1300 return (PICL_INVREFERENCE); 1301 (void) strcpy(classname, pinfo->piclinfo.name); 1302 ptr = strchr(&classname[1], '_'); 1303 *ptr = '\0'; 1304 refh = *(picl_hdl_t *)valbuf; 1305 err = check_ref_handle(refh, &classname[1]); 1306 if (err != PICL_SUCCESS) 1307 return (err); 1308 } 1309 } else if (refflag == 1) 1310 return (PICL_INVREFERENCE); 1311 else if ((pinfo->piclinfo.type == PICL_PTYPE_TABLE) && 1312 (!(pinfo->piclinfo.accessmode & PICL_VOLATILE))) { 1313 if (pinfo->piclinfo.size != sizeof (picl_prophdl_t)) 1314 return (PICL_INVALIDARG); 1315 tblh = *(picl_prophdl_t *)valbuf; 1316 err = check_table_handle(tblh); 1317 if (err != PICL_SUCCESS) 1318 return (err); 1319 } else if ((strcmp(pinfo->piclinfo.name, PICL_PROP_CLASSNAME) == 0) && 1320 ((pinfo->piclinfo.type != PICL_PTYPE_CHARSTRING) || 1321 (strlen(valbuf) >= PICL_CLASSNAMELEN_MAX))) 1322 return (PICL_RESERVEDNAME); 1323 else if ((strcmp(pinfo->piclinfo.name, PICL_PROP_NAME) == 0) && 1324 (pinfo->piclinfo.type != PICL_PTYPE_CHARSTRING)) 1325 return (PICL_RESERVEDNAME); 1326 /* 1327 * No locks held when you get here 1328 */ 1329 err = create_propobj(pinfo, valbuf, &pobj); 1330 if (err != PICL_SUCCESS) 1331 return (err); 1332 1333 alloc_and_add_to_ptree(pobj); 1334 *proph = pobj->ptree_hdl; 1335 return (PICL_SUCCESS); 1336 } 1337 1338 /* 1339 * Lock free routine to destroy table entries 1340 * This function removes the destroyed handles from the hash table 1341 * Uses lock free routines: hash_lookup() and hash_remove() 1342 */ 1343 static void 1344 destroy_table(picl_obj_t *pobj) 1345 { 1346 picl_prophdl_t tblh; 1347 picl_obj_t *tbl_obj; 1348 picl_obj_t *rowp; 1349 picl_obj_t *colp; 1350 picl_obj_t *freep; 1351 1352 tblh = *(picl_prophdl_t *)pobj->prop_val; 1353 tbl_obj = hash_lookup_obj(&ptreetbl, tblh); 1354 if (tbl_obj == NULL) 1355 return; 1356 1357 assert(tbl_obj->obj_type & PICL_OBJ_TABLE); 1358 1359 /* Delete all entries */ 1360 rowp = tbl_obj->next_row; 1361 while (rowp != NULL) { 1362 colp = rowp; 1363 rowp = rowp->next_col; 1364 while (colp != NULL) { 1365 freep = colp; 1366 colp = colp->next_row; 1367 (void) hash_remove(&ptreetbl, freep->ptree_hdl); 1368 if (freep->prop_val) 1369 free(freep->prop_val); 1370 free(freep); 1371 } 1372 } 1373 1374 (void) hash_remove(&ptreetbl, tbl_obj->ptree_hdl); 1375 free(tbl_obj); 1376 } 1377 1378 1379 /* 1380 * Lock free function that frees up a property object and removes the 1381 * handles from Ptree table 1382 */ 1383 static void 1384 destroy_propobj(picl_obj_t *propp) 1385 { 1386 if (propp->prop_type == PICL_PTYPE_TABLE) 1387 destroy_table(propp); 1388 1389 (void) hash_remove(&ptreetbl, propp->ptree_hdl); 1390 if (propp->prop_val) 1391 free(propp->prop_val); 1392 free(propp); 1393 } 1394 1395 /* 1396 * This function destroys a previously deleted property. 1397 * A deleted property does not have an associated node. 1398 * All memory allocated for this property are freed 1399 */ 1400 int 1401 ptree_destroy_prop(picl_prophdl_t proph) 1402 { 1403 picl_obj_t *propp; 1404 1405 (void) rw_wrlock(&ptree_rwlock); /* Exclusive Lock ptree */ 1406 1407 propp = hash_lookup_obj(&ptreetbl, proph); 1408 if (propp == NULL) { 1409 (void) rw_unlock(&ptree_rwlock); /* Unlock ptree */ 1410 return (ptree_hdl_error(proph)); 1411 } 1412 1413 /* Is the prop still attached to a node? */ 1414 if (propp->prop_node != NULL) { 1415 (void) rw_unlock(&ptree_rwlock); /* Unlock ptree */ 1416 return (PICL_CANTDESTROY); 1417 } 1418 1419 destroy_propobj(propp); 1420 1421 (void) rw_unlock(&ptree_rwlock); /* Unlock ptree */ 1422 return (PICL_SUCCESS); 1423 } 1424 1425 /* 1426 * This function adds a property to the property list of a node and adds 1427 * it to the PICL table if the node has a PICL handle. 1428 * This function locks the picl_rwlock and ptree_rwlock. 1429 */ 1430 int 1431 ptree_add_prop(picl_nodehdl_t nodeh, picl_prophdl_t proph) 1432 { 1433 int err; 1434 picl_obj_t *nodep; 1435 picl_obj_t *propp; 1436 picl_obj_t *tbl_obj; 1437 picl_obj_t *refobj; 1438 1439 (void) rw_rdlock(&ptree_rwlock); /* RDLock ptree */ 1440 1441 /* 1442 * Verify property handle 1443 */ 1444 err = lookup_verify_prop_handle(proph, &propp); 1445 if (err != PICL_SUCCESS) { 1446 (void) rw_unlock(&ptree_rwlock); /* Unlock ptree */ 1447 return (err); 1448 } 1449 1450 if (propp->prop_node != NULL) { 1451 (void) rw_unlock(&ptree_rwlock); 1452 return (PICL_INVALIDARG); 1453 } 1454 1455 nodep = NULL; 1456 /* 1457 * Exclusive Lock the node's properties 1458 */ 1459 err = lookup_and_lock_node(WRLOCK_NODE, nodeh, &nodep); 1460 if (err != PICL_SUCCESS) { 1461 (void) rw_unlock(&ptree_rwlock); /* Unlock ptree */ 1462 return (err); 1463 } 1464 1465 /* 1466 * check if prop already exists 1467 */ 1468 err = lookup_prop_by_name(nodep, propp->prop_name, NULL); 1469 if (err == PICL_SUCCESS) { 1470 unlock_node(nodep); /* Unlock node */ 1471 (void) rw_unlock(&ptree_rwlock); /* Unlock table */ 1472 return (PICL_PROPEXISTS); 1473 } 1474 1475 /* 1476 * Verify property's value 1477 */ 1478 tbl_obj = NULL; 1479 switch (propp->prop_type) { 1480 case PICL_PTYPE_TABLE: 1481 if (propp->prop_mode & PICL_VOLATILE) 1482 break; 1483 err = lookup_verify_table_prop(propp, &tbl_obj); 1484 if (err != PICL_SUCCESS) { 1485 unlock_node(nodep); 1486 (void) rw_unlock(&ptree_rwlock); 1487 return (err); 1488 } 1489 tbl_obj->prop_node = nodep; /* set table's nodep */ 1490 tbl_obj->table_prop = propp; /* set table prop */ 1491 break; 1492 case PICL_PTYPE_REFERENCE: 1493 if (propp->prop_mode & PICL_VOLATILE) 1494 break; 1495 err = lookup_verify_ref_prop(propp, &refobj); 1496 if (err != PICL_SUCCESS) { 1497 unlock_node(nodep); 1498 (void) rw_unlock(&ptree_rwlock); 1499 return (err); 1500 } 1501 if (IS_PICLIZED(nodep) && !IS_PICLIZED(refobj)) { 1502 unlock_node(nodep); 1503 (void) rw_unlock(&ptree_rwlock); 1504 return (err); 1505 } 1506 break; 1507 default: 1508 break; 1509 } 1510 1511 if (IS_PICLIZED(nodep)) 1512 piclize_prop(propp); 1513 /* 1514 * Add prop to beginning of list 1515 */ 1516 propp->prop_node = nodep; /* set prop's nodep */ 1517 propp->next_prop = nodep->first_prop; 1518 nodep->first_prop = propp; 1519 1520 unlock_node(nodep); /* Unlock node */ 1521 (void) rw_unlock(&ptree_rwlock); /* Unlock table */ 1522 return (PICL_SUCCESS); 1523 } 1524 1525 /* 1526 * Lock free function that unlinks a property from its node 1527 */ 1528 static int 1529 unlink_prop(picl_obj_t *nodep, picl_obj_t *propp) 1530 { 1531 picl_obj_t *iterp; 1532 1533 iterp = nodep->first_prop; 1534 if (iterp == propp) { /* first property */ 1535 nodep->first_prop = iterp->next_prop; 1536 return (PICL_SUCCESS); 1537 } 1538 while ((iterp != NULL) && (iterp->next_prop != propp)) 1539 iterp = iterp->next_prop; 1540 if (iterp == NULL) 1541 return (PICL_PROPNOTFOUND); 1542 iterp->next_prop = propp->next_prop; 1543 return (PICL_SUCCESS); 1544 } 1545 1546 /* 1547 * This function deletes the specified property from the property list 1548 * of its node and removes the handle from PICL table, if the node 1549 * was piclized. 1550 */ 1551 int 1552 ptree_delete_prop(picl_prophdl_t proph) 1553 { 1554 int err; 1555 picl_obj_t *nodep; 1556 picl_obj_t *propp; 1557 1558 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */ 1559 /* 1560 * Lookup the property's node and lock it if there is one 1561 * return the objects for the property and the node 1562 */ 1563 nodep = propp = NULL; 1564 err = lookup_and_lock_propnode(WRLOCK_NODE, proph, &nodep, &propp); 1565 if (err != PICL_SUCCESS) { 1566 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 1567 return (err); 1568 } else if (nodep == NULL) { 1569 /* Nothing to do - already deleted! */ 1570 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 1571 return (PICL_SUCCESS); 1572 } 1573 1574 if (propp->obj_type & PICL_OBJ_TABLEENTRY) { 1575 unlock_node(nodep); /* Unlock node */ 1576 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 1577 return (PICL_NOTPROP); 1578 } 1579 1580 err = unlink_prop(nodep, propp); 1581 if (err != PICL_SUCCESS) { 1582 unlock_node(nodep); /* Unlock node */ 1583 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 1584 return (err); 1585 } 1586 1587 propp->prop_node = NULL; /* reset prop's nodep */ 1588 propp->next_prop = NULL; 1589 1590 unpiclize_prop(propp); 1591 1592 unlock_node(nodep); /* Unlock node */ 1593 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 1594 return (PICL_SUCCESS); 1595 } 1596 1597 /* 1598 * Create a table object and return its handle 1599 */ 1600 int 1601 ptree_create_table(picl_prophdl_t *tblh) 1602 { 1603 picl_obj_t *pobj; 1604 1605 pobj = malloc(sizeof (picl_obj_t)); 1606 if (pobj == NULL) 1607 return (PICL_FAILURE); 1608 pobj->obj_type = PICL_OBJ_TABLE; 1609 pobj->prop_val = NULL; 1610 pobj->prop_node = NULL; 1611 pobj->ptree_hdl = PICL_INVALID_PICLHDL; 1612 pobj->picl_hdl = PICL_INVALID_PICLHDL; 1613 pobj->table_prop = NULL; 1614 pobj->next_row = NULL; 1615 pobj->next_col = NULL; 1616 1617 alloc_and_add_to_ptree(pobj); 1618 *tblh = pobj->ptree_hdl; 1619 return (PICL_SUCCESS); 1620 } 1621 1622 /* 1623 * Add the properties in <props> array as a row in the table 1624 * Add PICL handles if the table has a valid PICL handle 1625 */ 1626 int 1627 ptree_add_row_to_table(picl_prophdl_t tblh, int nprops, 1628 const picl_prophdl_t *props) 1629 { 1630 picl_obj_t *tbl_obj; 1631 picl_obj_t *nodep; 1632 picl_obj_t *lastrow; 1633 picl_obj_t **newrow; 1634 int i; 1635 int err; 1636 picl_obj_t *pobj; 1637 int picl_it; 1638 1639 if (nprops < 1) 1640 return (PICL_INVALIDARG); 1641 1642 newrow = malloc(sizeof (picl_obj_t *) * nprops); 1643 if (newrow == NULL) 1644 return (PICL_FAILURE); 1645 1646 (void) rw_rdlock(&ptree_rwlock); /* Lock ptree */ 1647 1648 err = lookup_and_lock_tablenode(WRLOCK_NODE, tblh, &nodep, &tbl_obj); 1649 if (err != PICL_SUCCESS) { 1650 free(newrow); 1651 (void) rw_unlock(&ptree_rwlock); /* Unlock table */ 1652 return (err); 1653 } 1654 1655 /* 1656 * make sure all are either props or table handles 1657 */ 1658 for (i = 0; i < nprops; ++i) { 1659 pobj = newrow[i] = hash_lookup_obj(&ptreetbl, props[i]); 1660 if (pobj == NULL) { /* no object */ 1661 err = ptree_hdl_error(props[i]); 1662 break; 1663 } 1664 if ((!(pobj->obj_type & PICL_OBJ_PROP)) && 1665 (!(pobj->obj_type & PICL_OBJ_TABLE))) { 1666 err = PICL_NOTPROP; 1667 break; 1668 } 1669 if (IS_PICLIZED(pobj) || (pobj->prop_table != NULL) || 1670 (pobj->prop_node != NULL)) { 1671 err = PICL_INVALIDARG; 1672 break; 1673 } 1674 1675 } 1676 if (err != PICL_SUCCESS) { 1677 free(newrow); 1678 unlock_node(nodep); 1679 (void) rw_unlock(&ptree_rwlock); /* Unlock table */ 1680 return (err); 1681 } 1682 1683 /* 1684 * Mark all props as table entries, set up row linkages 1685 */ 1686 picl_it = 0; 1687 if (IS_PICLIZED(tbl_obj)) 1688 picl_it = 1; 1689 for (i = 0; i < nprops; ++i) { 1690 newrow[i]->obj_type |= PICL_OBJ_TABLEENTRY; 1691 newrow[i]->prop_table = tbl_obj; 1692 newrow[i]->next_prop = NULL; 1693 newrow[i]->next_col = NULL; 1694 if (picl_it) 1695 piclize_obj(newrow[i]); 1696 if (i != nprops - 1) 1697 newrow[i]->next_row = newrow[i+1]; 1698 } 1699 newrow[nprops - 1]->next_row = NULL; 1700 1701 if (tbl_obj->next_row == NULL) { /* add first row */ 1702 tbl_obj->next_row = newrow[0]; 1703 tbl_obj->next_col = newrow[0]; 1704 } else { 1705 lastrow = tbl_obj->next_row; 1706 while (lastrow->next_col != NULL) 1707 lastrow = lastrow->next_col; 1708 i = 0; 1709 while (lastrow != NULL) { 1710 lastrow->next_col = newrow[i]; 1711 lastrow = lastrow->next_row; 1712 ++i; 1713 } 1714 } 1715 1716 unlock_node(nodep); /* unlock node */ 1717 (void) rw_unlock(&ptree_rwlock); /* Unlock ptree */ 1718 free(newrow); 1719 return (PICL_SUCCESS); 1720 } 1721 1722 /* 1723 * This function returns the handle of the next property in the row 1724 */ 1725 int 1726 ptree_get_next_by_row(picl_prophdl_t proph, picl_prophdl_t *nextrowh) 1727 { 1728 int err; 1729 picl_obj_t *nodep; 1730 picl_obj_t *propp; 1731 1732 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */ 1733 1734 nodep = propp = NULL; 1735 /* 1736 * proph could be a table handle or a table entry handle 1737 * Look it up as a table entry handle first, check error code 1738 * to see if it is a table handle 1739 */ 1740 err = lookup_and_lock_tableprop_node(RDLOCK_NODE, proph, &nodep, 1741 &propp); 1742 if (err != PICL_SUCCESS) { 1743 (void) rw_unlock(&ptree_rwlock); 1744 return (err); 1745 } 1746 1747 if (propp->next_row) 1748 *nextrowh = propp->next_row->ptree_hdl; 1749 else 1750 err = PICL_ENDOFLIST; 1751 1752 unlock_node(nodep); /* unlock node */ 1753 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 1754 return (err); 1755 } 1756 1757 int 1758 ptree_get_next_by_col(picl_prophdl_t proph, picl_prophdl_t *nextcolh) 1759 { 1760 int err; 1761 picl_obj_t *propp; 1762 picl_obj_t *nodep; 1763 1764 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */ 1765 nodep = propp = NULL; 1766 /* 1767 * proph could be a table handle or a table entry handle 1768 * Look it up as a table entry handle first, check error code 1769 * to see if it is a table handle 1770 */ 1771 err = lookup_and_lock_tableprop_node(RDLOCK_NODE, proph, &nodep, 1772 &propp); 1773 if (err != PICL_SUCCESS) { 1774 (void) rw_unlock(&ptree_rwlock); 1775 return (err); 1776 } 1777 1778 if (propp->next_col) 1779 *nextcolh = propp->next_col->ptree_hdl; 1780 else 1781 err = PICL_ENDOFLIST; 1782 1783 unlock_node(nodep); /* unlock node */ 1784 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 1785 return (err); 1786 } 1787 1788 /* 1789 * This function creates node object and adds its handle to the Ptree 1790 */ 1791 int 1792 ptree_create_node(const char *name, const char *clname, picl_nodehdl_t *nodeh) 1793 { 1794 picl_obj_t *pobj; 1795 ptree_propinfo_t propinfo; 1796 picl_prophdl_t phdl; 1797 picl_prophdl_t cphdl; 1798 int err; 1799 1800 if ((name == NULL) || (*name == '\0') || 1801 (clname == NULL) || (*clname == '\0')) 1802 return (PICL_INVALIDARG); 1803 1804 if ((strlen(name) >= PICL_PROPNAMELEN_MAX) || 1805 (strlen(clname) >= PICL_CLASSNAMELEN_MAX)) 1806 return (PICL_VALUETOOBIG); 1807 1808 /* 1809 * Create the picl object for node 1810 */ 1811 pobj = malloc(sizeof (picl_obj_t)); 1812 if (pobj == NULL) 1813 return (PICL_FAILURE); 1814 pobj->obj_type = PICL_OBJ_NODE; 1815 pobj->first_prop = NULL; 1816 pobj->ptree_hdl = PICL_INVALID_PICLHDL; 1817 pobj->picl_hdl = PICL_INVALID_PICLHDL; 1818 pobj->parent_node = NULL; 1819 pobj->sibling_node = NULL; 1820 pobj->child_node = NULL; 1821 pobj->node_classname = strdup(clname); 1822 if (pobj->node_classname == NULL) { 1823 free(pobj); 1824 return (PICL_FAILURE); 1825 } 1826 (void) rwlock_init(&pobj->node_lock, USYNC_THREAD, NULL); 1827 1828 alloc_and_add_to_ptree(pobj); /* commit the node */ 1829 1830 /* 1831 * create name property 1832 */ 1833 propinfo.version = PTREE_PROPINFO_VERSION_1; 1834 propinfo.piclinfo.type = PICL_PTYPE_CHARSTRING; 1835 propinfo.piclinfo.accessmode = PICL_READ; 1836 propinfo.piclinfo.size = strlen(name) + 1; 1837 (void) strcpy(propinfo.piclinfo.name, PICL_PROP_NAME); 1838 propinfo.read = NULL; 1839 propinfo.write = NULL; 1840 err = ptree_create_prop(&propinfo, (const void *)name, &phdl); 1841 if (err != PICL_SUCCESS) { 1842 (void) ptree_destroy_node(pobj->ptree_hdl); 1843 return (err); 1844 } 1845 err = ptree_add_prop(pobj->ptree_hdl, phdl); 1846 if (err != PICL_SUCCESS) { 1847 (void) ptree_destroy_prop(phdl); 1848 (void) ptree_destroy_node(pobj->ptree_hdl); 1849 return (err); 1850 } 1851 1852 /* 1853 * create picl classname property 1854 */ 1855 propinfo.piclinfo.size = strlen(clname) + 1; 1856 (void) strcpy(propinfo.piclinfo.name, PICL_PROP_CLASSNAME); 1857 propinfo.read = NULL; 1858 propinfo.write = NULL; 1859 err = ptree_create_prop(&propinfo, (const void *)clname, &cphdl); 1860 if (err != PICL_SUCCESS) { 1861 (void) ptree_destroy_node(pobj->ptree_hdl); 1862 return (err); 1863 } 1864 err = ptree_add_prop(pobj->ptree_hdl, cphdl); 1865 if (err != PICL_SUCCESS) { 1866 (void) ptree_destroy_prop(cphdl); 1867 (void) ptree_destroy_node(pobj->ptree_hdl); 1868 return (err); 1869 } 1870 1871 *nodeh = pobj->ptree_hdl; 1872 return (PICL_SUCCESS); 1873 } 1874 1875 /* 1876 * Destroy a node/subtree freeing up space 1877 * Removed destroyed objects' handles from PTree table 1878 */ 1879 static void 1880 destroy_subtree(picl_obj_t *nodep) 1881 { 1882 picl_obj_t *iterp; 1883 picl_obj_t *freep; 1884 picl_obj_t *chdp; 1885 1886 if (nodep == NULL) 1887 return; 1888 1889 chdp = nodep->child_node; 1890 while (chdp != NULL) { 1891 freep = chdp; 1892 chdp = chdp->sibling_node; 1893 destroy_subtree(freep); 1894 } 1895 1896 /* 1897 * Lock the node 1898 */ 1899 (void) lock_obj(WRLOCK_NODE, nodep); 1900 1901 /* 1902 * destroy all properties associated with this node 1903 */ 1904 iterp = nodep->first_prop; 1905 while (iterp != NULL) { 1906 freep = iterp; 1907 iterp = iterp->next_prop; 1908 destroy_propobj(freep); 1909 } 1910 1911 (void) hash_remove(&ptreetbl, nodep->ptree_hdl); 1912 (void) rwlock_destroy(&nodep->node_lock); 1913 free(nodep->node_classname); 1914 free(nodep); 1915 } 1916 1917 /* 1918 * This function destroys a previously deleted node/subtree. All the properties 1919 * are freed and removed from the PTree table. 1920 * Only one destroy is in progress at any time. 1921 */ 1922 int 1923 ptree_destroy_node(picl_nodehdl_t nodeh) 1924 { 1925 picl_obj_t *nodep; 1926 picl_obj_t *parp; 1927 picl_obj_t *np; 1928 int err; 1929 1930 (void) rw_wrlock(&ptree_rwlock); /* exclusive wrlock ptree */ 1931 nodep = NULL; 1932 err = lookup_verify_node_handle(nodeh, &nodep); 1933 if (err != PICL_SUCCESS) { 1934 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 1935 return (err); 1936 } 1937 1938 /* 1939 * Has this node/subtree been deleted? 1940 */ 1941 if (IS_PICLIZED(nodep)) { 1942 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 1943 return (PICL_CANTDESTROY); 1944 } 1945 1946 /* 1947 * update parent's child list to repair the tree when 1948 * parent is not null 1949 */ 1950 parp = nodep->parent_node; 1951 if (parp == NULL) { /* root */ 1952 destroy_subtree(nodep); 1953 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 1954 return (PICL_SUCCESS); 1955 } 1956 1957 np = parp->child_node; 1958 if (np == nodep) { /* first child */ 1959 parp->child_node = nodep->sibling_node; 1960 } else { 1961 while ((np != NULL) && (np->sibling_node != nodep)) 1962 np = np->sibling_node; 1963 if (np != NULL) 1964 np->sibling_node = nodep->sibling_node; 1965 } 1966 1967 destroy_subtree(nodep); 1968 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 1969 return (PICL_SUCCESS); 1970 } 1971 1972 /* 1973 * This function deletes a node/subtree from the tree and removes the handles 1974 * from PICL table 1975 */ 1976 int 1977 ptree_delete_node(picl_nodehdl_t nodeh) 1978 { 1979 picl_obj_t *nodep; 1980 picl_obj_t *parp; 1981 picl_obj_t *np; 1982 int err; 1983 1984 (void) rw_wrlock(&ptree_rwlock); /* exclusive wrlock ptree */ 1985 1986 nodep = NULL; 1987 err = lookup_verify_node_handle(nodeh, &nodep); 1988 if (err != PICL_SUCCESS) { 1989 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 1990 return (err); 1991 } 1992 1993 /* 1994 * unparent it 1995 */ 1996 parp = nodep->parent_node; 1997 if (parp != NULL) { 1998 np = parp->child_node; 1999 if (np == nodep) /* first child */ 2000 parp->child_node = nodep->sibling_node; 2001 else { 2002 while ((np != NULL) && (np->sibling_node != nodep)) 2003 np = np->sibling_node; 2004 if (np != NULL) 2005 np->sibling_node = nodep->sibling_node; 2006 } 2007 } 2008 2009 nodep->parent_node = NULL; 2010 nodep->sibling_node = NULL; 2011 2012 unpiclize_node(nodep); 2013 2014 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2015 return (PICL_SUCCESS); 2016 } 2017 2018 /* 2019 * This function adds a node as a child of another node 2020 */ 2021 int 2022 ptree_add_node(picl_nodehdl_t parh, picl_nodehdl_t chdh) 2023 { 2024 picl_obj_t *pnodep; 2025 picl_obj_t *cnodep; 2026 picl_obj_t *nodep; 2027 int err; 2028 2029 (void) rw_wrlock(&ptree_rwlock); /* exclusive lock ptree */ 2030 2031 pnodep = cnodep = NULL; 2032 err = lookup_verify_node_handle(parh, &pnodep); 2033 if (err != PICL_SUCCESS) { 2034 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2035 return (err); 2036 } 2037 2038 err = lookup_verify_node_handle(chdh, &cnodep); 2039 if (err != PICL_SUCCESS) { 2040 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2041 return (err); 2042 } 2043 2044 /* is chdh already a child? */ 2045 if (cnodep->parent_node != NULL) { 2046 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2047 return (PICL_CANTPARENT); 2048 } 2049 2050 /* 2051 * append child to children list 2052 */ 2053 cnodep->parent_node = pnodep; 2054 if (pnodep->child_node == NULL) 2055 pnodep->child_node = cnodep; 2056 else { 2057 for (nodep = pnodep->child_node; nodep->sibling_node != NULL; 2058 nodep = nodep->sibling_node) 2059 continue; 2060 nodep->sibling_node = cnodep; 2061 2062 } 2063 2064 /* piclize */ 2065 if (IS_PICLIZED(pnodep)) 2066 piclize_node(cnodep); 2067 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2068 return (PICL_SUCCESS); 2069 } 2070 2071 static void 2072 copy_propinfo_ver_1(ptree_propinfo_t *pinfo, picl_obj_t *propp) 2073 { 2074 pinfo->version = propp->pinfo_ver; 2075 pinfo->piclinfo.type = propp->prop_type; 2076 pinfo->piclinfo.accessmode = propp->prop_mode; 2077 pinfo->piclinfo.size = propp->prop_size; 2078 (void) strcpy(pinfo->piclinfo.name, propp->prop_name); 2079 pinfo->read = propp->read_func; 2080 pinfo->write = propp->write_func; 2081 } 2082 2083 static void 2084 copy_reserved_propinfo_ver_1(ptree_propinfo_t *pinfo, const char *pname) 2085 { 2086 pinfo->version = PTREE_PROPINFO_VERSION_1; 2087 pinfo->piclinfo.type = PICL_PTYPE_REFERENCE; 2088 pinfo->piclinfo.accessmode = PICL_READ; 2089 pinfo->piclinfo.size = sizeof (picl_nodehdl_t); 2090 (void) strcpy(pinfo->piclinfo.name, pname); 2091 pinfo->read = NULL; 2092 pinfo->write = NULL; 2093 } 2094 2095 /* 2096 * This function returns the property information to a plug-in 2097 */ 2098 int 2099 ptree_get_propinfo(picl_prophdl_t proph, ptree_propinfo_t *pinfo) 2100 { 2101 int err; 2102 picl_obj_t *nodep; 2103 picl_obj_t *propp; 2104 2105 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */ 2106 nodep = propp = NULL; 2107 err = lookup_and_lock_propnode(RDLOCK_NODE, proph, &nodep, &propp); 2108 if (err != PICL_SUCCESS) { 2109 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2110 return (err); 2111 } 2112 2113 if (propp->pinfo_ver == PTREE_PROPINFO_VERSION_1) 2114 copy_propinfo_ver_1(pinfo, propp); 2115 else 2116 err = PICL_FAILURE; 2117 2118 unlock_node(nodep); /* unlock node */ 2119 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2120 return (err); 2121 } 2122 2123 /* 2124 * This function returns the property information to a plug-in 2125 */ 2126 int 2127 xptree_get_propinfo_by_name(picl_nodehdl_t nodeh, const char *pname, 2128 ptree_propinfo_t *pinfo) 2129 { 2130 int err; 2131 picl_obj_t *nodep; 2132 picl_obj_t *propp; 2133 2134 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */ 2135 nodep = propp = NULL; 2136 err = lookup_and_lock_node(RDLOCK_NODE, nodeh, &nodep); /* lock node */ 2137 if (err != PICL_SUCCESS) { 2138 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2139 return (err); 2140 } 2141 2142 err = lookup_prop_by_name(nodep, pname, &propp); 2143 if (err != PICL_SUCCESS) { 2144 unlock_node(nodep); 2145 (void) rw_unlock(&ptree_rwlock); 2146 return (err); 2147 } 2148 2149 if (picl_restricted(pname)) 2150 copy_reserved_propinfo_ver_1(pinfo, pname); 2151 else if (propp->pinfo_ver == PTREE_PROPINFO_VERSION_1) 2152 copy_propinfo_ver_1(pinfo, propp); 2153 else 2154 err = PICL_FAILURE; 2155 2156 unlock_node(nodep); /* unlock node */ 2157 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2158 return (err); 2159 } 2160 2161 /* 2162 * This function must be called only after a lookup_prop_by_name() returns 2163 * success and only if picl_restricted() returns true. 2164 */ 2165 static int 2166 read_reserved_propval_and_unlock(picl_obj_t *nodep, const char *pname, 2167 void *vbuf, size_t size) 2168 { 2169 void *srcp; 2170 2171 if (size != sizeof (picl_nodehdl_t)) 2172 return (PICL_VALUETOOBIG); 2173 2174 if (strcmp(pname, PICL_PROP_PARENT) == 0) 2175 srcp = &nodep->parent_node->ptree_hdl; 2176 else if (strcmp(pname, PICL_PROP_CHILD) == 0) 2177 srcp = &nodep->child_node->ptree_hdl; 2178 else if (strcmp(pname, PICL_PROP_PEER) == 0) 2179 srcp = &nodep->sibling_node->ptree_hdl; 2180 else 2181 return (PICL_FAILURE); 2182 2183 (void) memcpy(vbuf, srcp, sizeof (picl_nodehdl_t)); 2184 unlock_node(nodep); 2185 (void) rw_unlock(&ptree_rwlock); 2186 return (PICL_SUCCESS); 2187 } 2188 2189 /* 2190 * Returns the property value in the buffer and releases the node and 2191 * ptree locks. 2192 * For volatile properties, this function releases the locks on ptree 2193 * table and the node before calling the plug-in provided access function 2194 */ 2195 static int 2196 read_propval_and_unlock(picl_obj_t *nodep, picl_obj_t *propp, void *vbuf, 2197 door_cred_t cred) 2198 { 2199 int err; 2200 int (*volrd)(ptree_rarg_t *arg, void *buf); 2201 2202 err = PICL_SUCCESS; 2203 if (propp->prop_mode & PICL_VOLATILE) { 2204 ptree_rarg_t rarg; 2205 2206 if (nodep) 2207 rarg.nodeh = nodep->ptree_hdl; 2208 else 2209 rarg.nodeh = PICL_INVALID_PICLHDL; 2210 rarg.proph = propp->ptree_hdl; 2211 rarg.cred = cred; 2212 volrd = propp->read_func; 2213 2214 unlock_node(nodep); /* unlock node */ 2215 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2216 2217 if (volrd == NULL) 2218 err = PICL_FAILURE; 2219 else 2220 err = (volrd)(&rarg, vbuf); 2221 return (err); 2222 } else if (propp->prop_type == PICL_PTYPE_CHARSTRING) 2223 (void) strlcpy(vbuf, propp->prop_val, propp->prop_size); 2224 else 2225 (void) memcpy(vbuf, propp->prop_val, propp->prop_size); 2226 2227 unlock_node(nodep); 2228 (void) rw_unlock(&ptree_rwlock); 2229 return (err); 2230 } 2231 2232 int 2233 xptree_get_propval_with_cred(picl_prophdl_t proph, void *vbuf, size_t size, 2234 door_cred_t cred) 2235 { 2236 picl_obj_t *propp; 2237 picl_obj_t *nodep; 2238 int err; 2239 2240 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */ 2241 nodep = propp = NULL; 2242 err = lookup_and_lock_propnode(RDLOCK_NODE, proph, &nodep, &propp); 2243 if (err != PICL_SUCCESS) { 2244 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2245 return (err); 2246 } 2247 2248 err = check_propsize(PROP_READ, propp, size); 2249 if (err != PICL_SUCCESS) { 2250 unlock_node(nodep); /* unlock node */ 2251 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2252 return (err); 2253 } 2254 2255 return (read_propval_and_unlock(nodep, propp, vbuf, cred)); 2256 } 2257 2258 /* 2259 * This function gets the credentials and calls get_propval_with_cred. 2260 */ 2261 int 2262 ptree_get_propval(picl_prophdl_t proph, void *vbuf, size_t size) 2263 { 2264 return (xptree_get_propval_with_cred(proph, vbuf, size, picld_cred)); 2265 } 2266 2267 /* 2268 * This function retrieves a property's value by by its name 2269 * For volatile properties, the locks on ptree and node are released 2270 * before calling the plug-in provided access function 2271 */ 2272 int 2273 xptree_get_propval_by_name_with_cred(picl_nodehdl_t nodeh, const char *pname, 2274 void *vbuf, size_t size, door_cred_t cred) 2275 { 2276 picl_obj_t *nodep; 2277 picl_obj_t *propp; 2278 int err; 2279 2280 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */ 2281 2282 nodep = NULL; 2283 err = lookup_and_lock_node(RDLOCK_NODE, nodeh, &nodep); /* lock node */ 2284 if (err != PICL_SUCCESS) { 2285 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2286 return (err); 2287 } 2288 2289 err = lookup_prop_by_name(nodep, pname, &propp); 2290 if (err != PICL_SUCCESS) { 2291 unlock_node(nodep); 2292 (void) rw_unlock(&ptree_rwlock); 2293 return (err); 2294 } 2295 2296 if (picl_restricted(pname)) 2297 return (read_reserved_propval_and_unlock(nodep, pname, vbuf, 2298 size)); 2299 2300 err = check_propsize(PROP_READ, propp, size); 2301 if (err != PICL_SUCCESS) { 2302 unlock_node(nodep); 2303 (void) rw_unlock(&ptree_rwlock); 2304 return (err); 2305 } 2306 2307 return (read_propval_and_unlock(nodep, propp, vbuf, cred)); 2308 } 2309 2310 /* 2311 * This function is used by plugins to get a value of a property 2312 * looking it up by its name. 2313 */ 2314 int 2315 ptree_get_propval_by_name(picl_nodehdl_t nodeh, const char *pname, void *vbuf, 2316 size_t size) 2317 { 2318 return (xptree_get_propval_by_name_with_cred(nodeh, pname, vbuf, size, 2319 picld_cred)); 2320 } 2321 2322 /* 2323 * This function updates a property's value. 2324 * For volatile properties, the locks on the node and the ptree table 2325 * are released before calling the plug-in provided access function. 2326 */ 2327 static int 2328 write_propval_and_unlock(picl_obj_t *nodep, picl_obj_t *propp, const void *vbuf, 2329 size_t size, door_cred_t cred) 2330 { 2331 int err; 2332 int (*volwr)(ptree_warg_t *arg, const void *buf); 2333 2334 err = PICL_SUCCESS; 2335 if (propp->prop_mode & PICL_VOLATILE) { 2336 ptree_warg_t warg; 2337 2338 if (nodep) 2339 warg.nodeh = nodep->ptree_hdl; 2340 else 2341 warg.nodeh = PICL_INVALID_PICLHDL; 2342 warg.proph = propp->ptree_hdl; 2343 warg.cred = cred; 2344 volwr = propp->write_func; 2345 2346 unlock_node(nodep); /* unlock node */ 2347 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2348 2349 if (volwr == NULL) 2350 err = PICL_FAILURE; 2351 else 2352 err = (volwr)(&warg, vbuf); 2353 return (err); 2354 } else 2355 (void) memcpy(propp->prop_val, vbuf, size); 2356 2357 unlock_node(nodep); /* unlock node */ 2358 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2359 return (err); 2360 } 2361 2362 int 2363 xptree_update_propval_with_cred(picl_prophdl_t proph, const void *vbuf, 2364 size_t size, door_cred_t cred) 2365 { 2366 picl_obj_t *nodep; 2367 picl_obj_t *propp; 2368 int err; 2369 2370 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */ 2371 nodep = propp = NULL; 2372 err = lookup_and_lock_propnode(WRLOCK_NODE, proph, &nodep, &propp); 2373 if (err != PICL_SUCCESS) { 2374 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2375 return (err); 2376 } 2377 2378 err = check_propsize(PROP_WRITE, propp, size); 2379 if (err != PICL_SUCCESS) { 2380 unlock_node(nodep); /* unlock node */ 2381 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2382 return (err); 2383 } 2384 2385 return (write_propval_and_unlock(nodep, propp, vbuf, size, cred)); 2386 } 2387 2388 /* 2389 * Ptree function used by plug-ins to update a property's value 2390 * calls update_propval_with_cred(), which releases locks for volatile props 2391 */ 2392 int 2393 ptree_update_propval(picl_prophdl_t proph, const void *vbuf, size_t size) 2394 { 2395 return (xptree_update_propval_with_cred(proph, vbuf, size, picld_cred)); 2396 } 2397 2398 /* 2399 * This function writes/updates a property's value by looking it up 2400 * by its name. 2401 * For volatile properties this function releases the locks on the 2402 * node and the ptree table. 2403 */ 2404 int 2405 xptree_update_propval_by_name_with_cred(picl_nodehdl_t nodeh, const char *pname, 2406 const void *vbuf, size_t size, door_cred_t cred) 2407 { 2408 picl_obj_t *nodep; 2409 picl_obj_t *propp; 2410 int err; 2411 2412 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */ 2413 nodep = NULL; 2414 err = lookup_and_lock_node(WRLOCK_NODE, nodeh, &nodep); /* lock node */ 2415 if (err != PICL_SUCCESS) { 2416 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2417 return (err); 2418 } 2419 2420 if (picl_restricted(pname)) { 2421 unlock_node(nodep); 2422 (void) rw_unlock(&ptree_rwlock); 2423 return (PICL_RESERVEDNAME); 2424 } 2425 2426 err = lookup_prop_by_name(nodep, pname, &propp); 2427 if (err != PICL_SUCCESS) { 2428 unlock_node(nodep); 2429 (void) rw_unlock(&ptree_rwlock); 2430 return (err); 2431 } 2432 2433 err = check_propsize(PROP_WRITE, propp, size); 2434 if (err != PICL_SUCCESS) { 2435 unlock_node(nodep); 2436 (void) rw_unlock(&ptree_rwlock); 2437 return (err); 2438 } 2439 2440 return (write_propval_and_unlock(nodep, propp, vbuf, size, cred)); 2441 } 2442 2443 /* 2444 * This function updates the value of a property specified by its name 2445 */ 2446 int 2447 ptree_update_propval_by_name(picl_nodehdl_t nodeh, const char *pname, 2448 const void *vbuf, size_t size) 2449 { 2450 return (xptree_update_propval_by_name_with_cred(nodeh, pname, vbuf, 2451 size, picld_cred)); 2452 } 2453 2454 /* 2455 * This function retrieves the handle of a property by its name 2456 */ 2457 int 2458 ptree_get_prop_by_name(picl_nodehdl_t nodeh, const char *pname, 2459 picl_prophdl_t *proph) 2460 { 2461 picl_obj_t *nodep; 2462 picl_obj_t *propp; 2463 int err; 2464 2465 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */ 2466 nodep = NULL; 2467 err = lookup_and_lock_node(RDLOCK_NODE, nodeh, &nodep); /* lock node */ 2468 if (err != PICL_SUCCESS) { 2469 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2470 return (err); 2471 } 2472 2473 if (picl_restricted(pname)) { 2474 err = PICL_RESERVEDNAME; 2475 unlock_node(nodep); /* unlock node */ 2476 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2477 return (err); 2478 } 2479 2480 err = lookup_prop_by_name(nodep, pname, &propp); 2481 if (err == PICL_SUCCESS) 2482 *proph = propp->ptree_hdl; 2483 2484 unlock_node(nodep); /* unlock node */ 2485 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2486 return (err); 2487 } 2488 2489 /* 2490 * This function returns the handle of the first property 2491 */ 2492 int 2493 ptree_get_first_prop(picl_nodehdl_t nodeh, picl_prophdl_t *proph) 2494 { 2495 picl_obj_t *pobj; 2496 int err; 2497 2498 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */ 2499 pobj = NULL; 2500 err = lookup_and_lock_node(RDLOCK_NODE, nodeh, &pobj); /* lock node */ 2501 if (err != PICL_SUCCESS) { 2502 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2503 return (err); 2504 } 2505 2506 if (pobj->first_prop) 2507 *proph = pobj->first_prop->ptree_hdl; 2508 else 2509 err = PICL_ENDOFLIST; 2510 2511 unlock_node(pobj); /* unlock node */ 2512 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2513 return (err); 2514 } 2515 2516 /* 2517 * This function returns the handle of next property in the list 2518 */ 2519 int 2520 ptree_get_next_prop(picl_prophdl_t proph, picl_prophdl_t *nextproph) 2521 { 2522 picl_obj_t *nodep; 2523 picl_obj_t *propp; 2524 int err; 2525 2526 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */ 2527 nodep = propp = NULL; 2528 err = lookup_and_lock_propnode(RDLOCK_NODE, proph, &nodep, &propp); 2529 if (err != PICL_SUCCESS) { 2530 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2531 return (err); 2532 } 2533 2534 if (propp->next_prop) { 2535 *nextproph = propp->next_prop->ptree_hdl; 2536 } else 2537 err = PICL_ENDOFLIST; 2538 2539 unlock_node(nodep); /* unlock node */ 2540 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 2541 return (err); 2542 } 2543 2544 /* 2545 * These functions are called by ptree_get_node_by_path() 2546 * Append a prop expression entry to the list 2547 */ 2548 static prop_list_t * 2549 append_entry_to_list(prop_list_t *el, prop_list_t *list) 2550 { 2551 prop_list_t *ptr; 2552 2553 if (el == NULL) 2554 return (list); 2555 2556 if (list == NULL) { 2557 list = el; 2558 return (list); 2559 } 2560 2561 /* 2562 * Add it to the end of list 2563 */ 2564 ptr = list; 2565 2566 while (ptr->next != NULL) 2567 ptr = ptr->next; 2568 2569 ptr->next = el; 2570 2571 return (list); 2572 } 2573 2574 /* 2575 * Free the property expression list 2576 */ 2577 static void 2578 free_list(prop_list_t *list) 2579 { 2580 prop_list_t *ptr; 2581 prop_list_t *tmp; 2582 2583 for (ptr = list; ptr != NULL; ptr = tmp) { 2584 tmp = ptr->next; 2585 free(ptr); 2586 } 2587 } 2588 2589 static int 2590 parse_prl(char *prl, char **name, char **baddr, prop_list_t **plist) 2591 { 2592 char *propptr; 2593 char *ptr; 2594 char *pname; 2595 char *pval; 2596 prop_list_t *el; 2597 2598 if (prl == NULL) 2599 return (PICL_FAILURE); 2600 2601 if ((prl[0] == '@') || (prl[0] == '?')) 2602 return (PICL_FAILURE); 2603 2604 *name = prl; 2605 2606 /* 2607 * get property expression 2608 */ 2609 ptr = strchr(prl, '?'); 2610 2611 if (ptr != NULL) { 2612 *ptr = '\0'; 2613 propptr = ptr + 1; 2614 } else 2615 propptr = NULL; 2616 2617 /* 2618 * get bus value 2619 */ 2620 ptr = strchr(prl, '@'); 2621 2622 if (ptr != NULL) { 2623 *ptr = '\0'; 2624 *baddr = ptr + 1; 2625 if (strlen(*baddr) == 0) /* no bus value after @ */ 2626 return (PICL_FAILURE); 2627 } 2628 2629 /* 2630 * create the prop list 2631 */ 2632 while (propptr != NULL) { 2633 pname = propptr; 2634 pval = NULL; 2635 2636 ptr = strchr(propptr, '?'); 2637 2638 if (ptr != NULL) { /* more ?<prop>=<propval> */ 2639 *ptr = '\0'; 2640 propptr = ptr + 1; 2641 } else 2642 propptr = NULL; 2643 2644 if (strlen(pname) == 0) /* no prop exp after ? */ 2645 return (PICL_FAILURE); 2646 2647 ptr = strchr(pname, '='); 2648 if (ptr != NULL) { /* not void prop */ 2649 *ptr = '\0'; 2650 pval = ptr + 1; 2651 /* 2652 * <prop>= is treated as void property 2653 */ 2654 if (strlen(pval) == 0) 2655 pval = NULL; 2656 } 2657 2658 el = (prop_list_t *)malloc(sizeof (prop_list_t)); 2659 el->pname = pname; 2660 el->pval = pval; 2661 el->next = NULL; 2662 *plist = append_entry_to_list(el, *plist); 2663 } 2664 2665 return (PICL_SUCCESS); 2666 } 2667 2668 static int 2669 prop_match(ptree_propinfo_t pinfo, void *vbuf, char *val) 2670 { 2671 int8_t cval; 2672 uint8_t ucval; 2673 int16_t sval; 2674 uint16_t usval; 2675 int32_t intval; 2676 uint32_t uintval; 2677 int64_t llval; 2678 uint64_t ullval; 2679 float fval; 2680 double dval; 2681 2682 switch (pinfo.piclinfo.type) { 2683 case PICL_PTYPE_CHARSTRING: 2684 if (strcasecmp(pinfo.piclinfo.name, PICL_PROP_CLASSNAME) == 0) { 2685 if (strcmp(val, PICL_CLASS_PICL) == 0) 2686 return (1); 2687 } 2688 if (strcmp(val, (char *)vbuf) == 0) 2689 return (1); 2690 else 2691 return (0); 2692 case PICL_PTYPE_INT: 2693 switch (pinfo.piclinfo.size) { 2694 case sizeof (int8_t): 2695 cval = (int8_t)strtol(val, (char **)NULL, 0); 2696 return (cval == *(char *)vbuf); 2697 case sizeof (int16_t): 2698 sval = (int16_t)strtol(val, (char **)NULL, 0); 2699 return (sval == *(int16_t *)vbuf); 2700 case sizeof (int32_t): 2701 intval = (int32_t)strtol(val, (char **)NULL, 0); 2702 return (intval == *(int32_t *)vbuf); 2703 case sizeof (int64_t): 2704 llval = strtoll(val, (char **)NULL, 0); 2705 return (llval == *(int64_t *)vbuf); 2706 default: 2707 return (0); 2708 } 2709 case PICL_PTYPE_UNSIGNED_INT: 2710 switch (pinfo.piclinfo.size) { 2711 case sizeof (uint8_t): 2712 ucval = (uint8_t)strtoul(val, (char **)NULL, 0); 2713 return (ucval == *(uint8_t *)vbuf); 2714 case sizeof (uint16_t): 2715 usval = (uint16_t)strtoul(val, (char **)NULL, 0); 2716 return (usval == *(uint16_t *)vbuf); 2717 case sizeof (uint32_t): 2718 uintval = (uint32_t)strtoul(val, (char **)NULL, 0); 2719 return (uintval == *(uint32_t *)vbuf); 2720 case sizeof (uint64_t): 2721 ullval = strtoull(val, (char **)NULL, 0); 2722 return (ullval == *(uint64_t *)vbuf); 2723 default: 2724 return (0); 2725 } 2726 case PICL_PTYPE_FLOAT: 2727 switch (pinfo.piclinfo.size) { 2728 case sizeof (float): 2729 fval = (float)strtod(val, (char **)NULL); 2730 return (fval == *(float *)vbuf); 2731 case sizeof (double): 2732 dval = strtod(val, (char **)NULL); 2733 return (dval == *(double *)vbuf); 2734 default: 2735 return (0); 2736 } 2737 case PICL_PTYPE_VOID: 2738 case PICL_PTYPE_TIMESTAMP: 2739 case PICL_PTYPE_TABLE: 2740 case PICL_PTYPE_REFERENCE: 2741 case PICL_PTYPE_BYTEARRAY: 2742 case PICL_PTYPE_UNKNOWN: 2743 default: 2744 return (0); 2745 } 2746 } 2747 2748 static int 2749 check_propval(picl_nodehdl_t nodeh, char *pname, char *pval) 2750 { 2751 int err; 2752 picl_prophdl_t proph; 2753 ptree_propinfo_t pinfo; 2754 void *vbuf; 2755 2756 err = ptree_get_prop_by_name(nodeh, pname, &proph); 2757 if (err != PICL_SUCCESS) 2758 return (err); 2759 2760 err = ptree_get_propinfo(proph, &pinfo); 2761 if (err != PICL_SUCCESS) 2762 return (err); 2763 2764 if (pval == NULL) { /* void type */ 2765 if (pinfo.piclinfo.type != PICL_PTYPE_VOID) 2766 return (PICL_FAILURE); 2767 } else { 2768 vbuf = alloca(pinfo.piclinfo.size); 2769 if (vbuf == NULL) 2770 return (PICL_FAILURE); 2771 err = ptree_get_propval(proph, vbuf, 2772 pinfo.piclinfo.size); 2773 if (err != PICL_SUCCESS) 2774 return (err); 2775 2776 if (!prop_match(pinfo, vbuf, pval)) 2777 return (PICL_FAILURE); 2778 } 2779 return (PICL_SUCCESS); 2780 } 2781 2782 static int 2783 get_child_by_path(picl_nodehdl_t rooth, char *prl, 2784 picl_nodehdl_t *nodeh, char *pname) 2785 { 2786 picl_nodehdl_t chdh; 2787 int err; 2788 char *nameval; 2789 char *nodename; 2790 char *path; 2791 char *baddr; 2792 char *busval; 2793 prop_list_t *plist; 2794 prop_list_t *ptr; 2795 2796 if (prl == NULL) 2797 return (PICL_FAILURE); 2798 2799 path = alloca(strlen(prl) + 1); 2800 if (path == NULL) 2801 return (PICL_FAILURE); 2802 2803 (void) strcpy(path, prl); 2804 2805 plist = NULL; 2806 nodename = NULL; 2807 baddr = NULL; 2808 2809 err = parse_prl(path, &nodename, &baddr, &plist); 2810 if (err != PICL_SUCCESS) { 2811 free_list(plist); 2812 return (err); 2813 } 2814 2815 if (nodename == NULL) 2816 return (PICL_FAILURE); 2817 2818 nameval = alloca(strlen(nodename) + 1); 2819 if (nameval == NULL) { 2820 free_list(plist); 2821 return (PICL_FAILURE); 2822 } 2823 2824 if (baddr != NULL) { 2825 busval = alloca(strlen(baddr) + 1); 2826 if (busval == NULL) { 2827 free_list(plist); 2828 return (PICL_FAILURE); 2829 } 2830 } 2831 2832 for (err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh, 2833 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND; 2834 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh, 2835 sizeof (picl_nodehdl_t))) { 2836 if (err != PICL_SUCCESS) { 2837 free_list(plist); 2838 return (PICL_FAILURE); 2839 } 2840 2841 /* 2842 * compare name 2843 */ 2844 if ((strcmp(pname, PICL_PROP_CLASSNAME) != 0) || 2845 (strcmp(nodename, PICL_CLASS_PICL) != 0)) { 2846 err = ptree_get_propval_by_name(chdh, pname, 2847 nameval, (strlen(nodename) + 1)); 2848 2849 if (err != PICL_SUCCESS) 2850 continue; 2851 if (strcmp(nameval, nodename) != 0) 2852 continue; 2853 } 2854 2855 /* 2856 * compare device address with bus-addr prop first 2857 * then with UnitAddress property 2858 */ 2859 if (baddr != NULL) { /* compare bus-addr prop */ 2860 if ((ptree_get_propval_by_name(chdh, PICL_PROP_BUS_ADDR, 2861 busval, (strlen(baddr) + 1)) != PICL_SUCCESS) && 2862 (ptree_get_propval_by_name(chdh, 2863 PICL_PROP_UNIT_ADDRESS, busval, 2864 (strlen(baddr) + 1)) != PICL_SUCCESS)) 2865 continue; 2866 2867 if (strcmp(busval, baddr) != 0) 2868 continue; /* not match */ 2869 } 2870 2871 if (plist == NULL) { /* no prop expression */ 2872 *nodeh = chdh; 2873 return (PICL_SUCCESS); 2874 } 2875 2876 /* 2877 * compare the property expression list 2878 */ 2879 ptr = plist; 2880 2881 while (ptr != NULL) { 2882 err = check_propval(chdh, ptr->pname, ptr->pval); 2883 if (err != PICL_SUCCESS) 2884 break; 2885 2886 ptr = ptr->next; 2887 } 2888 if (ptr == NULL) { 2889 *nodeh = chdh; 2890 free_list(plist); 2891 return (PICL_SUCCESS); 2892 } 2893 } 2894 free_list(plist); 2895 return (PICL_NOTNODE); 2896 } 2897 2898 /* 2899 * This functions returns the handle of node specified by its path 2900 */ 2901 int 2902 ptree_get_node_by_path(const char *piclprl, picl_nodehdl_t *handle) 2903 { 2904 picl_nodehdl_t rooth; 2905 picl_nodehdl_t chdh; 2906 char *path; 2907 char *ptr; 2908 char *defprop; 2909 char *tokindex; 2910 int err; 2911 int len; 2912 int npflg; /* namepath flag */ 2913 2914 2915 path = alloca(strlen(piclprl) + 1); 2916 if (path == NULL) 2917 return (PICL_FAILURE); 2918 (void) strcpy(path, piclprl); 2919 2920 npflg = 1; /* default */ 2921 defprop = path; 2922 if (path[0] == '/') { 2923 ptr = &path[1]; 2924 } else if ((tokindex = strchr(path, ':')) != NULL) { 2925 *tokindex = '\0'; 2926 ++tokindex; 2927 if (*tokindex == '/') 2928 ptr = tokindex + 1; 2929 else 2930 return (PICL_NOTNODE); 2931 npflg = 0; 2932 } else 2933 return (PICL_NOTNODE); 2934 2935 err = ptree_get_root(&rooth); 2936 if (err != PICL_SUCCESS) 2937 return (err); 2938 2939 for (chdh = rooth, tokindex = strchr(ptr, '/'); 2940 tokindex != NULL; 2941 ptr = tokindex + 1, tokindex = strchr(ptr, '/')) { 2942 *tokindex = '\0'; 2943 if (npflg) 2944 err = get_child_by_path(chdh, ptr, &chdh, 2945 PICL_PROP_NAME); 2946 else 2947 err = get_child_by_path(chdh, ptr, &chdh, 2948 defprop); 2949 2950 if (err != PICL_SUCCESS) 2951 return (err); 2952 } 2953 2954 /* 2955 * check if last token is empty or not 2956 * eg. /a/b/c/ or /a/b/c 2957 */ 2958 if (*ptr == '\0') { 2959 *handle = chdh; 2960 return (PICL_SUCCESS); 2961 } 2962 2963 len = strcspn(ptr, " \t\n"); 2964 if (len == 0) { 2965 *handle = chdh; 2966 return (PICL_SUCCESS); 2967 } 2968 2969 ptr[len] = '\0'; 2970 if (npflg) 2971 err = get_child_by_path(chdh, ptr, &chdh, PICL_PROP_NAME); 2972 else 2973 err = get_child_by_path(chdh, ptr, &chdh, defprop); 2974 2975 if (err != PICL_SUCCESS) 2976 return (err); 2977 2978 *handle = chdh; 2979 return (PICL_SUCCESS); 2980 } 2981 2982 /* 2983 * Initialize propinfo 2984 */ 2985 int 2986 ptree_init_propinfo(ptree_propinfo_t *infop, int version, int ptype, int pmode, 2987 size_t psize, char *pname, int (*readfn)(ptree_rarg_t *, void *), 2988 int (*writefn)(ptree_warg_t *, const void *)) 2989 { 2990 if (version != PTREE_PROPINFO_VERSION_1) 2991 return (PICL_NOTSUPPORTED); 2992 if ((infop == NULL) || (pname == NULL)) 2993 return (PICL_INVALIDARG); 2994 infop->version = version; 2995 infop->piclinfo.type = ptype; 2996 infop->piclinfo.accessmode = pmode; 2997 infop->piclinfo.size = psize; 2998 infop->read = readfn; 2999 infop->write = writefn; 3000 (void) strlcpy(infop->piclinfo.name, pname, PICL_PROPNAMELEN_MAX); 3001 return (PICL_SUCCESS); 3002 } 3003 3004 /* 3005 * Creates a property, adds it to the node, and returns the property 3006 * handle to the caller if successful and proph is not NULL 3007 */ 3008 int 3009 ptree_create_and_add_prop(picl_nodehdl_t nodeh, ptree_propinfo_t *infop, 3010 void *vbuf, picl_prophdl_t *proph) 3011 { 3012 int err; 3013 picl_prophdl_t tmph; 3014 3015 err = ptree_create_prop(infop, vbuf, &tmph); 3016 if (err != PICL_SUCCESS) 3017 return (err); 3018 err = ptree_add_prop(nodeh, tmph); 3019 if (err != PICL_SUCCESS) { 3020 (void) ptree_destroy_prop(tmph); 3021 return (err); 3022 } 3023 if (proph) 3024 *proph = tmph; 3025 return (PICL_SUCCESS); 3026 } 3027 3028 /* 3029 * Creates a node, adds it to its parent node, and returns the node 3030 * handle to the caller if successful 3031 */ 3032 int 3033 ptree_create_and_add_node(picl_nodehdl_t rooth, const char *name, 3034 const char *classname, picl_nodehdl_t *nodeh) 3035 { 3036 picl_nodehdl_t tmph; 3037 int err; 3038 3039 err = ptree_create_node(name, classname, &tmph); 3040 3041 if (err != PICL_SUCCESS) 3042 return (err); 3043 3044 err = ptree_add_node(rooth, tmph); 3045 if (err != PICL_SUCCESS) { 3046 (void) ptree_destroy_node(tmph); 3047 return (err); 3048 } 3049 3050 *nodeh = tmph; 3051 return (PICL_SUCCESS); 3052 } 3053 3054 3055 /* 3056 * recursively visit all nodes 3057 */ 3058 static int 3059 do_walk(picl_nodehdl_t rooth, const char *classname, 3060 void *c_args, int (*callback_fn)(picl_nodehdl_t hdl, void *args)) 3061 { 3062 int err; 3063 picl_nodehdl_t chdh; 3064 char classval[PICL_CLASSNAMELEN_MAX]; 3065 3066 err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh, 3067 sizeof (chdh)); 3068 while (err == PICL_SUCCESS) { 3069 err = ptree_get_propval_by_name(chdh, PICL_PROP_CLASSNAME, 3070 classval, sizeof (classval)); 3071 if (err != PICL_SUCCESS) 3072 return (err); 3073 3074 if ((classname == NULL) || (strcmp(classname, classval) == 0)) { 3075 err = callback_fn(chdh, c_args); 3076 if (err != PICL_WALK_CONTINUE) 3077 return (err); 3078 } 3079 3080 if ((err = do_walk(chdh, classname, c_args, callback_fn)) != 3081 PICL_WALK_CONTINUE) 3082 return (err); 3083 3084 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh, 3085 sizeof (chdh)); 3086 } 3087 if (err == PICL_PROPNOTFOUND) /* end of a branch */ 3088 return (PICL_WALK_CONTINUE); 3089 return (err); 3090 3091 } 3092 3093 /* 3094 * This function visits all the nodes in the subtree rooted at <rooth>. 3095 * For each node that matches the class name specified, the callback 3096 * function is invoked. 3097 */ 3098 int 3099 ptree_walk_tree_by_class(picl_nodehdl_t rooth, const char *classname, 3100 void *c_args, int (*callback_fn)(picl_nodehdl_t hdl, void *args)) 3101 { 3102 int err; 3103 3104 if (callback_fn == NULL) 3105 return (PICL_INVALIDARG); 3106 err = do_walk(rooth, classname, c_args, callback_fn); 3107 if ((err == PICL_WALK_CONTINUE) || (err == PICL_WALK_TERMINATE)) 3108 return (PICL_SUCCESS); 3109 return (err); 3110 } 3111 3112 static int 3113 compare_propval(picl_nodehdl_t nodeh, char *pname, picl_prop_type_t ptype, 3114 void *pval, size_t valsize) 3115 { 3116 int err; 3117 picl_prophdl_t proph; 3118 ptree_propinfo_t propinfo; 3119 void *vbuf; 3120 3121 err = ptree_get_prop_by_name(nodeh, pname, &proph); 3122 if (err != PICL_SUCCESS) 3123 return (0); 3124 err = ptree_get_propinfo(proph, &propinfo); 3125 if (err != PICL_SUCCESS) 3126 return (0); 3127 if (propinfo.piclinfo.type != ptype) 3128 return (0); 3129 if (propinfo.piclinfo.type == PICL_PTYPE_VOID) 3130 return (1); 3131 if (pval == NULL) 3132 return (0); 3133 if (valsize > propinfo.piclinfo.size) 3134 return (0); 3135 vbuf = alloca(propinfo.piclinfo.size); 3136 if (vbuf == NULL) 3137 return (0); 3138 err = ptree_get_propval(proph, vbuf, propinfo.piclinfo.size); 3139 if (err != PICL_SUCCESS) 3140 return (0); 3141 if (memcmp(vbuf, pval, valsize) == 0) 3142 return (1); 3143 return (0); 3144 } 3145 3146 3147 /* 3148 * This function traverses the subtree and finds a node that has a property 3149 * of the specified name and type with the specified value. 3150 * The matched node in the tree is returned in retnodeh. If there is 3151 * no node with that property, then PICL_NODENOTFOUND is returned. 3152 */ 3153 int 3154 ptree_find_node(picl_nodehdl_t rooth, char *pname, picl_prop_type_t ptype, 3155 void *pval, size_t valsize, picl_nodehdl_t *retnodeh) 3156 { 3157 int err; 3158 picl_nodehdl_t chdh; 3159 3160 if (pname == NULL) 3161 return (PICL_INVALIDARG); 3162 err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh, 3163 sizeof (chdh)); 3164 3165 while (err == PICL_SUCCESS) { 3166 if (compare_propval(chdh, pname, ptype, pval, valsize)) { 3167 if (retnodeh) 3168 *retnodeh = chdh; 3169 return (PICL_SUCCESS); 3170 } 3171 3172 err = ptree_find_node(chdh, pname, ptype, pval, valsize, 3173 retnodeh); 3174 if (err != PICL_NODENOTFOUND) 3175 return (err); 3176 3177 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh, 3178 sizeof (chdh)); 3179 } 3180 if (err == PICL_PROPNOTFOUND) 3181 return (PICL_NODENOTFOUND); 3182 return (err); 3183 } 3184 3185 /* 3186 * This function gets the frutree parent for a given node. 3187 * Traverse up the tree and look for the following properties: 3188 * Frutree parent reference properties: 3189 * _fru_parent 3190 * _location_parent 3191 * _port_parent 3192 * If the frutree reference property is found, return its value. 3193 * Else, return the handle of /frutree/chassis. 3194 */ 3195 int 3196 ptree_get_frutree_parent(picl_nodehdl_t nodeh, picl_nodehdl_t *fruh) 3197 { 3198 int err; 3199 picl_nodehdl_t nparh; 3200 picl_nodehdl_t fruparh; 3201 3202 err = PICL_SUCCESS; 3203 nparh = nodeh; 3204 while (err == PICL_SUCCESS) { 3205 err = ptree_get_propval_by_name(nparh, PICL_REFPROP_FRU_PARENT, 3206 &fruparh, sizeof (fruparh)); 3207 if (err == PICL_SUCCESS) { 3208 *fruh = fruparh; 3209 return (PICL_SUCCESS); 3210 } 3211 err = ptree_get_propval_by_name(nparh, 3212 PICL_REFPROP_LOC_PARENT, &fruparh, sizeof (fruparh)); 3213 if (err == PICL_SUCCESS) { 3214 *fruh = fruparh; 3215 return (PICL_SUCCESS); 3216 } 3217 err = ptree_get_propval_by_name(nparh, PICL_REFPROP_PORT_PARENT, 3218 &fruparh, sizeof (fruparh)); 3219 if (err == PICL_SUCCESS) { 3220 *fruh = fruparh; 3221 return (PICL_SUCCESS); 3222 } 3223 3224 err = ptree_get_propval_by_name(nparh, PICL_PROP_PARENT, &nparh, 3225 sizeof (nparh)); 3226 } 3227 3228 if (err == PICL_PROPNOTFOUND) { /* return /frutree/chassis handle */ 3229 err = ptree_get_node_by_path(PICL_FRUTREE_CHASSIS, &fruparh); 3230 if (err == PICL_SUCCESS) { 3231 *fruh = fruparh; 3232 return (PICL_SUCCESS); 3233 } 3234 } 3235 return (err); 3236 } 3237 3238 /* 3239 * This function is called by plug-ins to register with the daemon 3240 */ 3241 int 3242 picld_plugin_register(picld_plugin_reg_t *regp) 3243 { 3244 picld_plugin_reg_list_t *el; 3245 picld_plugin_reg_list_t *tmp; 3246 3247 if (regp == NULL) 3248 return (PICL_FAILURE); 3249 3250 if (regp->version != PICLD_PLUGIN_VERSION_1) 3251 return (PICL_NOTSUPPORTED); 3252 3253 el = malloc(sizeof (picld_plugin_reg_list_t)); 3254 if (el == NULL) 3255 return (PICL_FAILURE); 3256 el->reg.version = regp->version; 3257 el->reg.critical = regp->critical; 3258 if (regp->name) 3259 el->reg.name = strdup(regp->name); 3260 if (el->reg.name == NULL) 3261 return (PICL_FAILURE); 3262 3263 el->reg.plugin_init = regp->plugin_init; 3264 el->reg.plugin_fini = regp->plugin_fini; 3265 el->next = NULL; 3266 3267 if (plugin_reg_list == NULL) { 3268 plugin_reg_list = el; 3269 } else { /* add to end */ 3270 tmp = plugin_reg_list; 3271 while (tmp->next != NULL) 3272 tmp = tmp->next; 3273 tmp->next = el; 3274 } 3275 3276 return (PICL_SUCCESS); 3277 } 3278 3279 /* 3280 * Call fini routines of the registered plugins 3281 */ 3282 static void 3283 plugin_fini(picld_plugin_reg_list_t *p) 3284 { 3285 if (p == NULL) 3286 return; 3287 3288 plugin_fini(p->next); 3289 if (p->reg.plugin_fini) 3290 (p->reg.plugin_fini)(); 3291 } 3292 3293 /* 3294 * Create PICL Tree 3295 */ 3296 3297 static void 3298 init_plugin_reg_list(void) 3299 { 3300 plugin_reg_list = NULL; 3301 } 3302 3303 static int 3304 picltree_set_root(picl_nodehdl_t rooth) 3305 { 3306 picl_obj_t *pobj; 3307 int err; 3308 3309 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */ 3310 pobj = NULL; 3311 err = lookup_and_lock_node(RDLOCK_NODE, rooth, &pobj); /* lock node */ 3312 if (err != PICL_SUCCESS) { 3313 (void) rw_unlock(&ptree_rwlock); 3314 return (PICL_FAILURE); 3315 } 3316 piclize_node(pobj); 3317 picl_root_obj = pobj; 3318 ptree_root_hdl = pobj->ptree_hdl; 3319 unlock_node(pobj); /* unlock node */ 3320 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */ 3321 return (PICL_SUCCESS); 3322 } 3323 3324 static int 3325 picltree_init(void) 3326 { 3327 (void) rwlock_init(&ptree_rwlock, USYNC_THREAD, NULL); 3328 (void) rwlock_init(&picltbl_rwlock, USYNC_THREAD, NULL); 3329 3330 if (hash_init(&picltbl) < 0) 3331 return (PICL_FAILURE); 3332 if (hash_init(&ptreetbl) < 0) 3333 return (PICL_FAILURE); 3334 3335 if (pthread_mutex_init(&ptreehdl_lock, NULL) != 0) 3336 return (PICL_FAILURE); 3337 3338 if (pthread_mutex_init(&piclhdl_lock, NULL) != 0) 3339 return (PICL_FAILURE); 3340 3341 if (pthread_mutex_init(&evtq_lock, NULL) != 0) 3342 return (PICL_FAILURE); 3343 if (pthread_cond_init(&evtq_cv, NULL) != 0) 3344 return (PICL_FAILURE); 3345 if (pthread_mutex_init(&evthandler_lock, NULL) != 0) 3346 return (PICL_FAILURE); 3347 3348 picl_root_obj = NULL; 3349 eventqp = NULL; 3350 evt_handlers = NULL; 3351 ptree_root_hdl = PICL_INVALID_PICLHDL; 3352 3353 return (PICL_SUCCESS); 3354 } 3355 3356 static void 3357 add_unique_plugin_to_list(char *path, char *name) 3358 { 3359 char *buf; 3360 picld_plugin_desc_t *pl; 3361 picld_plugin_desc_t *tmp; 3362 3363 pl = plugin_desc; 3364 while (pl != NULL) { 3365 if (strcmp(pl->libname, name) == 0) 3366 return; 3367 else 3368 pl = pl->next; 3369 } 3370 3371 pl = malloc(sizeof (picld_plugin_desc_t)); 3372 if (pl == NULL) 3373 return; 3374 3375 pl->libname = strdup(name); 3376 if (pl->libname == NULL) 3377 return; 3378 buf = alloca(strlen(name) + strlen(path) + 2); 3379 if (buf == NULL) 3380 return; 3381 (void) strcpy(buf, path); 3382 (void) strcat(buf, name); 3383 pl->pathname = strdup(buf); 3384 if (pl->pathname == NULL) 3385 return; 3386 3387 pl->next = NULL; 3388 3389 if (plugin_desc == NULL) 3390 plugin_desc = pl; 3391 else { 3392 tmp = plugin_desc; 3393 while (tmp->next != NULL) 3394 tmp = tmp->next; 3395 tmp->next = pl; 3396 } 3397 } 3398 3399 static void 3400 get_plugins_from_dir(char *dirname) 3401 { 3402 struct dirent *ent; 3403 DIR *dir; 3404 int len; 3405 int solen = strlen(SO_VERS) + 1; 3406 3407 if ((dir = opendir(dirname)) == NULL) 3408 return; 3409 3410 while ((ent = readdir(dir)) != NULL) { 3411 if ((strcmp(ent->d_name, ".") == 0) || 3412 (strcmp(ent->d_name, "..") == 0)) 3413 continue; 3414 3415 len = strlen(ent->d_name) + 1; 3416 if (len < solen) 3417 continue; 3418 3419 if (strcmp(ent->d_name + (len - solen), SO_VERS) == 0) 3420 add_unique_plugin_to_list(dirname, ent->d_name); 3421 } 3422 3423 (void) closedir(dir); 3424 } 3425 3426 3427 static void 3428 init_plugin_list(void) 3429 { 3430 char nmbuf[SYS_NMLN]; 3431 char pname[PATH_MAX]; 3432 3433 plugin_desc = NULL; 3434 if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) { 3435 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf); 3436 if (access(pname, R_OK) == 0) 3437 get_plugins_from_dir(pname); 3438 } 3439 3440 if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) { 3441 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf); 3442 if (access(pname, R_OK) == 0) 3443 get_plugins_from_dir(pname); 3444 } 3445 3446 (void) snprintf(pname, PATH_MAX, "%s/", PICLD_COMMON_PLUGIN_DIR); 3447 if (access(pname, R_OK) == 0) 3448 get_plugins_from_dir(pname); 3449 } 3450 3451 static void 3452 load_plugins(void) 3453 { 3454 picld_plugin_desc_t *pl; 3455 3456 pl = plugin_desc; 3457 while (pl != NULL) { 3458 pl->dlh = dlopen(pl->pathname, RTLD_LAZY|RTLD_LOCAL); 3459 if (pl->dlh == NULL) { 3460 syslog(LOG_CRIT, dlerror()); 3461 return; 3462 } 3463 pl = pl->next; 3464 } 3465 } 3466 3467 3468 3469 static int 3470 add_root_props(picl_nodehdl_t rooth) 3471 { 3472 int err; 3473 picl_prophdl_t proph; 3474 ptree_propinfo_t pinfo; 3475 float picl_vers; 3476 3477 #define PICL_PROP_PICL_VERSION "PICLVersion" 3478 #define PICL_VERSION 1.1 3479 3480 err = ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION_1, 3481 PICL_PTYPE_FLOAT, PICL_READ, sizeof (picl_vers), 3482 PICL_PROP_PICL_VERSION, NULL, NULL); 3483 if (err != PICL_SUCCESS) 3484 return (err); 3485 3486 picl_vers = PICL_VERSION; 3487 err = ptree_create_and_add_prop(rooth, &pinfo, &picl_vers, &proph); 3488 return (err); 3489 } 3490 3491 static int 3492 construct_picltree(void) 3493 { 3494 int err; 3495 picld_plugin_reg_list_t *iter; 3496 picl_nodehdl_t rhdl; 3497 3498 /* 3499 * Create "/" node 3500 */ 3501 if ((err = ptree_create_node(PICL_NODE_ROOT, PICL_CLASS_PICL, 3502 &rhdl)) != PICL_SUCCESS) { 3503 return (err); 3504 } 3505 3506 if (picltree_set_root(rhdl) != PICL_SUCCESS) { 3507 return (PICL_FAILURE); 3508 } 3509 3510 err = add_root_props(rhdl); 3511 if (err != PICL_SUCCESS) 3512 return (err); 3513 3514 /* 3515 * Initialize the registered plug-in modules 3516 */ 3517 iter = plugin_reg_list; 3518 while (iter != NULL) { 3519 if (iter->reg.plugin_init) 3520 (iter->reg.plugin_init)(); 3521 iter = iter->next; 3522 } 3523 return (PICL_SUCCESS); 3524 } 3525 3526 void 3527 xptree_destroy(void) 3528 { 3529 dbg_print(1, "xptree_destroy: picl_root_obj = %s\n", 3530 (picl_root_obj == NULL ? "NULL" : "not-NULL")); 3531 3532 if (picl_root_obj == NULL) 3533 return; 3534 3535 dbg_print(1, "xptree_destroy: call plugin_fini\n"); 3536 plugin_fini(plugin_reg_list); 3537 dbg_print(1, "xptree_destroy: plugin_fini DONE\n"); 3538 3539 (void) ptree_delete_node(picl_root_obj->ptree_hdl); 3540 (void) ptree_destroy_node(picl_root_obj->ptree_hdl); 3541 3542 (void) rw_wrlock(&ptree_rwlock); 3543 picl_root_obj = NULL; 3544 (void) rw_unlock(&ptree_rwlock); 3545 } 3546 3547 /*ARGSUSED*/ 3548 int 3549 xptree_initialize(int flg) 3550 { 3551 int err; 3552 pthread_attr_t attr; 3553 pthread_t tid; 3554 3555 picld_pid = getpid(); 3556 picld_cred.dc_euid = geteuid(); 3557 picld_cred.dc_egid = getegid(); 3558 picld_cred.dc_ruid = getuid(); 3559 picld_cred.dc_rgid = getgid(); 3560 picld_cred.dc_pid = getpid(); 3561 3562 picl_hdl_hi = 1; 3563 ptree_hdl_hi = 1; 3564 ptree_generation = 1; 3565 qempty_wait = 0; 3566 3567 if (pthread_mutex_init(&ptree_refresh_mutex, NULL) != 0) 3568 return (PICL_FAILURE); 3569 3570 if (picltree_init() != PICL_SUCCESS) 3571 return (PICL_FAILURE); 3572 3573 init_plugin_reg_list(); 3574 init_plugin_list(); 3575 load_plugins(); 3576 3577 err = construct_picltree(); 3578 if (err != PICL_SUCCESS) 3579 return (err); 3580 3581 /* 3582 * Dispatch events after all plug-ins have initialized 3583 */ 3584 if (pthread_attr_init(&attr) != 0) 3585 return (PICL_FAILURE); 3586 3587 (void) pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); 3588 if (pthread_create(&tid, &attr, ptree_event_thread, NULL)) 3589 return (PICL_FAILURE); 3590 3591 return (PICL_SUCCESS); 3592 } 3593 3594 int 3595 xptree_reinitialize(void) 3596 { 3597 int err; 3598 3599 /* 3600 * Wait for eventq to become empty 3601 */ 3602 dbg_print(1, "xptree_reinitialize: wait for evtq empty\n"); 3603 (void) pthread_mutex_lock(&evtq_lock); 3604 qempty_wait = 1; 3605 while (eventqp != NULL) 3606 (void) pthread_cond_wait(&evtq_empty, &evtq_lock); 3607 qempty_wait = 0; 3608 (void) pthread_mutex_unlock(&evtq_lock); 3609 dbg_print(1, "xptree_reinitialize: evtq empty is EMPTY\n"); 3610 3611 (void) rw_wrlock(&ptree_rwlock); 3612 picl_root_obj = NULL; 3613 ptree_root_hdl = PICL_INVALID_PICLHDL; 3614 (void) rw_unlock(&ptree_rwlock); 3615 (void) pthread_mutex_lock(&ptree_refresh_mutex); 3616 ++ptree_generation; 3617 (void) pthread_mutex_unlock(&ptree_refresh_mutex); 3618 3619 err = construct_picltree(); 3620 (void) pthread_mutex_lock(&ptree_refresh_mutex); 3621 (void) pthread_cond_broadcast(&ptree_refresh_cond); 3622 (void) pthread_mutex_unlock(&ptree_refresh_mutex); 3623 3624 (void) pthread_mutex_lock(&evtq_lock); 3625 (void) pthread_cond_broadcast(&evtq_cv); 3626 (void) pthread_mutex_unlock(&evtq_lock); 3627 3628 return (err); 3629 } 3630 3631 /* 3632 * This function is called by the PICL daemon on behalf of clients to 3633 * wait for a tree refresh 3634 */ 3635 int 3636 xptree_refresh_notify(uint32_t secs) 3637 { 3638 int curgen; 3639 int ret; 3640 timespec_t to; 3641 3642 if (secs != 0) { 3643 if (pthread_mutex_lock(&ptree_refresh_mutex) != 0) 3644 return (PICL_FAILURE); 3645 3646 curgen = ptree_generation; 3647 3648 while (curgen == ptree_generation) { 3649 if (secs == UINT32_MAX) /* wait forever */ 3650 (void) pthread_cond_wait(&ptree_refresh_cond, 3651 &ptree_refresh_mutex); 3652 else { 3653 to.tv_sec = secs; 3654 to.tv_nsec = 0; 3655 ret = pthread_cond_reltimedwait_np( 3656 &ptree_refresh_cond, 3657 &ptree_refresh_mutex, &to); 3658 if (ret == ETIMEDOUT) 3659 break; 3660 } 3661 } 3662 3663 (void) pthread_mutex_unlock(&ptree_refresh_mutex); 3664 } 3665 3666 return (PICL_SUCCESS); 3667 } 3668 3669 /*VARARGS2*/ 3670 void 3671 dbg_print(int level, const char *fmt, ...) 3672 { 3673 if (verbose_level >= level) { 3674 va_list ap; 3675 3676 va_start(ap, fmt); 3677 (void) vprintf(fmt, ap); 3678 va_end(ap); 3679 } 3680 } 3681 3682 /*ARGSUSED*/ 3683 void 3684 dbg_exec(int level, void (*fn)(void *args), void *args) 3685 { 3686 if (verbose_level > level) 3687 (*fn)(args); 3688 } 3689