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