cmd: remove locator
[unleashed.git] / usr / src / lib / libpicltree / picltree.c
blob77804b985ca6c9c4f9d3adbf7615d8076d1bc74d
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
27 * This module implements the PTree interface and the PICL to PTree calls
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).
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.
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.
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.
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.
62 * Two-Phase Locking scheme: lock acquire phase and lock release phase.
64 * Lock Ordering:
65 * The ptree_rwlock and node locks are always acquired in the following order:
66 * lock ptree_rwlock
67 * lock node
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.
83 * Never hold more than one node lock at a time.
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.
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"
133 #define SO_VERS ".so.1"
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 */
152 static picld_plugin_reg_list_t *plugin_reg_list = NULL;
153 static picld_plugin_desc_t *plugin_desc;
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;
163 * PICL daemon verbose level
165 int verbose_level;
169 * Event handler free functions
171 static void
172 free_handler(evt_handler_t *evhp)
174 free(evhp->ename);
175 (void) pthread_cond_broadcast(&evhp->cv);
176 (void) pthread_cond_destroy(&evhp->cv);
177 free(evhp);
182 * queue_event to events queue
184 static void
185 queue_event(eventq_t *evt)
187 eventq_t *tmpp;
189 evt->next = NULL;
190 if (eventqp == NULL)
191 eventqp = evt;
192 else {
193 tmpp = eventqp;
194 while (tmpp->next != NULL)
195 tmpp = tmpp->next;
196 tmpp->next = evt;
201 * unqueue_event from the specified eventq
203 static eventq_t *
204 unqueue_event(eventq_t **qp)
206 eventq_t *evtp;
208 evtp = *qp;
209 if (evtp != NULL)
210 *qp = evtp->next;
211 return (evtp);
215 * register an event handler by adding it to the list
218 ptree_register_handler(const char *ename,
219 void (*evt_handler)(const char *ename, const void *earg, size_t size,
220 void *cookie), void *cookie)
222 evt_handler_t *ent;
223 evt_handler_t *iter;
225 if (ename == NULL)
226 return (PICL_INVALIDARG);
229 * Initialize event handler entry
231 ent = malloc(sizeof (*ent));
232 if (ent == NULL)
233 return (PICL_FAILURE);
234 ent->ename = strdup(ename);
235 if (ent->ename == NULL) {
236 free(ent);
237 return (PICL_FAILURE);
239 ent->cookie = cookie;
240 ent->evt_handler = evt_handler;
241 ent->execflg = 0;
242 ent->wakeupflg = 0;
243 (void) pthread_cond_init(&ent->cv, NULL);
244 ent->next = NULL;
247 * add handler to the handler list
249 (void) pthread_mutex_lock(&evthandler_lock);
250 if (evt_handlers == NULL) {
251 evt_handlers = ent;
252 (void) pthread_mutex_unlock(&evthandler_lock);
253 return (PICL_SUCCESS);
255 iter = evt_handlers;
256 while (iter->next != NULL)
257 iter = iter->next;
258 iter->next = ent;
259 (void) pthread_mutex_unlock(&evthandler_lock);
261 return (PICL_SUCCESS);
265 * unregister handler
267 void
268 ptree_unregister_handler(const char *ename,
269 void (*evt_handler)(const char *ename, const void *earg, size_t size,
270 void *cookie), void *cookie)
272 evt_handler_t *evhdlrp, **evhdlrpp;
274 if (ename == NULL)
275 return;
278 * unlink handler from handler list
280 (void) pthread_mutex_lock(&evthandler_lock);
282 retry:
283 for (evhdlrpp = &evt_handlers; (evhdlrp = *evhdlrpp) != NULL;
284 evhdlrpp = &evhdlrp->next) {
285 if ((evhdlrp->cookie != cookie) ||
286 (strcmp(evhdlrp->ename, ename) != 0) ||
287 (evhdlrp->evt_handler != evt_handler))
288 continue;
291 * If the handler is in execution, release the lock
292 * and wait for it to complete and retry.
294 if (evhdlrp->execflg) {
295 evhdlrp->wakeupflg = 1;
296 (void) pthread_cond_wait(&evhdlrp->cv,
297 &evthandler_lock);
298 goto retry;
302 * Unlink this handler from the linked list
304 *evhdlrpp = evhdlrp->next;
305 free_handler(evhdlrp);
306 break;
309 (void) pthread_mutex_unlock(&evthandler_lock);
313 * Call all registered handlers for the event
315 static void
316 call_event_handlers(eventq_t *ev)
318 evt_handler_t *iter;
319 void (*evhandler)(const char *, const void *, size_t, void *);
320 void (*completion_handler)(char *ename, void *earg, size_t size);
322 (void) pthread_mutex_lock(&evthandler_lock);
323 iter = evt_handlers;
324 while (iter != NULL) {
325 if (strcmp(iter->ename, ev->ename) == 0) {
326 evhandler = iter->evt_handler;
327 iter->execflg = 1;
328 (void) pthread_mutex_unlock(&evthandler_lock);
329 if (evhandler) {
330 dbg_print(2, "ptree_evthr: Invoking evthdlr:%p"
331 " ename:%s\n", evhandler, ev->ename);
332 (*evhandler)(ev->ename, ev->earg, ev->size,
333 iter->cookie);
334 dbg_print(2, "ptree_evthr: done evthdlr:%p "
335 "ename:%s\n", evhandler, ev->ename);
337 (void) pthread_mutex_lock(&evthandler_lock);
338 iter->execflg = 0;
339 if (iter->wakeupflg) {
340 iter->wakeupflg = 0;
341 (void) pthread_cond_broadcast(&iter->cv);
344 iter = iter->next;
346 (void) pthread_mutex_unlock(&evthandler_lock);
347 if ((completion_handler = ev->completion_handler) != NULL) {
348 dbg_print(2,
349 "ptree_evthr: Invoking completion hdlr:%p ename:%s\n",
350 completion_handler, ev->ename);
351 (*completion_handler)((char *)ev->ename, (void *)ev->earg,
352 ev->size);
353 dbg_print(2, "ptree_evthr: done completion hdlr:%p ename:%s\n",
354 completion_handler, ev->ename);
356 (void) pthread_mutex_lock(&ptree_refresh_mutex);
357 ++ptree_generation;
358 (void) pthread_cond_broadcast(&ptree_refresh_cond);
359 (void) pthread_mutex_unlock(&ptree_refresh_mutex);
363 * This function is called by a plug-in to post an event
366 ptree_post_event(const char *ename, const void *earg, size_t size,
367 void (*completion_handler)(char *ename, void *earg, size_t size))
369 eventq_t *evt;
371 if (ename == NULL)
372 return (PICL_INVALIDARG);
374 evt = malloc(sizeof (*evt));
375 if (evt == NULL)
376 return (PICL_FAILURE);
377 evt->ename = ename;
378 evt->earg = earg;
379 evt->size = size;
380 evt->completion_handler = completion_handler;
382 (void) pthread_mutex_lock(&evtq_lock);
383 queue_event(evt);
384 (void) pthread_cond_broadcast(&evtq_cv);
385 (void) pthread_mutex_unlock(&evtq_lock);
386 return (PICL_SUCCESS);
390 * PICLTREE event thread
392 /*ARGSUSED*/
393 static void *
394 ptree_event_thread(void *argp)
396 eventq_t *evt;
398 for (;;) {
399 (void) pthread_mutex_lock(&evtq_lock);
400 while (eventqp == NULL) {
402 * Signal empty queue
404 if (qempty_wait)
405 (void) pthread_cond_broadcast(&evtq_empty);
406 (void) pthread_cond_wait(&evtq_cv, &evtq_lock);
408 if ((evt = unqueue_event(&eventqp)) != NULL) {
409 (void) pthread_mutex_unlock(&evtq_lock);
410 call_event_handlers(evt);
411 free(evt);
412 } else
413 (void) pthread_mutex_unlock(&evtq_lock);
415 /*NOTREACHED*/
416 return (NULL);
421 * Create a new element
423 static hash_elem_t *
424 hash_newobj(uint32_t hdl_val, void *obj_val)
426 hash_elem_t *n;
428 n = malloc(sizeof (*n));
429 if (n == NULL)
430 return (NULL);
431 n->hdl = hdl_val;
432 n->hash_obj = obj_val;
433 n->next = NULL;
434 return (n);
437 static hash_elem_t *
438 hash_newhdl(uint32_t picl_hdl, uint32_t ptreeh)
440 hash_elem_t *n;
442 n = malloc(sizeof (*n));
443 if (n == NULL)
444 return (NULL);
445 n->hdl = picl_hdl;
446 n->hash_hdl = ptreeh;
447 n->next = NULL;
448 return (n);
452 * Initialize a hash table by setting all entries to NULL
454 static int
455 hash_init(hash_t *htbl)
457 int i;
459 htbl->hash_size = HASH_TBL_SIZE;
460 htbl->tbl = malloc(sizeof (hash_elem_t *) * HASH_TBL_SIZE);
461 if (htbl->tbl == NULL)
462 return (-1);
463 for (i = 0; i < htbl->hash_size; ++i)
464 htbl->tbl[i] = NULL;
465 return (0);
469 * Lock free function to add an entry in the hash table
471 static int
472 hash_add_newobj(hash_t *htbl, picl_hdl_t hdl, void *pobj)
474 int indx;
475 hash_elem_t *n;
476 uint32_t hash_val = HASH_VAL(hdl);
478 n = hash_newobj(hash_val, pobj);
479 if (n == NULL)
480 return (-1);
481 indx = HASH_INDEX(htbl->hash_size, hash_val);
482 n->next = htbl->tbl[indx];
483 htbl->tbl[indx] = n;
484 return (0);
487 static int
488 hash_add_newhdl(hash_t *htbl, picl_hdl_t piclh, picl_hdl_t ptreeh)
490 int indx;
491 hash_elem_t *n;
492 uint32_t picl_val = HASH_VAL(piclh);
493 uint32_t ptree_val = HASH_VAL(ptreeh);
495 n = hash_newhdl(picl_val, ptree_val);
496 if (n == NULL)
497 return (-1);
499 indx = HASH_INDEX(htbl->hash_size, picl_val);
500 n->next = htbl->tbl[indx];
501 htbl->tbl[indx] = n;
502 return (0);
506 * Lock free function to remove the handle from the hash table
507 * Returns -1 if element not found, 0 if successful
509 static int
510 hash_remove(hash_t *htbl, picl_hdl_t hdl)
512 hash_elem_t *nxt;
513 hash_elem_t *cur;
514 int i;
515 uint32_t hash_val = HASH_VAL(hdl);
517 i = HASH_INDEX(htbl->hash_size, hash_val);
518 if (htbl->tbl[i] == NULL)
519 return (-1);
521 cur = htbl->tbl[i];
522 if (cur->hdl == hash_val) {
523 htbl->tbl[i] = cur->next;
524 free(cur);
525 return (0);
527 nxt = cur->next;
528 while (nxt != NULL) {
529 if (nxt->hdl == hash_val) {
530 cur->next = nxt->next;
531 free(nxt);
532 return (0);
534 cur = nxt;
535 nxt = nxt->next;
537 return (-1);
541 * Lock free function to lookup the hash table for a given handle
542 * Returns NULL if not found
544 static void *
545 hash_lookup_obj(hash_t *htbl, picl_hdl_t hdl)
547 hash_elem_t *tmp;
548 int i;
549 uint32_t hash_val;
551 hash_val = HASH_VAL(hdl);
552 i = HASH_INDEX(htbl->hash_size, hash_val);
553 tmp = htbl->tbl[i];
554 while (tmp != NULL) {
555 if (tmp->hdl == hash_val)
556 return (tmp->hash_obj);
557 tmp = tmp->next;
559 return (NULL);
562 static picl_hdl_t
563 hash_lookup_hdl(hash_t *htbl, picl_hdl_t hdl)
565 hash_elem_t *tmp;
566 int i;
567 uint32_t hash_val;
569 hash_val = HASH_VAL(hdl);
570 i = HASH_INDEX(htbl->hash_size, hash_val);
571 tmp = htbl->tbl[i];
572 while (tmp != NULL) {
573 if (tmp->hdl == hash_val)
574 return (MAKE_HANDLE(picld_pid, tmp->hash_hdl));
575 tmp = tmp->next;
577 return (PICL_INVALID_PICLHDL);
581 * Is the PICL handle stale or invalid handle?
583 static int
584 picl_hdl_error(picl_hdl_t hdl)
586 uint32_t hash_val = HASH_VAL(hdl);
587 pid_t pid = GET_PID(hdl);
588 int err;
590 (void) pthread_mutex_lock(&piclhdl_lock);
591 err = PICL_STALEHANDLE;
592 if ((pid != picld_pid) || (hash_val >= picl_hdl_hi) ||
593 (hash_val == 0))
594 err = PICL_INVALIDHANDLE;
595 (void) pthread_mutex_unlock(&piclhdl_lock);
596 return (err);
600 * Is the Ptree handle stale or invalid handle?
602 static int
603 ptree_hdl_error(picl_hdl_t hdl)
605 uint32_t hash_val = HASH_VAL(hdl);
606 pid_t pid = GET_PID(hdl);
607 int err;
609 (void) pthread_mutex_lock(&ptreehdl_lock);
610 err = PICL_STALEHANDLE;
611 if ((pid != picld_pid) || (hash_val >= ptree_hdl_hi) ||
612 (hash_val == 0))
613 err = PICL_INVALIDHANDLE;
614 (void) pthread_mutex_unlock(&ptreehdl_lock);
615 return (err);
619 * For a PICL handle, return the PTree handle and the PICL object
620 * Locks and releases the PICL table.
623 cvt_picl2ptree(picl_hdl_t hdl, picl_hdl_t *ptree_hdl)
625 picl_hdl_t tmph;
626 int err;
628 (void) rw_rdlock(&picltbl_rwlock); /* lock picl */
629 tmph = hash_lookup_hdl(&picltbl, hdl);
630 if (tmph == PICL_INVALID_PICLHDL) {
631 err = picl_hdl_error(hdl);
632 (void) rw_unlock(&picltbl_rwlock); /* unlock picl */
633 return (err);
635 *ptree_hdl = tmph;
636 (void) rw_unlock(&picltbl_rwlock); /* unlock picl */
637 return (PICL_SUCCESS);
641 * Allocate a ptree handle
643 static picl_hdl_t
644 alloc_ptreehdl(void)
646 picl_hdl_t hdl;
648 (void) pthread_mutex_lock(&ptreehdl_lock); /* lock ptreehdl */
649 hdl = MAKE_HANDLE(picld_pid, ptree_hdl_hi);
650 ++ptree_hdl_hi;
651 (void) pthread_mutex_unlock(&ptreehdl_lock); /* unlock ptreehdl */
652 return (hdl);
656 * Allocate a picl handle
657 * A PICL handle is ptree_hdl value with 1 in MSB of handle value.
658 * If a ptree handle already has 1 in MSB, then it cannot be piclized
659 * and the daemon must be restarted.
661 static picl_hdl_t
662 alloc_piclhdl(void)
664 picl_hdl_t hdl;
666 (void) pthread_mutex_lock(&piclhdl_lock); /* lock piclhdl */
667 hdl = MAKE_HANDLE(picld_pid, picl_hdl_hi);
668 ++picl_hdl_hi;
669 (void) pthread_mutex_unlock(&piclhdl_lock); /* unlock piclhdl */
670 return (hdl);
674 * Allocate and add handle to PTree hash table
676 static void
677 alloc_and_add_to_ptree(picl_obj_t *pobj)
679 pobj->ptree_hdl = alloc_ptreehdl();
680 (void) rw_wrlock(&ptree_rwlock);
681 (void) hash_add_newobj(&ptreetbl, pobj->ptree_hdl, pobj);
682 (void) rw_unlock(&ptree_rwlock);
686 * Lock a picl node object
688 static int
689 lock_obj(int rw, picl_obj_t *nodep)
691 if (rw == RDLOCK_NODE)
692 (void) rw_rdlock(&nodep->node_lock);
693 else if (rw == WRLOCK_NODE)
694 (void) rw_wrlock(&nodep->node_lock);
695 else
696 return (-1);
697 return (0);
701 * Release the picl node object.
702 * This function may be called with a NULL object pointer.
704 static void
705 unlock_node(picl_obj_t *nodep)
707 if (nodep == NULL)
708 return;
709 (void) rw_unlock(&nodep->node_lock);
713 * This function locks the node of a property and returns the node object
714 * and the property object.
716 static int
717 lookup_and_lock_propnode(int rw, picl_prophdl_t proph, picl_obj_t **nodep,
718 picl_obj_t **propp)
720 picl_obj_t *pobj;
721 picl_obj_t *nobj;
723 pobj = hash_lookup_obj(&ptreetbl, proph);
724 if (pobj == NULL)
725 return (ptree_hdl_error(proph));
728 * Get the property's or table entry's node object
730 nobj = NULL;
731 if (pobj->obj_type == PICL_OBJ_PROP)
732 nobj = pobj->prop_node;
733 else if (pobj->obj_type == (PICL_OBJ_PROP|PICL_OBJ_TABLEENTRY))
734 nobj = pobj->prop_table->prop_node;
735 else {
736 *propp = pobj; /* return the prop */
737 return (PICL_NOTPROP);
740 if (nobj && (lock_obj(rw, nobj) < 0)) /* Lock node */
741 return (PICL_FAILURE);
743 *nodep = nobj;
744 *propp = pobj;
746 return (PICL_SUCCESS);
750 * This function locks the node of a table and returns the node object
751 * and the table object.
753 static int
754 lookup_and_lock_tablenode(int rw, picl_prophdl_t tblh, picl_obj_t **nodep,
755 picl_obj_t **tblobj)
757 picl_obj_t *pobj;
758 picl_obj_t *nobj;
760 pobj = hash_lookup_obj(&ptreetbl, tblh);
761 if (pobj == NULL)
762 return (ptree_hdl_error(tblh));
765 * Get the property's or table entry's node object
767 nobj = NULL;
768 if (pobj->obj_type != PICL_OBJ_TABLE)
769 return (PICL_NOTTABLE);
770 nobj = pobj->prop_node;
772 if (nobj && (lock_obj(rw, nobj) < 0)) /* Lock node */
773 return (PICL_FAILURE);
775 *nodep = nobj;
776 *tblobj = pobj;
778 return (PICL_SUCCESS);
782 * This locks the node of a table or a table entry and returns the
783 * node object and the table or table entry object
785 static int
786 lookup_and_lock_tableprop_node(int rw, picl_prophdl_t tblproph,
787 picl_obj_t **nodep, picl_obj_t **tblpropp)
789 picl_obj_t *pobj;
790 picl_obj_t *nobj;
792 pobj = hash_lookup_obj(&ptreetbl, tblproph);
793 if (pobj == NULL)
794 return (ptree_hdl_error(tblproph));
797 * Get the property's or table entry's node object
799 nobj = NULL;
800 if ((pobj->obj_type != PICL_OBJ_TABLE) && /* not a table */
801 !(pobj->obj_type & PICL_OBJ_TABLEENTRY)) /* or an entry */
802 return (PICL_NOTTABLE);
803 if (pobj->obj_type == PICL_OBJ_TABLE)
804 nobj = pobj->prop_node;
805 else
806 nobj = pobj->prop_table->prop_node;
808 if (nobj && (lock_obj(rw, nobj) < 0)) /* Lock node */
809 return (PICL_FAILURE);
811 *tblpropp = pobj;
812 *nodep = nobj;
814 return (PICL_SUCCESS);
818 * Lock the node corresponding to the given handle and return its object
820 static int
821 lookup_and_lock_node(int rw, picl_nodehdl_t nodeh, picl_obj_t **nodep)
823 picl_obj_t *nobj;
825 nobj = hash_lookup_obj(&ptreetbl, nodeh);
826 if (nobj == NULL)
827 return (ptree_hdl_error(nodeh));
828 else if (nobj->obj_type != PICL_OBJ_NODE)
829 return (PICL_NOTNODE);
830 if (lock_obj(rw, nobj) < 0) /* Lock node */
831 return (PICL_FAILURE);
832 *nodep = nobj;
833 return (PICL_SUCCESS);
837 * Is the property name a restricted property name?
839 static int
840 picl_restricted(const char *name)
842 if (strcmp(name, PICL_PROP_CLASSNAME) == 0)
843 return (0); /* not restricted */
845 if ((name[0] == '_') && (strchr(&name[1], '_') == NULL))
846 return (1);
847 return (0);
851 * Check the value size with the property size
852 * Return PICL_INVALIDARG if the size does not match exactly for strongly
853 * typed properties.
854 * For charstring reads allow sizes that match the value size
855 * For bytearray return PICL_VALUETOOBIG
856 * if the size is greater than the buffer size.
858 static int
859 check_propsize(int op, picl_obj_t *propp, size_t sz)
861 if (propp->prop_mode & PICL_VOLATILE) {
862 if (sz != propp->prop_size)
863 return (PICL_INVALIDARG);
864 else
865 return (PICL_SUCCESS);
869 * check size for non-volatile properties
871 switch (propp->prop_type) {
872 case PICL_PTYPE_CHARSTRING:
873 if ((op == PROP_READ) &&
874 (strlen(propp->prop_val) >= sz))
875 return (PICL_VALUETOOBIG);
876 if ((op == PROP_WRITE) && (sz > propp->prop_size))
877 return (PICL_VALUETOOBIG);
878 break;
879 case PICL_PTYPE_BYTEARRAY:
880 if (op == PROP_WRITE) {
881 if (sz > propp->prop_size)
882 return (PICL_VALUETOOBIG);
883 return (PICL_SUCCESS); /* allow small writes */
885 /* FALLTHROUGH */
886 default:
887 if (propp->prop_size != sz)
888 return (PICL_INVALIDARG);
889 break;
891 return (PICL_SUCCESS);
894 void
895 cvt_ptree2picl(picl_hdl_t *handlep)
897 picl_obj_t *pobj;
899 (void) rw_rdlock(&ptree_rwlock);
900 pobj = hash_lookup_obj(&ptreetbl, *handlep);
901 if (pobj == NULL)
902 *handlep = PICL_INVALID_PICLHDL;
903 else
904 (void) memcpy(handlep, &pobj->picl_hdl, sizeof (*handlep));
905 (void) rw_unlock(&ptree_rwlock);
909 * The caller of the piclize() set of functions is assumed to hold
910 * the ptree_rwlock().
912 static void
913 piclize_obj(picl_obj_t *pobj)
915 (void) rw_wrlock(&picltbl_rwlock);
916 pobj->picl_hdl = alloc_piclhdl();
917 (void) hash_add_newhdl(&picltbl, pobj->picl_hdl, pobj->ptree_hdl);
918 (void) rw_unlock(&picltbl_rwlock);
921 static void
922 piclize_table(picl_obj_t *tbl_obj)
924 picl_obj_t *rowp;
925 picl_obj_t *colp;
927 for (rowp = tbl_obj->next_row; rowp != NULL; rowp = rowp->next_col)
928 for (colp = rowp; colp != NULL; colp = colp->next_row)
929 piclize_obj(colp);
932 static void
933 piclize_prop(picl_obj_t *propp)
935 picl_obj_t *tbl_obj;
936 picl_prophdl_t tblh;
938 piclize_obj(propp);
939 if (!(propp->prop_mode & PICL_VOLATILE) &&
940 (propp->prop_type == PICL_PTYPE_TABLE)) {
941 tblh = *(picl_prophdl_t *)propp->prop_val;
942 tbl_obj = hash_lookup_obj(&ptreetbl, tblh);
943 if (tbl_obj == NULL)
944 return;
945 piclize_obj(tbl_obj);
946 piclize_table(tbl_obj);
951 * Function to create PICL handles for a subtree and add them to
952 * the table
954 static void
955 piclize_node(picl_obj_t *nodep)
957 picl_obj_t *propp;
958 picl_obj_t *chdp;
960 piclize_obj(nodep);
961 propp = nodep->first_prop;
962 while (propp != NULL) {
963 piclize_prop(propp);
964 propp = propp->next_prop;
967 /* go through the children */
968 for (chdp = nodep->child_node; chdp != NULL; chdp = chdp->sibling_node)
969 piclize_node(chdp);
973 * Function to remove PICL handles
975 static void
976 unpiclize_obj(picl_obj_t *pobj)
978 (void) rw_wrlock(&picltbl_rwlock);
979 (void) hash_remove(&picltbl, pobj->picl_hdl);
980 pobj->picl_hdl = PICL_INVALID_PICLHDL;
981 (void) rw_unlock(&picltbl_rwlock);
984 static void
985 unpiclize_table(picl_obj_t *tbl_obj)
987 picl_obj_t *rowp;
988 picl_obj_t *colp;
990 for (rowp = tbl_obj->next_row; rowp != NULL; rowp = rowp->next_col)
991 for (colp = rowp; colp != NULL; colp = colp->next_row)
992 unpiclize_obj(colp);
993 unpiclize_obj(tbl_obj);
996 static void
997 unpiclize_prop(picl_obj_t *propp)
999 picl_obj_t *tbl_obj;
1000 picl_prophdl_t tblh;
1002 if (!IS_PICLIZED(propp))
1003 return;
1004 unpiclize_obj(propp);
1005 if (!(propp->prop_mode & PICL_VOLATILE) &&
1006 (propp->prop_type == PICL_PTYPE_TABLE)) {
1007 tblh = *(picl_prophdl_t *)propp->prop_val;
1008 tbl_obj = hash_lookup_obj(&ptreetbl, tblh);
1009 unpiclize_table(tbl_obj);
1014 * Function to remove PICL handles for a subtree and its
1015 * properties
1017 static void
1018 unpiclize_node(picl_obj_t *nodep)
1020 picl_obj_t *propp;
1021 picl_obj_t *chdp;
1024 if (!IS_PICLIZED(nodep))
1025 return;
1027 unpiclize_obj(nodep);
1028 propp = nodep->first_prop;
1029 while (propp != NULL) {
1030 unpiclize_prop(propp);
1031 propp = propp->next_prop;
1034 /* go through the children */
1035 for (chdp = nodep->child_node; chdp != NULL; chdp = chdp->sibling_node)
1036 unpiclize_node(chdp);
1041 * The caller holds the lock on the ptree_lock when calling this.
1042 * If ret is not NULL then this function returns the referenced object.
1044 static int
1045 lookup_verify_ref_prop(picl_obj_t *propp, picl_obj_t **ret)
1047 picl_nodehdl_t refh;
1048 picl_obj_t *refobj;
1050 refh = *(picl_nodehdl_t *)propp->prop_val;
1051 refobj = hash_lookup_obj(&ptreetbl, refh);
1052 if (refobj == NULL)
1053 return (ptree_hdl_error(refh));
1054 else if (refobj->obj_type != PICL_OBJ_NODE)
1055 return (PICL_INVREFERENCE);
1056 if (ret)
1057 *ret = refobj;
1058 return (PICL_SUCCESS);
1062 * The caller holds the lock on ptree_lock when calling this.
1063 * If ret is not NULL, then this function returns the table object
1065 static int
1066 lookup_verify_table_prop(picl_obj_t *propp, picl_obj_t **ret)
1068 picl_prophdl_t tblh;
1069 picl_obj_t *tbl_obj;
1071 tblh = *(picl_prophdl_t *)propp->prop_val;
1072 tbl_obj = hash_lookup_obj(&ptreetbl, tblh);
1073 if (tbl_obj == NULL)
1074 return (ptree_hdl_error(tblh));
1075 else if (!(tbl_obj->obj_type & PICL_OBJ_TABLE))
1076 return (PICL_NOTTABLE);
1077 if (ret)
1078 *ret = tbl_obj;
1079 return (PICL_SUCCESS);
1082 static int
1083 lookup_verify_prop_handle(picl_prophdl_t proph, picl_obj_t **ret)
1085 picl_obj_t *propp;
1087 propp = hash_lookup_obj(&ptreetbl, proph);
1088 if (propp == NULL)
1089 return (ptree_hdl_error(proph));
1090 else if (!(propp->obj_type & PICL_OBJ_PROP))
1091 return (PICL_NOTPROP);
1092 if (ret)
1093 *ret = propp;
1094 return (PICL_SUCCESS);
1097 static int
1098 lookup_verify_node_handle(picl_nodehdl_t nodeh, picl_obj_t **ret)
1100 picl_obj_t *nodep;
1102 nodep = hash_lookup_obj(&ptreetbl, nodeh);
1103 if (nodep == NULL)
1104 return (ptree_hdl_error(nodeh));
1105 else if (nodep->obj_type != PICL_OBJ_NODE)
1106 return (PICL_NOTNODE);
1107 if (ret)
1108 *ret = nodep;
1109 return (PICL_SUCCESS);
1112 static int
1113 lookup_prop_by_name(picl_obj_t *nodep, const char *pname, picl_obj_t **ret)
1115 picl_obj_t *propp;
1117 if (strcmp(pname, PICL_PROP_PARENT) == 0) {
1118 if (nodep->parent_node == NULL)
1119 return (PICL_PROPNOTFOUND);
1120 else
1121 return (PICL_SUCCESS);
1123 if (strcmp(pname, PICL_PROP_CHILD) == 0) {
1124 if (nodep->child_node == NULL)
1125 return (PICL_PROPNOTFOUND);
1126 else
1127 return (PICL_SUCCESS);
1129 if (strcmp(pname, PICL_PROP_PEER) == 0) {
1130 if (nodep->sibling_node == NULL)
1131 return (PICL_PROPNOTFOUND);
1132 else
1133 return (PICL_SUCCESS);
1136 propp = nodep->first_prop;
1137 while (propp != NULL) {
1138 if (strcmp(propp->prop_name, pname) == 0) {
1139 if (ret)
1140 *ret = propp;
1141 return (PICL_SUCCESS);
1143 propp = propp->next_prop;
1145 return (PICL_PROPNOTFOUND);
1149 * This function locks the ptree, verifies that the handle is a reference
1150 * to a node of specified class name, releases the lock
1152 static int
1153 check_ref_handle(picl_nodehdl_t refh, char *clname)
1155 picl_obj_t *refobj;
1156 picl_obj_t *propp;
1157 int err;
1159 (void) rw_rdlock(&ptree_rwlock); /* Lock ptree */
1160 refobj = hash_lookup_obj(&ptreetbl, refh);
1161 if ((refobj == NULL) || !(refobj->obj_type & PICL_OBJ_NODE)) {
1162 (void) rw_unlock(&ptree_rwlock);
1163 return (PICL_INVREFERENCE);
1166 err = lookup_prop_by_name(refobj, PICL_PROP_CLASSNAME, &propp);
1167 if ((err != PICL_SUCCESS) || (propp->prop_val == NULL) ||
1168 (strcmp(propp->prop_val, clname) != 0))
1169 err = PICL_INVREFERENCE;
1170 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
1171 return (err);
1174 static int
1175 check_table_handle(picl_prophdl_t tblh)
1177 picl_obj_t *tbl_obj;
1178 int err;
1180 (void) rw_rdlock(&ptree_rwlock);
1181 err = PICL_SUCCESS;
1182 tbl_obj = hash_lookup_obj(&ptreetbl, tblh);
1183 if ((tbl_obj == NULL) || !(tbl_obj->obj_type & PICL_OBJ_TABLE))
1184 err = PICL_NOTTABLE;
1185 (void) rw_unlock(&ptree_rwlock);
1186 return (err);
1190 * PICLTree Interface routines for plug-in modules
1193 ptree_get_root(picl_nodehdl_t *rooth)
1195 *rooth = ptree_root_hdl;
1196 return (PICL_SUCCESS);
1200 * Lock free create a property object
1202 static int
1203 create_propobj(const ptree_propinfo_t *pinfo, const void *valbuf,
1204 picl_obj_t **pobjp)
1206 picl_obj_t *pobj;
1208 if (pinfo->version != PTREE_PROPINFO_VERSION_1)
1209 return (PICL_NOTSUPPORTED);
1211 if (!(pinfo->piclinfo.accessmode & PICL_VOLATILE) &&
1212 (pinfo->piclinfo.type != PICL_PTYPE_VOID) &&
1213 (valbuf == NULL))
1214 return (PICL_INVALIDARG);
1216 pobj = malloc(sizeof (picl_obj_t));
1217 if (pobj == NULL)
1218 return (PICL_FAILURE);
1220 pobj->obj_type = PICL_OBJ_PROP;
1221 pobj->pinfo_ver = pinfo->version;
1222 pobj->prop_type = pinfo->piclinfo.type;
1223 pobj->prop_mode = pinfo->piclinfo.accessmode;
1224 pobj->prop_size = pinfo->piclinfo.size;
1225 (void) strcpy(pobj->prop_name, pinfo->piclinfo.name);
1226 pobj->read_func = pinfo->read;
1227 pobj->write_func = pinfo->write;
1229 pobj->prop_val = NULL;
1230 if (!(pinfo->piclinfo.accessmode & PICL_VOLATILE)) {
1231 pobj->prop_val = malloc(pinfo->piclinfo.size);
1232 if (pobj->prop_val == NULL) {
1233 free(pobj);
1234 return (PICL_FAILURE);
1236 if (pobj->prop_type == PICL_PTYPE_CHARSTRING)
1237 (void) strlcpy(pobj->prop_val, valbuf,
1238 pinfo->piclinfo.size);
1239 else
1240 (void) memcpy(pobj->prop_val, valbuf,
1241 pinfo->piclinfo.size);
1243 pobj->prop_node = NULL;
1244 pobj->ptree_hdl = PICL_INVALID_PICLHDL;
1245 pobj->picl_hdl = PICL_INVALID_PICLHDL;
1246 pobj->next_prop = NULL;
1247 pobj->next_row = NULL;
1248 pobj->next_col = NULL;
1250 *pobjp = pobj;
1251 return (PICL_SUCCESS);
1255 * Check for valid arguments, create a property object,
1256 * Lock ptree_rwlock, add the new property handle, release the lock
1257 * For reference properties and table properties, the handles are verified
1258 * before creating the property.
1261 ptree_create_prop(const ptree_propinfo_t *pinfo, const void *valbuf,
1262 picl_prophdl_t *proph)
1264 picl_obj_t *pobj;
1265 picl_nodehdl_t refh;
1266 picl_prophdl_t tblh;
1267 int err;
1268 char *ptr;
1269 int refflag;
1270 char classname[PICL_PROPNAMELEN_MAX];
1272 if (pinfo == NULL)
1273 return (PICL_INVALIDARG);
1274 if (pinfo->version != PTREE_PROPINFO_VERSION_1)
1275 return (PICL_NOTSUPPORTED);
1276 if (pinfo->piclinfo.size >= PICL_PROPSIZE_MAX)
1277 return (PICL_VALUETOOBIG);
1278 if (picl_restricted(pinfo->piclinfo.name))
1279 return (PICL_RESERVEDNAME);
1281 refflag = 0;
1282 if ((pinfo->piclinfo.name[0] == '_') &&
1283 (strchr(&pinfo->piclinfo.name[1], '_') != NULL))
1284 refflag = 1;
1286 if (pinfo->piclinfo.type == PICL_PTYPE_REFERENCE) {
1287 if (refflag == 0)
1288 return (PICL_INVREFERENCE);
1290 * check valid reference handle for non-volatiles
1292 if (!(pinfo->piclinfo.accessmode & PICL_VOLATILE)) {
1293 if (valbuf == NULL)
1294 return (PICL_INVREFERENCE);
1295 if (pinfo->piclinfo.size != sizeof (picl_nodehdl_t))
1296 return (PICL_INVREFERENCE);
1297 (void) strcpy(classname, pinfo->piclinfo.name);
1298 ptr = strchr(&classname[1], '_');
1299 *ptr = '\0';
1300 refh = *(picl_hdl_t *)valbuf;
1301 err = check_ref_handle(refh, &classname[1]);
1302 if (err != PICL_SUCCESS)
1303 return (err);
1305 } else if (refflag == 1)
1306 return (PICL_INVREFERENCE);
1307 else if ((pinfo->piclinfo.type == PICL_PTYPE_TABLE) &&
1308 (!(pinfo->piclinfo.accessmode & PICL_VOLATILE))) {
1309 if (pinfo->piclinfo.size != sizeof (picl_prophdl_t))
1310 return (PICL_INVALIDARG);
1311 tblh = *(picl_prophdl_t *)valbuf;
1312 err = check_table_handle(tblh);
1313 if (err != PICL_SUCCESS)
1314 return (err);
1315 } else if ((strcmp(pinfo->piclinfo.name, PICL_PROP_CLASSNAME) == 0) &&
1316 ((pinfo->piclinfo.type != PICL_PTYPE_CHARSTRING) ||
1317 (strlen(valbuf) >= PICL_CLASSNAMELEN_MAX)))
1318 return (PICL_RESERVEDNAME);
1319 else if ((strcmp(pinfo->piclinfo.name, PICL_PROP_NAME) == 0) &&
1320 (pinfo->piclinfo.type != PICL_PTYPE_CHARSTRING))
1321 return (PICL_RESERVEDNAME);
1323 * No locks held when you get here
1325 err = create_propobj(pinfo, valbuf, &pobj);
1326 if (err != PICL_SUCCESS)
1327 return (err);
1329 alloc_and_add_to_ptree(pobj);
1330 *proph = pobj->ptree_hdl;
1331 return (PICL_SUCCESS);
1335 * Lock free routine to destroy table entries
1336 * This function removes the destroyed handles from the hash table
1337 * Uses lock free routines: hash_lookup() and hash_remove()
1339 static void
1340 destroy_table(picl_obj_t *pobj)
1342 picl_prophdl_t tblh;
1343 picl_obj_t *tbl_obj;
1344 picl_obj_t *rowp;
1345 picl_obj_t *colp;
1346 picl_obj_t *freep;
1348 tblh = *(picl_prophdl_t *)pobj->prop_val;
1349 tbl_obj = hash_lookup_obj(&ptreetbl, tblh);
1350 if (tbl_obj == NULL)
1351 return;
1353 assert(tbl_obj->obj_type & PICL_OBJ_TABLE);
1355 /* Delete all entries */
1356 rowp = tbl_obj->next_row;
1357 while (rowp != NULL) {
1358 colp = rowp;
1359 rowp = rowp->next_col;
1360 while (colp != NULL) {
1361 freep = colp;
1362 colp = colp->next_row;
1363 (void) hash_remove(&ptreetbl, freep->ptree_hdl);
1364 free(freep->prop_val);
1365 free(freep);
1369 (void) hash_remove(&ptreetbl, tbl_obj->ptree_hdl);
1370 free(tbl_obj);
1375 * Lock free function that frees up a property object and removes the
1376 * handles from Ptree table
1378 static void
1379 destroy_propobj(picl_obj_t *propp)
1381 if (propp->prop_type == PICL_PTYPE_TABLE)
1382 destroy_table(propp);
1384 (void) hash_remove(&ptreetbl, propp->ptree_hdl);
1385 free(propp->prop_val);
1386 free(propp);
1390 * This function destroys a previously deleted property.
1391 * A deleted property does not have an associated node.
1392 * All memory allocated for this property are freed
1395 ptree_destroy_prop(picl_prophdl_t proph)
1397 picl_obj_t *propp;
1399 (void) rw_wrlock(&ptree_rwlock); /* Exclusive Lock ptree */
1401 propp = hash_lookup_obj(&ptreetbl, proph);
1402 if (propp == NULL) {
1403 (void) rw_unlock(&ptree_rwlock); /* Unlock ptree */
1404 return (ptree_hdl_error(proph));
1407 /* Is the prop still attached to a node? */
1408 if (propp->prop_node != NULL) {
1409 (void) rw_unlock(&ptree_rwlock); /* Unlock ptree */
1410 return (PICL_CANTDESTROY);
1413 destroy_propobj(propp);
1415 (void) rw_unlock(&ptree_rwlock); /* Unlock ptree */
1416 return (PICL_SUCCESS);
1420 * This function adds a property to the property list of a node and adds
1421 * it to the PICL table if the node has a PICL handle.
1422 * This function locks the picl_rwlock and ptree_rwlock.
1425 ptree_add_prop(picl_nodehdl_t nodeh, picl_prophdl_t proph)
1427 int err;
1428 picl_obj_t *nodep;
1429 picl_obj_t *propp;
1430 picl_obj_t *tbl_obj;
1431 picl_obj_t *refobj;
1433 (void) rw_rdlock(&ptree_rwlock); /* RDLock ptree */
1436 * Verify property handle
1438 err = lookup_verify_prop_handle(proph, &propp);
1439 if (err != PICL_SUCCESS) {
1440 (void) rw_unlock(&ptree_rwlock); /* Unlock ptree */
1441 return (err);
1444 if (propp->prop_node != NULL) {
1445 (void) rw_unlock(&ptree_rwlock);
1446 return (PICL_INVALIDARG);
1449 nodep = NULL;
1451 * Exclusive Lock the node's properties
1453 err = lookup_and_lock_node(WRLOCK_NODE, nodeh, &nodep);
1454 if (err != PICL_SUCCESS) {
1455 (void) rw_unlock(&ptree_rwlock); /* Unlock ptree */
1456 return (err);
1460 * check if prop already exists
1462 err = lookup_prop_by_name(nodep, propp->prop_name, NULL);
1463 if (err == PICL_SUCCESS) {
1464 unlock_node(nodep); /* Unlock node */
1465 (void) rw_unlock(&ptree_rwlock); /* Unlock table */
1466 return (PICL_PROPEXISTS);
1470 * Verify property's value
1472 tbl_obj = NULL;
1473 switch (propp->prop_type) {
1474 case PICL_PTYPE_TABLE:
1475 if (propp->prop_mode & PICL_VOLATILE)
1476 break;
1477 err = lookup_verify_table_prop(propp, &tbl_obj);
1478 if (err != PICL_SUCCESS) {
1479 unlock_node(nodep);
1480 (void) rw_unlock(&ptree_rwlock);
1481 return (err);
1483 tbl_obj->prop_node = nodep; /* set table's nodep */
1484 tbl_obj->table_prop = propp; /* set table prop */
1485 break;
1486 case PICL_PTYPE_REFERENCE:
1487 if (propp->prop_mode & PICL_VOLATILE)
1488 break;
1489 err = lookup_verify_ref_prop(propp, &refobj);
1490 if (err != PICL_SUCCESS) {
1491 unlock_node(nodep);
1492 (void) rw_unlock(&ptree_rwlock);
1493 return (err);
1495 if (IS_PICLIZED(nodep) && !IS_PICLIZED(refobj)) {
1496 unlock_node(nodep);
1497 (void) rw_unlock(&ptree_rwlock);
1498 return (err);
1500 break;
1501 default:
1502 break;
1505 if (IS_PICLIZED(nodep))
1506 piclize_prop(propp);
1508 * Add prop to beginning of list
1510 propp->prop_node = nodep; /* set prop's nodep */
1511 propp->next_prop = nodep->first_prop;
1512 nodep->first_prop = propp;
1514 unlock_node(nodep); /* Unlock node */
1515 (void) rw_unlock(&ptree_rwlock); /* Unlock table */
1516 return (PICL_SUCCESS);
1520 * Lock free function that unlinks a property from its node
1522 static int
1523 unlink_prop(picl_obj_t *nodep, picl_obj_t *propp)
1525 picl_obj_t *iterp;
1527 iterp = nodep->first_prop;
1528 if (iterp == propp) { /* first property */
1529 nodep->first_prop = iterp->next_prop;
1530 return (PICL_SUCCESS);
1532 while ((iterp != NULL) && (iterp->next_prop != propp))
1533 iterp = iterp->next_prop;
1534 if (iterp == NULL)
1535 return (PICL_PROPNOTFOUND);
1536 iterp->next_prop = propp->next_prop;
1537 return (PICL_SUCCESS);
1541 * This function deletes the specified property from the property list
1542 * of its node and removes the handle from PICL table, if the node
1543 * was piclized.
1546 ptree_delete_prop(picl_prophdl_t proph)
1548 int err;
1549 picl_obj_t *nodep;
1550 picl_obj_t *propp;
1552 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
1554 * Lookup the property's node and lock it if there is one
1555 * return the objects for the property and the node
1557 nodep = propp = NULL;
1558 err = lookup_and_lock_propnode(WRLOCK_NODE, proph, &nodep, &propp);
1559 if (err != PICL_SUCCESS) {
1560 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
1561 return (err);
1562 } else if (nodep == NULL) {
1563 /* Nothing to do - already deleted! */
1564 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
1565 return (PICL_SUCCESS);
1568 if (propp->obj_type & PICL_OBJ_TABLEENTRY) {
1569 unlock_node(nodep); /* Unlock node */
1570 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
1571 return (PICL_NOTPROP);
1574 err = unlink_prop(nodep, propp);
1575 if (err != PICL_SUCCESS) {
1576 unlock_node(nodep); /* Unlock node */
1577 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
1578 return (err);
1581 propp->prop_node = NULL; /* reset prop's nodep */
1582 propp->next_prop = NULL;
1584 unpiclize_prop(propp);
1586 unlock_node(nodep); /* Unlock node */
1587 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
1588 return (PICL_SUCCESS);
1592 * Create a table object and return its handle
1595 ptree_create_table(picl_prophdl_t *tblh)
1597 picl_obj_t *pobj;
1599 pobj = malloc(sizeof (picl_obj_t));
1600 if (pobj == NULL)
1601 return (PICL_FAILURE);
1602 pobj->obj_type = PICL_OBJ_TABLE;
1603 pobj->prop_val = NULL;
1604 pobj->prop_node = NULL;
1605 pobj->ptree_hdl = PICL_INVALID_PICLHDL;
1606 pobj->picl_hdl = PICL_INVALID_PICLHDL;
1607 pobj->table_prop = NULL;
1608 pobj->next_row = NULL;
1609 pobj->next_col = NULL;
1611 alloc_and_add_to_ptree(pobj);
1612 *tblh = pobj->ptree_hdl;
1613 return (PICL_SUCCESS);
1617 * Add the properties in <props> array as a row in the table
1618 * Add PICL handles if the table has a valid PICL handle
1621 ptree_add_row_to_table(picl_prophdl_t tblh, int nprops,
1622 const picl_prophdl_t *props)
1624 picl_obj_t *tbl_obj;
1625 picl_obj_t *nodep;
1626 picl_obj_t *lastrow;
1627 picl_obj_t **newrow;
1628 int i;
1629 int err;
1630 picl_obj_t *pobj;
1631 int picl_it;
1633 if (nprops < 1)
1634 return (PICL_INVALIDARG);
1636 newrow = malloc(sizeof (picl_obj_t *) * nprops);
1637 if (newrow == NULL)
1638 return (PICL_FAILURE);
1640 (void) rw_rdlock(&ptree_rwlock); /* Lock ptree */
1642 err = lookup_and_lock_tablenode(WRLOCK_NODE, tblh, &nodep, &tbl_obj);
1643 if (err != PICL_SUCCESS) {
1644 free(newrow);
1645 (void) rw_unlock(&ptree_rwlock); /* Unlock table */
1646 return (err);
1650 * make sure all are either props or table handles
1652 for (i = 0; i < nprops; ++i) {
1653 pobj = newrow[i] = hash_lookup_obj(&ptreetbl, props[i]);
1654 if (pobj == NULL) { /* no object */
1655 err = ptree_hdl_error(props[i]);
1656 break;
1658 if ((!(pobj->obj_type & PICL_OBJ_PROP)) &&
1659 (!(pobj->obj_type & PICL_OBJ_TABLE))) {
1660 err = PICL_NOTPROP;
1661 break;
1663 if (IS_PICLIZED(pobj) || (pobj->prop_table != NULL) ||
1664 (pobj->prop_node != NULL)) {
1665 err = PICL_INVALIDARG;
1666 break;
1670 if (err != PICL_SUCCESS) {
1671 free(newrow);
1672 unlock_node(nodep);
1673 (void) rw_unlock(&ptree_rwlock); /* Unlock table */
1674 return (err);
1678 * Mark all props as table entries, set up row linkages
1680 picl_it = 0;
1681 if (IS_PICLIZED(tbl_obj))
1682 picl_it = 1;
1683 for (i = 0; i < nprops; ++i) {
1684 newrow[i]->obj_type |= PICL_OBJ_TABLEENTRY;
1685 newrow[i]->prop_table = tbl_obj;
1686 newrow[i]->next_prop = NULL;
1687 newrow[i]->next_col = NULL;
1688 if (picl_it)
1689 piclize_obj(newrow[i]);
1690 if (i != nprops - 1)
1691 newrow[i]->next_row = newrow[i+1];
1693 newrow[nprops - 1]->next_row = NULL;
1695 if (tbl_obj->next_row == NULL) { /* add first row */
1696 tbl_obj->next_row = newrow[0];
1697 tbl_obj->next_col = newrow[0];
1698 } else {
1699 lastrow = tbl_obj->next_row;
1700 while (lastrow->next_col != NULL)
1701 lastrow = lastrow->next_col;
1702 i = 0;
1703 while (lastrow != NULL) {
1704 lastrow->next_col = newrow[i];
1705 lastrow = lastrow->next_row;
1706 ++i;
1710 unlock_node(nodep); /* unlock node */
1711 (void) rw_unlock(&ptree_rwlock); /* Unlock ptree */
1712 free(newrow);
1713 return (PICL_SUCCESS);
1717 * This function returns the handle of the next property in the row
1720 ptree_get_next_by_row(picl_prophdl_t proph, picl_prophdl_t *nextrowh)
1722 int err;
1723 picl_obj_t *nodep;
1724 picl_obj_t *propp;
1726 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
1728 nodep = propp = NULL;
1730 * proph could be a table handle or a table entry handle
1731 * Look it up as a table entry handle first, check error code
1732 * to see if it is a table handle
1734 err = lookup_and_lock_tableprop_node(RDLOCK_NODE, proph, &nodep,
1735 &propp);
1736 if (err != PICL_SUCCESS) {
1737 (void) rw_unlock(&ptree_rwlock);
1738 return (err);
1741 if (propp->next_row)
1742 *nextrowh = propp->next_row->ptree_hdl;
1743 else
1744 err = PICL_ENDOFLIST;
1746 unlock_node(nodep); /* unlock node */
1747 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
1748 return (err);
1752 ptree_get_next_by_col(picl_prophdl_t proph, picl_prophdl_t *nextcolh)
1754 int err;
1755 picl_obj_t *propp;
1756 picl_obj_t *nodep;
1758 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
1759 nodep = propp = NULL;
1761 * proph could be a table handle or a table entry handle
1762 * Look it up as a table entry handle first, check error code
1763 * to see if it is a table handle
1765 err = lookup_and_lock_tableprop_node(RDLOCK_NODE, proph, &nodep,
1766 &propp);
1767 if (err != PICL_SUCCESS) {
1768 (void) rw_unlock(&ptree_rwlock);
1769 return (err);
1772 if (propp->next_col)
1773 *nextcolh = propp->next_col->ptree_hdl;
1774 else
1775 err = PICL_ENDOFLIST;
1777 unlock_node(nodep); /* unlock node */
1778 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
1779 return (err);
1783 * This function creates node object and adds its handle to the Ptree
1786 ptree_create_node(const char *name, const char *clname, picl_nodehdl_t *nodeh)
1788 picl_obj_t *pobj;
1789 ptree_propinfo_t propinfo;
1790 picl_prophdl_t phdl;
1791 picl_prophdl_t cphdl;
1792 int err;
1794 if ((name == NULL) || (*name == '\0') ||
1795 (clname == NULL) || (*clname == '\0'))
1796 return (PICL_INVALIDARG);
1798 if ((strlen(name) >= PICL_PROPNAMELEN_MAX) ||
1799 (strlen(clname) >= PICL_CLASSNAMELEN_MAX))
1800 return (PICL_VALUETOOBIG);
1803 * Create the picl object for node
1805 pobj = malloc(sizeof (picl_obj_t));
1806 if (pobj == NULL)
1807 return (PICL_FAILURE);
1808 pobj->obj_type = PICL_OBJ_NODE;
1809 pobj->first_prop = NULL;
1810 pobj->ptree_hdl = PICL_INVALID_PICLHDL;
1811 pobj->picl_hdl = PICL_INVALID_PICLHDL;
1812 pobj->parent_node = NULL;
1813 pobj->sibling_node = NULL;
1814 pobj->child_node = NULL;
1815 pobj->node_classname = strdup(clname);
1816 if (pobj->node_classname == NULL) {
1817 free(pobj);
1818 return (PICL_FAILURE);
1820 (void) rwlock_init(&pobj->node_lock, USYNC_THREAD, NULL);
1822 alloc_and_add_to_ptree(pobj); /* commit the node */
1825 * create name property
1827 propinfo.version = PTREE_PROPINFO_VERSION_1;
1828 propinfo.piclinfo.type = PICL_PTYPE_CHARSTRING;
1829 propinfo.piclinfo.accessmode = PICL_READ;
1830 propinfo.piclinfo.size = strlen(name) + 1;
1831 (void) strcpy(propinfo.piclinfo.name, PICL_PROP_NAME);
1832 propinfo.read = NULL;
1833 propinfo.write = NULL;
1834 err = ptree_create_prop(&propinfo, (const void *)name, &phdl);
1835 if (err != PICL_SUCCESS) {
1836 (void) ptree_destroy_node(pobj->ptree_hdl);
1837 return (err);
1839 err = ptree_add_prop(pobj->ptree_hdl, phdl);
1840 if (err != PICL_SUCCESS) {
1841 (void) ptree_destroy_prop(phdl);
1842 (void) ptree_destroy_node(pobj->ptree_hdl);
1843 return (err);
1847 * create picl classname property
1849 propinfo.piclinfo.size = strlen(clname) + 1;
1850 (void) strcpy(propinfo.piclinfo.name, PICL_PROP_CLASSNAME);
1851 propinfo.read = NULL;
1852 propinfo.write = NULL;
1853 err = ptree_create_prop(&propinfo, (const void *)clname, &cphdl);
1854 if (err != PICL_SUCCESS) {
1855 (void) ptree_destroy_node(pobj->ptree_hdl);
1856 return (err);
1858 err = ptree_add_prop(pobj->ptree_hdl, cphdl);
1859 if (err != PICL_SUCCESS) {
1860 (void) ptree_destroy_prop(cphdl);
1861 (void) ptree_destroy_node(pobj->ptree_hdl);
1862 return (err);
1865 *nodeh = pobj->ptree_hdl;
1866 return (PICL_SUCCESS);
1870 * Destroy a node/subtree freeing up space
1871 * Removed destroyed objects' handles from PTree table
1873 static void
1874 destroy_subtree(picl_obj_t *nodep)
1876 picl_obj_t *iterp;
1877 picl_obj_t *freep;
1878 picl_obj_t *chdp;
1880 if (nodep == NULL)
1881 return;
1883 chdp = nodep->child_node;
1884 while (chdp != NULL) {
1885 freep = chdp;
1886 chdp = chdp->sibling_node;
1887 destroy_subtree(freep);
1891 * Lock the node
1893 (void) lock_obj(WRLOCK_NODE, nodep);
1896 * destroy all properties associated with this node
1898 iterp = nodep->first_prop;
1899 while (iterp != NULL) {
1900 freep = iterp;
1901 iterp = iterp->next_prop;
1902 destroy_propobj(freep);
1905 (void) hash_remove(&ptreetbl, nodep->ptree_hdl);
1906 (void) rwlock_destroy(&nodep->node_lock);
1907 free(nodep->node_classname);
1908 free(nodep);
1912 * This function destroys a previously deleted node/subtree. All the properties
1913 * are freed and removed from the PTree table.
1914 * Only one destroy is in progress at any time.
1917 ptree_destroy_node(picl_nodehdl_t nodeh)
1919 picl_obj_t *nodep;
1920 picl_obj_t *parp;
1921 picl_obj_t *np;
1922 int err;
1924 (void) rw_wrlock(&ptree_rwlock); /* exclusive wrlock ptree */
1925 nodep = NULL;
1926 err = lookup_verify_node_handle(nodeh, &nodep);
1927 if (err != PICL_SUCCESS) {
1928 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
1929 return (err);
1933 * Has this node/subtree been deleted?
1935 if (IS_PICLIZED(nodep)) {
1936 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
1937 return (PICL_CANTDESTROY);
1941 * update parent's child list to repair the tree when
1942 * parent is not null
1944 parp = nodep->parent_node;
1945 if (parp == NULL) { /* root */
1946 destroy_subtree(nodep);
1947 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
1948 return (PICL_SUCCESS);
1951 np = parp->child_node;
1952 if (np == nodep) { /* first child */
1953 parp->child_node = nodep->sibling_node;
1954 } else {
1955 while ((np != NULL) && (np->sibling_node != nodep))
1956 np = np->sibling_node;
1957 if (np != NULL)
1958 np->sibling_node = nodep->sibling_node;
1961 destroy_subtree(nodep);
1962 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
1963 return (PICL_SUCCESS);
1967 * This function deletes a node/subtree from the tree and removes the handles
1968 * from PICL table
1971 ptree_delete_node(picl_nodehdl_t nodeh)
1973 picl_obj_t *nodep;
1974 picl_obj_t *parp;
1975 picl_obj_t *np;
1976 int err;
1978 (void) rw_wrlock(&ptree_rwlock); /* exclusive wrlock ptree */
1980 nodep = NULL;
1981 err = lookup_verify_node_handle(nodeh, &nodep);
1982 if (err != PICL_SUCCESS) {
1983 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
1984 return (err);
1988 * unparent it
1990 parp = nodep->parent_node;
1991 if (parp != NULL) {
1992 np = parp->child_node;
1993 if (np == nodep) /* first child */
1994 parp->child_node = nodep->sibling_node;
1995 else {
1996 while ((np != NULL) && (np->sibling_node != nodep))
1997 np = np->sibling_node;
1998 if (np != NULL)
1999 np->sibling_node = nodep->sibling_node;
2003 nodep->parent_node = NULL;
2004 nodep->sibling_node = NULL;
2006 unpiclize_node(nodep);
2008 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2009 return (PICL_SUCCESS);
2013 * This function adds a node as a child of another node
2016 ptree_add_node(picl_nodehdl_t parh, picl_nodehdl_t chdh)
2018 picl_obj_t *pnodep;
2019 picl_obj_t *cnodep;
2020 picl_obj_t *nodep;
2021 int err;
2023 (void) rw_wrlock(&ptree_rwlock); /* exclusive lock ptree */
2025 pnodep = cnodep = NULL;
2026 err = lookup_verify_node_handle(parh, &pnodep);
2027 if (err != PICL_SUCCESS) {
2028 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2029 return (err);
2032 err = lookup_verify_node_handle(chdh, &cnodep);
2033 if (err != PICL_SUCCESS) {
2034 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2035 return (err);
2038 /* is chdh already a child? */
2039 if (cnodep->parent_node != NULL) {
2040 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2041 return (PICL_CANTPARENT);
2045 * append child to children list
2047 cnodep->parent_node = pnodep;
2048 if (pnodep->child_node == NULL)
2049 pnodep->child_node = cnodep;
2050 else {
2051 for (nodep = pnodep->child_node; nodep->sibling_node != NULL;
2052 nodep = nodep->sibling_node)
2053 continue;
2054 nodep->sibling_node = cnodep;
2058 /* piclize */
2059 if (IS_PICLIZED(pnodep))
2060 piclize_node(cnodep);
2061 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2062 return (PICL_SUCCESS);
2065 static void
2066 copy_propinfo_ver_1(ptree_propinfo_t *pinfo, picl_obj_t *propp)
2068 pinfo->version = propp->pinfo_ver;
2069 pinfo->piclinfo.type = propp->prop_type;
2070 pinfo->piclinfo.accessmode = propp->prop_mode;
2071 pinfo->piclinfo.size = propp->prop_size;
2072 (void) strcpy(pinfo->piclinfo.name, propp->prop_name);
2073 pinfo->read = propp->read_func;
2074 pinfo->write = propp->write_func;
2077 static void
2078 copy_reserved_propinfo_ver_1(ptree_propinfo_t *pinfo, const char *pname)
2080 pinfo->version = PTREE_PROPINFO_VERSION_1;
2081 pinfo->piclinfo.type = PICL_PTYPE_REFERENCE;
2082 pinfo->piclinfo.accessmode = PICL_READ;
2083 pinfo->piclinfo.size = sizeof (picl_nodehdl_t);
2084 (void) strcpy(pinfo->piclinfo.name, pname);
2085 pinfo->read = NULL;
2086 pinfo->write = NULL;
2090 * This function returns the property information to a plug-in
2093 ptree_get_propinfo(picl_prophdl_t proph, ptree_propinfo_t *pinfo)
2095 int err;
2096 picl_obj_t *nodep;
2097 picl_obj_t *propp;
2099 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
2100 nodep = propp = NULL;
2101 err = lookup_and_lock_propnode(RDLOCK_NODE, proph, &nodep, &propp);
2102 if (err != PICL_SUCCESS) {
2103 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2104 return (err);
2107 if (propp->pinfo_ver == PTREE_PROPINFO_VERSION_1)
2108 copy_propinfo_ver_1(pinfo, propp);
2109 else
2110 err = PICL_FAILURE;
2112 unlock_node(nodep); /* unlock node */
2113 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2114 return (err);
2118 * This function returns the property information to a plug-in
2121 xptree_get_propinfo_by_name(picl_nodehdl_t nodeh, const char *pname,
2122 ptree_propinfo_t *pinfo)
2124 int err;
2125 picl_obj_t *nodep;
2126 picl_obj_t *propp;
2128 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
2129 nodep = propp = NULL;
2130 err = lookup_and_lock_node(RDLOCK_NODE, nodeh, &nodep); /* lock node */
2131 if (err != PICL_SUCCESS) {
2132 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2133 return (err);
2136 err = lookup_prop_by_name(nodep, pname, &propp);
2137 if (err != PICL_SUCCESS) {
2138 unlock_node(nodep);
2139 (void) rw_unlock(&ptree_rwlock);
2140 return (err);
2143 if (picl_restricted(pname))
2144 copy_reserved_propinfo_ver_1(pinfo, pname);
2145 else if (propp->pinfo_ver == PTREE_PROPINFO_VERSION_1)
2146 copy_propinfo_ver_1(pinfo, propp);
2147 else
2148 err = PICL_FAILURE;
2150 unlock_node(nodep); /* unlock node */
2151 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2152 return (err);
2156 * This function must be called only after a lookup_prop_by_name() returns
2157 * success and only if picl_restricted() returns true.
2159 static int
2160 read_reserved_propval_and_unlock(picl_obj_t *nodep, const char *pname,
2161 void *vbuf, size_t size)
2163 void *srcp;
2165 if (size != sizeof (picl_nodehdl_t))
2166 return (PICL_VALUETOOBIG);
2168 if (strcmp(pname, PICL_PROP_PARENT) == 0)
2169 srcp = &nodep->parent_node->ptree_hdl;
2170 else if (strcmp(pname, PICL_PROP_CHILD) == 0)
2171 srcp = &nodep->child_node->ptree_hdl;
2172 else if (strcmp(pname, PICL_PROP_PEER) == 0)
2173 srcp = &nodep->sibling_node->ptree_hdl;
2174 else
2175 return (PICL_FAILURE);
2177 (void) memcpy(vbuf, srcp, sizeof (picl_nodehdl_t));
2178 unlock_node(nodep);
2179 (void) rw_unlock(&ptree_rwlock);
2180 return (PICL_SUCCESS);
2184 * Returns the property value in the buffer and releases the node and
2185 * ptree locks.
2186 * For volatile properties, this function releases the locks on ptree
2187 * table and the node before calling the plug-in provided access function
2189 static int
2190 read_propval_and_unlock(picl_obj_t *nodep, picl_obj_t *propp, void *vbuf,
2191 door_cred_t cred)
2193 int err;
2194 int (*volrd)(ptree_rarg_t *arg, void *buf);
2196 err = PICL_SUCCESS;
2197 if (propp->prop_mode & PICL_VOLATILE) {
2198 ptree_rarg_t rarg;
2200 if (nodep)
2201 rarg.nodeh = nodep->ptree_hdl;
2202 else
2203 rarg.nodeh = PICL_INVALID_PICLHDL;
2204 rarg.proph = propp->ptree_hdl;
2205 rarg.cred = cred;
2206 volrd = propp->read_func;
2208 unlock_node(nodep); /* unlock node */
2209 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2211 if (volrd == NULL)
2212 err = PICL_FAILURE;
2213 else
2214 err = (volrd)(&rarg, vbuf);
2215 return (err);
2216 } else if (propp->prop_type == PICL_PTYPE_CHARSTRING)
2217 (void) strlcpy(vbuf, propp->prop_val, propp->prop_size);
2218 else
2219 (void) memcpy(vbuf, propp->prop_val, propp->prop_size);
2221 unlock_node(nodep);
2222 (void) rw_unlock(&ptree_rwlock);
2223 return (err);
2227 xptree_get_propval_with_cred(picl_prophdl_t proph, void *vbuf, size_t size,
2228 door_cred_t cred)
2230 picl_obj_t *propp;
2231 picl_obj_t *nodep;
2232 int err;
2234 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
2235 nodep = propp = NULL;
2236 err = lookup_and_lock_propnode(RDLOCK_NODE, proph, &nodep, &propp);
2237 if (err != PICL_SUCCESS) {
2238 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2239 return (err);
2242 err = check_propsize(PROP_READ, propp, size);
2243 if (err != PICL_SUCCESS) {
2244 unlock_node(nodep); /* unlock node */
2245 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2246 return (err);
2249 return (read_propval_and_unlock(nodep, propp, vbuf, cred));
2253 * This function gets the credentials and calls get_propval_with_cred.
2256 ptree_get_propval(picl_prophdl_t proph, void *vbuf, size_t size)
2258 return (xptree_get_propval_with_cred(proph, vbuf, size, picld_cred));
2262 * This function retrieves a property's value by by its name
2263 * For volatile properties, the locks on ptree and node are released
2264 * before calling the plug-in provided access function
2267 xptree_get_propval_by_name_with_cred(picl_nodehdl_t nodeh, const char *pname,
2268 void *vbuf, size_t size, door_cred_t cred)
2270 picl_obj_t *nodep;
2271 picl_obj_t *propp;
2272 int err;
2274 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
2276 nodep = NULL;
2277 err = lookup_and_lock_node(RDLOCK_NODE, nodeh, &nodep); /* lock node */
2278 if (err != PICL_SUCCESS) {
2279 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2280 return (err);
2283 err = lookup_prop_by_name(nodep, pname, &propp);
2284 if (err != PICL_SUCCESS) {
2285 unlock_node(nodep);
2286 (void) rw_unlock(&ptree_rwlock);
2287 return (err);
2290 if (picl_restricted(pname))
2291 return (read_reserved_propval_and_unlock(nodep, pname, vbuf,
2292 size));
2294 err = check_propsize(PROP_READ, propp, size);
2295 if (err != PICL_SUCCESS) {
2296 unlock_node(nodep);
2297 (void) rw_unlock(&ptree_rwlock);
2298 return (err);
2301 return (read_propval_and_unlock(nodep, propp, vbuf, cred));
2305 * This function is used by plugins to get a value of a property
2306 * looking it up by its name.
2309 ptree_get_propval_by_name(picl_nodehdl_t nodeh, const char *pname, void *vbuf,
2310 size_t size)
2312 return (xptree_get_propval_by_name_with_cred(nodeh, pname, vbuf, size,
2313 picld_cred));
2317 * This function updates a property's value.
2318 * For volatile properties, the locks on the node and the ptree table
2319 * are released before calling the plug-in provided access function.
2321 static int
2322 write_propval_and_unlock(picl_obj_t *nodep, picl_obj_t *propp, const void *vbuf,
2323 size_t size, door_cred_t cred)
2325 int err;
2326 int (*volwr)(ptree_warg_t *arg, const void *buf);
2328 err = PICL_SUCCESS;
2329 if (propp->prop_mode & PICL_VOLATILE) {
2330 ptree_warg_t warg;
2332 if (nodep)
2333 warg.nodeh = nodep->ptree_hdl;
2334 else
2335 warg.nodeh = PICL_INVALID_PICLHDL;
2336 warg.proph = propp->ptree_hdl;
2337 warg.cred = cred;
2338 volwr = propp->write_func;
2340 unlock_node(nodep); /* unlock node */
2341 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2343 if (volwr == NULL)
2344 err = PICL_FAILURE;
2345 else
2346 err = (volwr)(&warg, vbuf);
2347 return (err);
2348 } else
2349 (void) memcpy(propp->prop_val, vbuf, size);
2351 unlock_node(nodep); /* unlock node */
2352 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2353 return (err);
2357 xptree_update_propval_with_cred(picl_prophdl_t proph, const void *vbuf,
2358 size_t size, door_cred_t cred)
2360 picl_obj_t *nodep;
2361 picl_obj_t *propp;
2362 int err;
2364 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
2365 nodep = propp = NULL;
2366 err = lookup_and_lock_propnode(WRLOCK_NODE, proph, &nodep, &propp);
2367 if (err != PICL_SUCCESS) {
2368 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2369 return (err);
2372 err = check_propsize(PROP_WRITE, propp, size);
2373 if (err != PICL_SUCCESS) {
2374 unlock_node(nodep); /* unlock node */
2375 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2376 return (err);
2379 return (write_propval_and_unlock(nodep, propp, vbuf, size, cred));
2383 * Ptree function used by plug-ins to update a property's value
2384 * calls update_propval_with_cred(), which releases locks for volatile props
2387 ptree_update_propval(picl_prophdl_t proph, const void *vbuf, size_t size)
2389 return (xptree_update_propval_with_cred(proph, vbuf, size, picld_cred));
2393 * This function writes/updates a property's value by looking it up
2394 * by its name.
2395 * For volatile properties this function releases the locks on the
2396 * node and the ptree table.
2399 xptree_update_propval_by_name_with_cred(picl_nodehdl_t nodeh, const char *pname,
2400 const void *vbuf, size_t size, door_cred_t cred)
2402 picl_obj_t *nodep;
2403 picl_obj_t *propp;
2404 int err;
2406 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
2407 nodep = NULL;
2408 err = lookup_and_lock_node(WRLOCK_NODE, nodeh, &nodep); /* lock node */
2409 if (err != PICL_SUCCESS) {
2410 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2411 return (err);
2414 if (picl_restricted(pname)) {
2415 unlock_node(nodep);
2416 (void) rw_unlock(&ptree_rwlock);
2417 return (PICL_RESERVEDNAME);
2420 err = lookup_prop_by_name(nodep, pname, &propp);
2421 if (err != PICL_SUCCESS) {
2422 unlock_node(nodep);
2423 (void) rw_unlock(&ptree_rwlock);
2424 return (err);
2427 err = check_propsize(PROP_WRITE, propp, size);
2428 if (err != PICL_SUCCESS) {
2429 unlock_node(nodep);
2430 (void) rw_unlock(&ptree_rwlock);
2431 return (err);
2434 return (write_propval_and_unlock(nodep, propp, vbuf, size, cred));
2438 * This function updates the value of a property specified by its name
2441 ptree_update_propval_by_name(picl_nodehdl_t nodeh, const char *pname,
2442 const void *vbuf, size_t size)
2444 return (xptree_update_propval_by_name_with_cred(nodeh, pname, vbuf,
2445 size, picld_cred));
2449 * This function retrieves the handle of a property by its name
2452 ptree_get_prop_by_name(picl_nodehdl_t nodeh, const char *pname,
2453 picl_prophdl_t *proph)
2455 picl_obj_t *nodep;
2456 picl_obj_t *propp;
2457 int err;
2459 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
2460 nodep = NULL;
2461 err = lookup_and_lock_node(RDLOCK_NODE, nodeh, &nodep); /* lock node */
2462 if (err != PICL_SUCCESS) {
2463 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2464 return (err);
2467 if (picl_restricted(pname)) {
2468 err = PICL_RESERVEDNAME;
2469 unlock_node(nodep); /* unlock node */
2470 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2471 return (err);
2474 err = lookup_prop_by_name(nodep, pname, &propp);
2475 if (err == PICL_SUCCESS)
2476 *proph = propp->ptree_hdl;
2478 unlock_node(nodep); /* unlock node */
2479 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2480 return (err);
2484 * This function returns the handle of the first property
2487 ptree_get_first_prop(picl_nodehdl_t nodeh, picl_prophdl_t *proph)
2489 picl_obj_t *pobj;
2490 int err;
2492 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
2493 pobj = NULL;
2494 err = lookup_and_lock_node(RDLOCK_NODE, nodeh, &pobj); /* lock node */
2495 if (err != PICL_SUCCESS) {
2496 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2497 return (err);
2500 if (pobj->first_prop)
2501 *proph = pobj->first_prop->ptree_hdl;
2502 else
2503 err = PICL_ENDOFLIST;
2505 unlock_node(pobj); /* unlock node */
2506 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2507 return (err);
2511 * This function returns the handle of next property in the list
2514 ptree_get_next_prop(picl_prophdl_t proph, picl_prophdl_t *nextproph)
2516 picl_obj_t *nodep;
2517 picl_obj_t *propp;
2518 int err;
2520 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
2521 nodep = propp = NULL;
2522 err = lookup_and_lock_propnode(RDLOCK_NODE, proph, &nodep, &propp);
2523 if (err != PICL_SUCCESS) {
2524 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2525 return (err);
2528 if (propp->next_prop) {
2529 *nextproph = propp->next_prop->ptree_hdl;
2530 } else
2531 err = PICL_ENDOFLIST;
2533 unlock_node(nodep); /* unlock node */
2534 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2535 return (err);
2539 * These functions are called by ptree_get_node_by_path()
2540 * Append a prop expression entry to the list
2542 static prop_list_t *
2543 append_entry_to_list(prop_list_t *el, prop_list_t *list)
2545 prop_list_t *ptr;
2547 if (el == NULL)
2548 return (list);
2550 if (list == NULL) {
2551 list = el;
2552 return (list);
2556 * Add it to the end of list
2558 ptr = list;
2560 while (ptr->next != NULL)
2561 ptr = ptr->next;
2563 ptr->next = el;
2565 return (list);
2569 * Free the property expression list
2571 static void
2572 free_list(prop_list_t *list)
2574 prop_list_t *ptr;
2575 prop_list_t *tmp;
2577 for (ptr = list; ptr != NULL; ptr = tmp) {
2578 tmp = ptr->next;
2579 free(ptr);
2583 static int
2584 parse_prl(char *prl, char **name, char **baddr, prop_list_t **plist)
2586 char *propptr;
2587 char *ptr;
2588 char *pname;
2589 char *pval;
2590 prop_list_t *el;
2592 if (prl == NULL)
2593 return (PICL_FAILURE);
2595 if ((prl[0] == '@') || (prl[0] == '?'))
2596 return (PICL_FAILURE);
2598 *name = prl;
2601 * get property expression
2603 ptr = strchr(prl, '?');
2605 if (ptr != NULL) {
2606 *ptr = '\0';
2607 propptr = ptr + 1;
2608 } else
2609 propptr = NULL;
2612 * get bus value
2614 ptr = strchr(prl, '@');
2616 if (ptr != NULL) {
2617 *ptr = '\0';
2618 *baddr = ptr + 1;
2619 if (strlen(*baddr) == 0) /* no bus value after @ */
2620 return (PICL_FAILURE);
2624 * create the prop list
2626 while (propptr != NULL) {
2627 pname = propptr;
2628 pval = NULL;
2630 ptr = strchr(propptr, '?');
2632 if (ptr != NULL) { /* more ?<prop>=<propval> */
2633 *ptr = '\0';
2634 propptr = ptr + 1;
2635 } else
2636 propptr = NULL;
2638 if (strlen(pname) == 0) /* no prop exp after ? */
2639 return (PICL_FAILURE);
2641 ptr = strchr(pname, '=');
2642 if (ptr != NULL) { /* not void prop */
2643 *ptr = '\0';
2644 pval = ptr + 1;
2646 * <prop>= is treated as void property
2648 if (strlen(pval) == 0)
2649 pval = NULL;
2652 el = (prop_list_t *)malloc(sizeof (prop_list_t));
2653 el->pname = pname;
2654 el->pval = pval;
2655 el->next = NULL;
2656 *plist = append_entry_to_list(el, *plist);
2659 return (PICL_SUCCESS);
2662 static int
2663 prop_match(ptree_propinfo_t pinfo, void *vbuf, char *val)
2665 int8_t cval;
2666 uint8_t ucval;
2667 int16_t sval;
2668 uint16_t usval;
2669 int32_t intval;
2670 uint32_t uintval;
2671 int64_t llval;
2672 uint64_t ullval;
2673 float fval;
2674 double dval;
2676 switch (pinfo.piclinfo.type) {
2677 case PICL_PTYPE_CHARSTRING:
2678 if (strcasecmp(pinfo.piclinfo.name, PICL_PROP_CLASSNAME) == 0) {
2679 if (strcmp(val, PICL_CLASS_PICL) == 0)
2680 return (1);
2682 if (strcmp(val, (char *)vbuf) == 0)
2683 return (1);
2684 else
2685 return (0);
2686 case PICL_PTYPE_INT:
2687 switch (pinfo.piclinfo.size) {
2688 case sizeof (int8_t):
2689 cval = (int8_t)strtol(val, (char **)NULL, 0);
2690 return (cval == *(char *)vbuf);
2691 case sizeof (int16_t):
2692 sval = (int16_t)strtol(val, (char **)NULL, 0);
2693 return (sval == *(int16_t *)vbuf);
2694 case sizeof (int32_t):
2695 intval = (int32_t)strtol(val, (char **)NULL, 0);
2696 return (intval == *(int32_t *)vbuf);
2697 case sizeof (int64_t):
2698 llval = strtoll(val, (char **)NULL, 0);
2699 return (llval == *(int64_t *)vbuf);
2700 default:
2701 return (0);
2703 case PICL_PTYPE_UNSIGNED_INT:
2704 switch (pinfo.piclinfo.size) {
2705 case sizeof (uint8_t):
2706 ucval = (uint8_t)strtoul(val, (char **)NULL, 0);
2707 return (ucval == *(uint8_t *)vbuf);
2708 case sizeof (uint16_t):
2709 usval = (uint16_t)strtoul(val, (char **)NULL, 0);
2710 return (usval == *(uint16_t *)vbuf);
2711 case sizeof (uint32_t):
2712 uintval = (uint32_t)strtoul(val, (char **)NULL, 0);
2713 return (uintval == *(uint32_t *)vbuf);
2714 case sizeof (uint64_t):
2715 ullval = strtoull(val, (char **)NULL, 0);
2716 return (ullval == *(uint64_t *)vbuf);
2717 default:
2718 return (0);
2720 case PICL_PTYPE_FLOAT:
2721 switch (pinfo.piclinfo.size) {
2722 case sizeof (float):
2723 fval = (float)strtod(val, (char **)NULL);
2724 return (fval == *(float *)vbuf);
2725 case sizeof (double):
2726 dval = strtod(val, (char **)NULL);
2727 return (dval == *(double *)vbuf);
2728 default:
2729 return (0);
2731 case PICL_PTYPE_VOID:
2732 case PICL_PTYPE_TIMESTAMP:
2733 case PICL_PTYPE_TABLE:
2734 case PICL_PTYPE_REFERENCE:
2735 case PICL_PTYPE_BYTEARRAY:
2736 case PICL_PTYPE_UNKNOWN:
2737 default:
2738 return (0);
2742 static int
2743 check_propval(picl_nodehdl_t nodeh, char *pname, char *pval)
2745 int err;
2746 picl_prophdl_t proph;
2747 ptree_propinfo_t pinfo;
2748 void *vbuf;
2750 err = ptree_get_prop_by_name(nodeh, pname, &proph);
2751 if (err != PICL_SUCCESS)
2752 return (err);
2754 err = ptree_get_propinfo(proph, &pinfo);
2755 if (err != PICL_SUCCESS)
2756 return (err);
2758 if (pval == NULL) { /* void type */
2759 if (pinfo.piclinfo.type != PICL_PTYPE_VOID)
2760 return (PICL_FAILURE);
2761 } else {
2762 vbuf = alloca(pinfo.piclinfo.size);
2763 if (vbuf == NULL)
2764 return (PICL_FAILURE);
2765 err = ptree_get_propval(proph, vbuf,
2766 pinfo.piclinfo.size);
2767 if (err != PICL_SUCCESS)
2768 return (err);
2770 if (!prop_match(pinfo, vbuf, pval))
2771 return (PICL_FAILURE);
2773 return (PICL_SUCCESS);
2776 static int
2777 get_child_by_path(picl_nodehdl_t rooth, char *prl,
2778 picl_nodehdl_t *nodeh, char *pname)
2780 picl_nodehdl_t chdh;
2781 int err;
2782 char *nameval;
2783 char *nodename;
2784 char *path;
2785 char *baddr;
2786 char *busval;
2787 prop_list_t *plist;
2788 prop_list_t *ptr;
2790 if (prl == NULL)
2791 return (PICL_FAILURE);
2793 path = strdupa(prl);
2794 if (path == NULL)
2795 return (PICL_FAILURE);
2797 plist = NULL;
2798 nodename = NULL;
2799 baddr = NULL;
2801 err = parse_prl(path, &nodename, &baddr, &plist);
2802 if (err != PICL_SUCCESS) {
2803 free_list(plist);
2804 return (err);
2807 if (nodename == NULL)
2808 return (PICL_FAILURE);
2810 nameval = alloca(strlen(nodename) + 1);
2811 if (nameval == NULL) {
2812 free_list(plist);
2813 return (PICL_FAILURE);
2816 if (baddr != NULL) {
2817 busval = alloca(strlen(baddr) + 1);
2818 if (busval == NULL) {
2819 free_list(plist);
2820 return (PICL_FAILURE);
2824 for (err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh,
2825 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND;
2826 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
2827 sizeof (picl_nodehdl_t))) {
2828 if (err != PICL_SUCCESS) {
2829 free_list(plist);
2830 return (PICL_FAILURE);
2834 * compare name
2836 if ((strcmp(pname, PICL_PROP_CLASSNAME) != 0) ||
2837 (strcmp(nodename, PICL_CLASS_PICL) != 0)) {
2838 err = ptree_get_propval_by_name(chdh, pname,
2839 nameval, (strlen(nodename) + 1));
2841 if (err != PICL_SUCCESS)
2842 continue;
2843 if (strcmp(nameval, nodename) != 0)
2844 continue;
2848 * compare device address with bus-addr prop first
2849 * then with UnitAddress property
2851 if (baddr != NULL) { /* compare bus-addr prop */
2852 if ((ptree_get_propval_by_name(chdh, PICL_PROP_BUS_ADDR,
2853 busval, (strlen(baddr) + 1)) != PICL_SUCCESS) &&
2854 (ptree_get_propval_by_name(chdh,
2855 PICL_PROP_UNIT_ADDRESS, busval,
2856 (strlen(baddr) + 1)) != PICL_SUCCESS))
2857 continue;
2859 if (strcmp(busval, baddr) != 0)
2860 continue; /* not match */
2863 if (plist == NULL) { /* no prop expression */
2864 *nodeh = chdh;
2865 return (PICL_SUCCESS);
2869 * compare the property expression list
2871 ptr = plist;
2873 while (ptr != NULL) {
2874 err = check_propval(chdh, ptr->pname, ptr->pval);
2875 if (err != PICL_SUCCESS)
2876 break;
2878 ptr = ptr->next;
2880 if (ptr == NULL) {
2881 *nodeh = chdh;
2882 free_list(plist);
2883 return (PICL_SUCCESS);
2886 free_list(plist);
2887 return (PICL_NOTNODE);
2891 * This functions returns the handle of node specified by its path
2894 ptree_get_node_by_path(const char *piclprl, picl_nodehdl_t *handle)
2896 picl_nodehdl_t rooth;
2897 picl_nodehdl_t chdh;
2898 char *path;
2899 char *ptr;
2900 char *defprop;
2901 char *tokindex;
2902 int err;
2903 int len;
2904 int npflg; /* namepath flag */
2907 path = strdupa(piclprl);
2908 if (path == NULL)
2909 return (PICL_FAILURE);
2911 npflg = 1; /* default */
2912 defprop = path;
2913 if (path[0] == '/') {
2914 ptr = &path[1];
2915 } else if ((tokindex = strchr(path, ':')) != NULL) {
2916 *tokindex = '\0';
2917 ++tokindex;
2918 if (*tokindex == '/')
2919 ptr = tokindex + 1;
2920 else
2921 return (PICL_NOTNODE);
2922 npflg = 0;
2923 } else
2924 return (PICL_NOTNODE);
2926 err = ptree_get_root(&rooth);
2927 if (err != PICL_SUCCESS)
2928 return (err);
2930 for (chdh = rooth, tokindex = strchr(ptr, '/');
2931 tokindex != NULL;
2932 ptr = tokindex + 1, tokindex = strchr(ptr, '/')) {
2933 *tokindex = '\0';
2934 if (npflg)
2935 err = get_child_by_path(chdh, ptr, &chdh,
2936 PICL_PROP_NAME);
2937 else
2938 err = get_child_by_path(chdh, ptr, &chdh,
2939 defprop);
2941 if (err != PICL_SUCCESS)
2942 return (err);
2946 * check if last token is empty or not
2947 * eg. /a/b/c/ or /a/b/c
2949 if (*ptr == '\0') {
2950 *handle = chdh;
2951 return (PICL_SUCCESS);
2954 len = strcspn(ptr, " \t\n");
2955 if (len == 0) {
2956 *handle = chdh;
2957 return (PICL_SUCCESS);
2960 ptr[len] = '\0';
2961 if (npflg)
2962 err = get_child_by_path(chdh, ptr, &chdh, PICL_PROP_NAME);
2963 else
2964 err = get_child_by_path(chdh, ptr, &chdh, defprop);
2966 if (err != PICL_SUCCESS)
2967 return (err);
2969 *handle = chdh;
2970 return (PICL_SUCCESS);
2974 * Initialize propinfo
2977 ptree_init_propinfo(ptree_propinfo_t *infop, int version, int ptype, int pmode,
2978 size_t psize, char *pname, int (*readfn)(ptree_rarg_t *, void *),
2979 int (*writefn)(ptree_warg_t *, const void *))
2981 if (version != PTREE_PROPINFO_VERSION_1)
2982 return (PICL_NOTSUPPORTED);
2983 if ((infop == NULL) || (pname == NULL))
2984 return (PICL_INVALIDARG);
2985 infop->version = version;
2986 infop->piclinfo.type = ptype;
2987 infop->piclinfo.accessmode = pmode;
2988 infop->piclinfo.size = psize;
2989 infop->read = readfn;
2990 infop->write = writefn;
2991 (void) strlcpy(infop->piclinfo.name, pname, PICL_PROPNAMELEN_MAX);
2992 return (PICL_SUCCESS);
2996 * Creates a property, adds it to the node, and returns the property
2997 * handle to the caller if successful and proph is not NULL
3000 ptree_create_and_add_prop(picl_nodehdl_t nodeh, ptree_propinfo_t *infop,
3001 void *vbuf, picl_prophdl_t *proph)
3003 int err;
3004 picl_prophdl_t tmph;
3006 err = ptree_create_prop(infop, vbuf, &tmph);
3007 if (err != PICL_SUCCESS)
3008 return (err);
3009 err = ptree_add_prop(nodeh, tmph);
3010 if (err != PICL_SUCCESS) {
3011 (void) ptree_destroy_prop(tmph);
3012 return (err);
3014 if (proph)
3015 *proph = tmph;
3016 return (PICL_SUCCESS);
3020 * Creates a node, adds it to its parent node, and returns the node
3021 * handle to the caller if successful
3024 ptree_create_and_add_node(picl_nodehdl_t rooth, const char *name,
3025 const char *classname, picl_nodehdl_t *nodeh)
3027 picl_nodehdl_t tmph;
3028 int err;
3030 err = ptree_create_node(name, classname, &tmph);
3032 if (err != PICL_SUCCESS)
3033 return (err);
3035 err = ptree_add_node(rooth, tmph);
3036 if (err != PICL_SUCCESS) {
3037 (void) ptree_destroy_node(tmph);
3038 return (err);
3041 *nodeh = tmph;
3042 return (PICL_SUCCESS);
3047 * recursively visit all nodes
3049 static int
3050 do_walk(picl_nodehdl_t rooth, const char *classname,
3051 void *c_args, int (*callback_fn)(picl_nodehdl_t hdl, void *args))
3053 int err;
3054 picl_nodehdl_t chdh;
3055 char classval[PICL_CLASSNAMELEN_MAX];
3057 err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh,
3058 sizeof (chdh));
3059 while (err == PICL_SUCCESS) {
3060 err = ptree_get_propval_by_name(chdh, PICL_PROP_CLASSNAME,
3061 classval, sizeof (classval));
3062 if (err != PICL_SUCCESS)
3063 return (err);
3065 if ((classname == NULL) || (strcmp(classname, classval) == 0)) {
3066 err = callback_fn(chdh, c_args);
3067 if (err != PICL_WALK_CONTINUE)
3068 return (err);
3071 if ((err = do_walk(chdh, classname, c_args, callback_fn)) !=
3072 PICL_WALK_CONTINUE)
3073 return (err);
3075 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
3076 sizeof (chdh));
3078 if (err == PICL_PROPNOTFOUND) /* end of a branch */
3079 return (PICL_WALK_CONTINUE);
3080 return (err);
3085 * This function visits all the nodes in the subtree rooted at <rooth>.
3086 * For each node that matches the class name specified, the callback
3087 * function is invoked.
3090 ptree_walk_tree_by_class(picl_nodehdl_t rooth, const char *classname,
3091 void *c_args, int (*callback_fn)(picl_nodehdl_t hdl, void *args))
3093 int err;
3095 if (callback_fn == NULL)
3096 return (PICL_INVALIDARG);
3097 err = do_walk(rooth, classname, c_args, callback_fn);
3098 if ((err == PICL_WALK_CONTINUE) || (err == PICL_WALK_TERMINATE))
3099 return (PICL_SUCCESS);
3100 return (err);
3103 static int
3104 compare_propval(picl_nodehdl_t nodeh, char *pname, picl_prop_type_t ptype,
3105 void *pval, size_t valsize)
3107 int err;
3108 picl_prophdl_t proph;
3109 ptree_propinfo_t propinfo;
3110 void *vbuf;
3112 err = ptree_get_prop_by_name(nodeh, pname, &proph);
3113 if (err != PICL_SUCCESS)
3114 return (0);
3115 err = ptree_get_propinfo(proph, &propinfo);
3116 if (err != PICL_SUCCESS)
3117 return (0);
3118 if (propinfo.piclinfo.type != ptype)
3119 return (0);
3120 if (propinfo.piclinfo.type == PICL_PTYPE_VOID)
3121 return (1);
3122 if (pval == NULL)
3123 return (0);
3124 if (valsize > propinfo.piclinfo.size)
3125 return (0);
3126 vbuf = alloca(propinfo.piclinfo.size);
3127 if (vbuf == NULL)
3128 return (0);
3129 err = ptree_get_propval(proph, vbuf, propinfo.piclinfo.size);
3130 if (err != PICL_SUCCESS)
3131 return (0);
3132 if (memcmp(vbuf, pval, valsize) == 0)
3133 return (1);
3134 return (0);
3139 * This function traverses the subtree and finds a node that has a property
3140 * of the specified name and type with the specified value.
3141 * The matched node in the tree is returned in retnodeh. If there is
3142 * no node with that property, then PICL_NODENOTFOUND is returned.
3145 ptree_find_node(picl_nodehdl_t rooth, char *pname, picl_prop_type_t ptype,
3146 void *pval, size_t valsize, picl_nodehdl_t *retnodeh)
3148 int err;
3149 picl_nodehdl_t chdh;
3151 if (pname == NULL)
3152 return (PICL_INVALIDARG);
3153 err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh,
3154 sizeof (chdh));
3156 while (err == PICL_SUCCESS) {
3157 if (compare_propval(chdh, pname, ptype, pval, valsize)) {
3158 if (retnodeh)
3159 *retnodeh = chdh;
3160 return (PICL_SUCCESS);
3163 err = ptree_find_node(chdh, pname, ptype, pval, valsize,
3164 retnodeh);
3165 if (err != PICL_NODENOTFOUND)
3166 return (err);
3168 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
3169 sizeof (chdh));
3171 if (err == PICL_PROPNOTFOUND)
3172 return (PICL_NODENOTFOUND);
3173 return (err);
3177 * This function gets the frutree parent for a given node.
3178 * Traverse up the tree and look for the following properties:
3179 * Frutree parent reference properties:
3180 * _fru_parent
3181 * _location_parent
3182 * _port_parent
3183 * If the frutree reference property is found, return its value.
3184 * Else, return the handle of /frutree/chassis.
3187 ptree_get_frutree_parent(picl_nodehdl_t nodeh, picl_nodehdl_t *fruh)
3189 int err;
3190 picl_nodehdl_t nparh;
3191 picl_nodehdl_t fruparh;
3193 err = PICL_SUCCESS;
3194 nparh = nodeh;
3195 while (err == PICL_SUCCESS) {
3196 err = ptree_get_propval_by_name(nparh, PICL_REFPROP_FRU_PARENT,
3197 &fruparh, sizeof (fruparh));
3198 if (err == PICL_SUCCESS) {
3199 *fruh = fruparh;
3200 return (PICL_SUCCESS);
3202 err = ptree_get_propval_by_name(nparh,
3203 PICL_REFPROP_LOC_PARENT, &fruparh, sizeof (fruparh));
3204 if (err == PICL_SUCCESS) {
3205 *fruh = fruparh;
3206 return (PICL_SUCCESS);
3208 err = ptree_get_propval_by_name(nparh, PICL_REFPROP_PORT_PARENT,
3209 &fruparh, sizeof (fruparh));
3210 if (err == PICL_SUCCESS) {
3211 *fruh = fruparh;
3212 return (PICL_SUCCESS);
3215 err = ptree_get_propval_by_name(nparh, PICL_PROP_PARENT, &nparh,
3216 sizeof (nparh));
3219 if (err == PICL_PROPNOTFOUND) { /* return /frutree/chassis handle */
3220 err = ptree_get_node_by_path(PICL_FRUTREE_CHASSIS, &fruparh);
3221 if (err == PICL_SUCCESS) {
3222 *fruh = fruparh;
3223 return (PICL_SUCCESS);
3226 return (err);
3230 * This function is called by plug-ins to register with the daemon
3233 picld_plugin_register(picld_plugin_reg_t *regp)
3235 picld_plugin_reg_list_t *el;
3236 picld_plugin_reg_list_t *tmp;
3238 if (regp == NULL)
3239 return (PICL_FAILURE);
3241 if (regp->version != PICLD_PLUGIN_VERSION_1)
3242 return (PICL_NOTSUPPORTED);
3244 el = malloc(sizeof (picld_plugin_reg_list_t));
3245 if (el == NULL)
3246 return (PICL_FAILURE);
3247 el->reg.version = regp->version;
3248 el->reg.critical = regp->critical;
3249 if (regp->name)
3250 el->reg.name = strdup(regp->name);
3251 if (el->reg.name == NULL)
3252 return (PICL_FAILURE);
3254 el->reg.plugin_init = regp->plugin_init;
3255 el->reg.plugin_fini = regp->plugin_fini;
3256 el->next = NULL;
3258 if (plugin_reg_list == NULL) {
3259 plugin_reg_list = el;
3260 } else { /* add to end */
3261 tmp = plugin_reg_list;
3262 while (tmp->next != NULL)
3263 tmp = tmp->next;
3264 tmp->next = el;
3267 return (PICL_SUCCESS);
3271 * Call fini routines of the registered plugins
3273 static void
3274 plugin_fini(picld_plugin_reg_list_t *p)
3276 if (p == NULL)
3277 return;
3279 plugin_fini(p->next);
3280 if (p->reg.plugin_fini)
3281 (p->reg.plugin_fini)();
3285 * Create PICL Tree
3288 static void
3289 init_plugin_reg_list(void)
3291 plugin_reg_list = NULL;
3294 static int
3295 picltree_set_root(picl_nodehdl_t rooth)
3297 picl_obj_t *pobj;
3298 int err;
3300 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
3301 pobj = NULL;
3302 err = lookup_and_lock_node(RDLOCK_NODE, rooth, &pobj); /* lock node */
3303 if (err != PICL_SUCCESS) {
3304 (void) rw_unlock(&ptree_rwlock);
3305 return (PICL_FAILURE);
3307 piclize_node(pobj);
3308 picl_root_obj = pobj;
3309 ptree_root_hdl = pobj->ptree_hdl;
3310 unlock_node(pobj); /* unlock node */
3311 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
3312 return (PICL_SUCCESS);
3315 static int
3316 picltree_init(void)
3318 (void) rwlock_init(&ptree_rwlock, USYNC_THREAD, NULL);
3319 (void) rwlock_init(&picltbl_rwlock, USYNC_THREAD, NULL);
3321 if (hash_init(&picltbl) < 0)
3322 return (PICL_FAILURE);
3323 if (hash_init(&ptreetbl) < 0)
3324 return (PICL_FAILURE);
3326 if (pthread_mutex_init(&ptreehdl_lock, NULL) != 0)
3327 return (PICL_FAILURE);
3329 if (pthread_mutex_init(&piclhdl_lock, NULL) != 0)
3330 return (PICL_FAILURE);
3332 if (pthread_mutex_init(&evtq_lock, NULL) != 0)
3333 return (PICL_FAILURE);
3334 if (pthread_cond_init(&evtq_cv, NULL) != 0)
3335 return (PICL_FAILURE);
3336 if (pthread_mutex_init(&evthandler_lock, NULL) != 0)
3337 return (PICL_FAILURE);
3339 picl_root_obj = NULL;
3340 eventqp = NULL;
3341 evt_handlers = NULL;
3342 ptree_root_hdl = PICL_INVALID_PICLHDL;
3344 return (PICL_SUCCESS);
3347 static void
3348 add_unique_plugin_to_list(char *path, char *name)
3350 picld_plugin_desc_t *pl;
3351 picld_plugin_desc_t *tmp;
3353 pl = plugin_desc;
3354 while (pl != NULL) {
3355 if (strcmp(pl->libname, name) == 0)
3356 return;
3357 else
3358 pl = pl->next;
3361 pl = malloc(sizeof (picld_plugin_desc_t));
3362 if (pl == NULL)
3363 return;
3365 pl->libname = strdup(name);
3366 if (pl->libname == NULL)
3367 return;
3369 if (asprintf(&pl->pathname, "%s/%s", path, name) < 0)
3370 pl->pathname = NULL;
3371 if (pl->pathname == NULL)
3372 return;
3374 pl->next = NULL;
3376 if (plugin_desc == NULL)
3377 plugin_desc = pl;
3378 else {
3379 tmp = plugin_desc;
3380 while (tmp->next != NULL)
3381 tmp = tmp->next;
3382 tmp->next = pl;
3386 static void
3387 get_plugins_from_dir(char *dirname)
3389 struct dirent *ent;
3390 DIR *dir;
3391 int len;
3392 int solen = strlen(SO_VERS) + 1;
3394 if ((dir = opendir(dirname)) == NULL)
3395 return;
3397 while ((ent = readdir(dir)) != NULL) {
3398 if ((strcmp(ent->d_name, ".") == 0) ||
3399 (strcmp(ent->d_name, "..") == 0))
3400 continue;
3402 len = strlen(ent->d_name) + 1;
3403 if (len < solen)
3404 continue;
3406 if (strcmp(ent->d_name + (len - solen), SO_VERS) == 0)
3407 add_unique_plugin_to_list(dirname, ent->d_name);
3410 (void) closedir(dir);
3414 static void
3415 init_plugin_list(void)
3417 get_plugins_from_dir(PICLD_PLAT_PLUGIN_DIR);
3418 get_plugins_from_dir(PICLD_COMMON_PLUGIN_DIR);
3421 static void
3422 load_plugins(void)
3424 picld_plugin_desc_t *pl;
3426 pl = plugin_desc;
3427 while (pl != NULL) {
3428 pl->dlh = dlopen(pl->pathname, RTLD_LAZY|RTLD_LOCAL);
3429 if (pl->dlh == NULL) {
3430 syslog(LOG_CRIT, dlerror());
3431 return;
3433 pl = pl->next;
3439 static int
3440 add_root_props(picl_nodehdl_t rooth)
3442 int err;
3443 picl_prophdl_t proph;
3444 ptree_propinfo_t pinfo;
3445 float picl_vers;
3447 #define PICL_PROP_PICL_VERSION "PICLVersion"
3448 #define PICL_VERSION 1.1
3450 err = ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION_1,
3451 PICL_PTYPE_FLOAT, PICL_READ, sizeof (picl_vers),
3452 PICL_PROP_PICL_VERSION, NULL, NULL);
3453 if (err != PICL_SUCCESS)
3454 return (err);
3456 picl_vers = PICL_VERSION;
3457 err = ptree_create_and_add_prop(rooth, &pinfo, &picl_vers, &proph);
3458 return (err);
3461 static int
3462 construct_picltree(void)
3464 int err;
3465 picld_plugin_reg_list_t *iter;
3466 picl_nodehdl_t rhdl;
3469 * Create "/" node
3471 if ((err = ptree_create_node(PICL_NODE_ROOT, PICL_CLASS_PICL,
3472 &rhdl)) != PICL_SUCCESS) {
3473 return (err);
3476 if (picltree_set_root(rhdl) != PICL_SUCCESS) {
3477 return (PICL_FAILURE);
3480 err = add_root_props(rhdl);
3481 if (err != PICL_SUCCESS)
3482 return (err);
3485 * Initialize the registered plug-in modules
3487 iter = plugin_reg_list;
3488 while (iter != NULL) {
3489 if (iter->reg.plugin_init)
3490 (iter->reg.plugin_init)();
3491 iter = iter->next;
3493 return (PICL_SUCCESS);
3496 void
3497 xptree_destroy(void)
3499 dbg_print(1, "xptree_destroy: picl_root_obj = %s\n",
3500 (picl_root_obj == NULL ? "NULL" : "not-NULL"));
3502 if (picl_root_obj == NULL)
3503 return;
3505 dbg_print(1, "xptree_destroy: call plugin_fini\n");
3506 plugin_fini(plugin_reg_list);
3507 dbg_print(1, "xptree_destroy: plugin_fini DONE\n");
3509 (void) ptree_delete_node(picl_root_obj->ptree_hdl);
3510 (void) ptree_destroy_node(picl_root_obj->ptree_hdl);
3512 (void) rw_wrlock(&ptree_rwlock);
3513 picl_root_obj = NULL;
3514 (void) rw_unlock(&ptree_rwlock);
3517 /*ARGSUSED*/
3519 xptree_initialize(int flg)
3521 int err;
3522 pthread_attr_t attr;
3523 pthread_t tid;
3525 picld_pid = getpid();
3526 picld_cred.dc_euid = geteuid();
3527 picld_cred.dc_egid = getegid();
3528 picld_cred.dc_ruid = getuid();
3529 picld_cred.dc_rgid = getgid();
3530 picld_cred.dc_pid = getpid();
3532 picl_hdl_hi = 1;
3533 ptree_hdl_hi = 1;
3534 ptree_generation = 1;
3535 qempty_wait = 0;
3537 if (pthread_mutex_init(&ptree_refresh_mutex, NULL) != 0)
3538 return (PICL_FAILURE);
3540 if (picltree_init() != PICL_SUCCESS)
3541 return (PICL_FAILURE);
3543 init_plugin_reg_list();
3544 init_plugin_list();
3545 load_plugins();
3547 err = construct_picltree();
3548 if (err != PICL_SUCCESS)
3549 return (err);
3552 * Dispatch events after all plug-ins have initialized
3554 if (pthread_attr_init(&attr) != 0)
3555 return (PICL_FAILURE);
3557 (void) pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
3558 if (pthread_create(&tid, &attr, ptree_event_thread, NULL))
3559 return (PICL_FAILURE);
3561 return (PICL_SUCCESS);
3565 xptree_reinitialize(void)
3567 int err;
3570 * Wait for eventq to become empty
3572 dbg_print(1, "xptree_reinitialize: wait for evtq empty\n");
3573 (void) pthread_mutex_lock(&evtq_lock);
3574 qempty_wait = 1;
3575 while (eventqp != NULL)
3576 (void) pthread_cond_wait(&evtq_empty, &evtq_lock);
3577 qempty_wait = 0;
3578 (void) pthread_mutex_unlock(&evtq_lock);
3579 dbg_print(1, "xptree_reinitialize: evtq empty is EMPTY\n");
3581 (void) rw_wrlock(&ptree_rwlock);
3582 picl_root_obj = NULL;
3583 ptree_root_hdl = PICL_INVALID_PICLHDL;
3584 (void) rw_unlock(&ptree_rwlock);
3585 (void) pthread_mutex_lock(&ptree_refresh_mutex);
3586 ++ptree_generation;
3587 (void) pthread_mutex_unlock(&ptree_refresh_mutex);
3589 err = construct_picltree();
3590 (void) pthread_mutex_lock(&ptree_refresh_mutex);
3591 (void) pthread_cond_broadcast(&ptree_refresh_cond);
3592 (void) pthread_mutex_unlock(&ptree_refresh_mutex);
3594 (void) pthread_mutex_lock(&evtq_lock);
3595 (void) pthread_cond_broadcast(&evtq_cv);
3596 (void) pthread_mutex_unlock(&evtq_lock);
3598 return (err);
3602 * This function is called by the PICL daemon on behalf of clients to
3603 * wait for a tree refresh
3606 xptree_refresh_notify(uint32_t secs)
3608 int curgen;
3609 int ret;
3610 timespec_t to;
3612 if (secs != 0) {
3613 if (pthread_mutex_lock(&ptree_refresh_mutex) != 0)
3614 return (PICL_FAILURE);
3616 curgen = ptree_generation;
3618 while (curgen == ptree_generation) {
3619 if (secs == UINT32_MAX) /* wait forever */
3620 (void) pthread_cond_wait(&ptree_refresh_cond,
3621 &ptree_refresh_mutex);
3622 else {
3623 to.tv_sec = secs;
3624 to.tv_nsec = 0;
3625 ret = pthread_cond_reltimedwait_np(
3626 &ptree_refresh_cond,
3627 &ptree_refresh_mutex, &to);
3628 if (ret == ETIMEDOUT)
3629 break;
3633 (void) pthread_mutex_unlock(&ptree_refresh_mutex);
3636 return (PICL_SUCCESS);
3639 /*VARARGS2*/
3640 void
3641 dbg_print(int level, const char *fmt, ...)
3643 if (verbose_level >= level) {
3644 va_list ap;
3646 va_start(ap, fmt);
3647 (void) vprintf(fmt, ap);
3648 va_end(ap);
3652 /*ARGSUSED*/
3653 void
3654 dbg_exec(int level, void (*fn)(void *args), void *args)
3656 if (verbose_level > level)
3657 (*fn)(args);