14736 zfs: Improve sorted scan memory accounting
[illumos-gate.git] / usr / src / lib / libpicltree / picltree.c
blobf62c14e82befa0f52e3a785e46e76dd5ed507d8f
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 if (evhp->ename)
175 free(evhp->ename);
176 (void) pthread_cond_broadcast(&evhp->cv);
177 (void) pthread_cond_destroy(&evhp->cv);
178 free(evhp);
183 * queue_event to events queue
185 static void
186 queue_event(eventq_t *evt)
188 eventq_t *tmpp;
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;
202 * unqueue_event from the specified eventq
204 static eventq_t *
205 unqueue_event(eventq_t **qp)
207 eventq_t *evtp;
209 evtp = *qp;
210 if (evtp != NULL)
211 *qp = evtp->next;
212 return (evtp);
216 * register an event handler by adding it to the list
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)
223 evt_handler_t *ent;
224 evt_handler_t *iter;
226 if (ename == NULL)
227 return (PICL_INVALIDARG);
230 * Initialize event handler entry
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);
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;
248 * add handler to the handler list
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);
256 iter = evt_handlers;
257 while (iter->next != NULL)
258 iter = iter->next;
259 iter->next = ent;
260 (void) pthread_mutex_unlock(&evthandler_lock);
262 return (PICL_SUCCESS);
266 * unregister handler
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)
273 evt_handler_t *evhdlrp, **evhdlrpp;
275 if (ename == NULL)
276 return;
279 * unlink handler from handler list
281 (void) pthread_mutex_lock(&evthandler_lock);
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;
292 * If the handler is in execution, release the lock
293 * and wait for it to complete and retry.
295 if (evhdlrp->execflg) {
296 evhdlrp->wakeupflg = 1;
297 (void) pthread_cond_wait(&evhdlrp->cv,
298 &evthandler_lock);
299 goto retry;
303 * Unlink this handler from the linked list
305 *evhdlrpp = evhdlrp->next;
306 free_handler(evhdlrp);
307 break;
310 (void) pthread_mutex_unlock(&evthandler_lock);
314 * Call all registered handlers for the event
316 static void
317 call_event_handlers(eventq_t *ev)
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);
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);
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);
345 iter = iter->next;
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);
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);
364 * This function is called by a plug-in to post an event
367 ptree_post_event(const char *ename, const void *earg, size_t size,
368 void (*completion_handler)(char *ename, void *earg, size_t size))
370 eventq_t *evt;
372 if (ename == NULL)
373 return (PICL_INVALIDARG);
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;
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);
391 * PICLTREE event thread
393 /*ARGSUSED*/
394 static void *
395 ptree_event_thread(void *argp)
397 eventq_t *evt;
399 for (;;) {
400 (void) pthread_mutex_lock(&evtq_lock);
401 while (eventqp == NULL) {
403 * Signal empty queue
405 if (qempty_wait)
406 (void) pthread_cond_broadcast(&evtq_empty);
407 (void) pthread_cond_wait(&evtq_cv, &evtq_lock);
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);
416 /*NOTREACHED*/
417 return (NULL);
422 * Create a new element
424 static hash_elem_t *
425 hash_newobj(uint32_t hdl_val, void *obj_val)
427 hash_elem_t *n;
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);
438 static hash_elem_t *
439 hash_newhdl(uint32_t picl_hdl, uint32_t ptreeh)
441 hash_elem_t *n;
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);
453 * Initialize a hash table by setting all entries to NULL
455 static int
456 hash_init(hash_t *htbl)
458 int i;
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);
470 * Lock free function to add an entry in the hash table
472 static int
473 hash_add_newobj(hash_t *htbl, picl_hdl_t hdl, void *pobj)
475 int indx;
476 hash_elem_t *n;
477 uint32_t hash_val = HASH_VAL(hdl);
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);
488 static int
489 hash_add_newhdl(hash_t *htbl, picl_hdl_t piclh, picl_hdl_t ptreeh)
491 int indx;
492 hash_elem_t *n;
493 uint32_t picl_val = HASH_VAL(piclh);
494 uint32_t ptree_val = HASH_VAL(ptreeh);
496 n = hash_newhdl(picl_val, ptree_val);
497 if (n == NULL)
498 return (-1);
500 indx = HASH_INDEX(htbl->hash_size, picl_val);
501 n->next = htbl->tbl[indx];
502 htbl->tbl[indx] = n;
503 return (0);
507 * Lock free function to remove the handle from the hash table
508 * Returns -1 if element not found, 0 if successful
510 static int
511 hash_remove(hash_t *htbl, picl_hdl_t hdl)
513 hash_elem_t *nxt;
514 hash_elem_t *cur;
515 int i;
516 uint32_t hash_val = HASH_VAL(hdl);
518 i = HASH_INDEX(htbl->hash_size, hash_val);
519 if (htbl->tbl[i] == NULL)
520 return (-1);
522 cur = htbl->tbl[i];
523 if (cur->hdl == hash_val) {
524 htbl->tbl[i] = cur->next;
525 free(cur);
526 return (0);
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);
535 cur = nxt;
536 nxt = nxt->next;
538 return (-1);
542 * Lock free function to lookup the hash table for a given handle
543 * Returns NULL if not found
545 static void *
546 hash_lookup_obj(hash_t *htbl, picl_hdl_t hdl)
548 hash_elem_t *tmp;
549 int i;
550 uint32_t hash_val;
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;
560 return (NULL);
563 static picl_hdl_t
564 hash_lookup_hdl(hash_t *htbl, picl_hdl_t hdl)
566 hash_elem_t *tmp;
567 int i;
568 uint32_t hash_val;
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;
578 return (PICL_INVALID_PICLHDL);
582 * Is the PICL handle stale or invalid handle?
584 static int
585 picl_hdl_error(picl_hdl_t hdl)
587 uint32_t hash_val = HASH_VAL(hdl);
588 pid_t pid = GET_PID(hdl);
589 int err;
591 (void) pthread_mutex_lock(&piclhdl_lock);
592 err = PICL_STALEHANDLE;
593 if ((pid != picld_pid) || (hash_val >= picl_hdl_hi) ||
594 (hash_val == 0))
595 err = PICL_INVALIDHANDLE;
596 (void) pthread_mutex_unlock(&piclhdl_lock);
597 return (err);
601 * Is the Ptree handle stale or invalid handle?
603 static int
604 ptree_hdl_error(picl_hdl_t hdl)
606 uint32_t hash_val = HASH_VAL(hdl);
607 pid_t pid = GET_PID(hdl);
608 int err;
610 (void) pthread_mutex_lock(&ptreehdl_lock);
611 err = PICL_STALEHANDLE;
612 if ((pid != picld_pid) || (hash_val >= ptree_hdl_hi) ||
613 (hash_val == 0))
614 err = PICL_INVALIDHANDLE;
615 (void) pthread_mutex_unlock(&ptreehdl_lock);
616 return (err);
620 * For a PICL handle, return the PTree handle and the PICL object
621 * Locks and releases the PICL table.
624 cvt_picl2ptree(picl_hdl_t hdl, picl_hdl_t *ptree_hdl)
626 picl_hdl_t tmph;
627 int err;
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);
636 *ptree_hdl = tmph;
637 (void) rw_unlock(&picltbl_rwlock); /* unlock picl */
638 return (PICL_SUCCESS);
642 * Allocate a ptree handle
644 static picl_hdl_t
645 alloc_ptreehdl(void)
647 picl_hdl_t hdl;
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);
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.
662 static picl_hdl_t
663 alloc_piclhdl(void)
665 picl_hdl_t hdl;
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);
675 * Allocate and add handle to PTree hash table
677 static void
678 alloc_and_add_to_ptree(picl_obj_t *pobj)
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);
687 * Lock a picl node object
689 static int
690 lock_obj(int rw, picl_obj_t *nodep)
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);
702 * Release the picl node object.
703 * This function may be called with a NULL object pointer.
705 static void
706 unlock_node(picl_obj_t *nodep)
708 if (nodep == NULL)
709 return;
710 (void) rw_unlock(&nodep->node_lock);
714 * This function locks the node of a property and returns the node object
715 * and the property object.
717 static int
718 lookup_and_lock_propnode(int rw, picl_prophdl_t proph, picl_obj_t **nodep,
719 picl_obj_t **propp)
721 picl_obj_t *pobj;
722 picl_obj_t *nobj;
724 pobj = hash_lookup_obj(&ptreetbl, proph);
725 if (pobj == NULL)
726 return (ptree_hdl_error(proph));
729 * Get the property's or table entry's node object
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);
741 if (nobj && (lock_obj(rw, nobj) < 0)) /* Lock node */
742 return (PICL_FAILURE);
744 *nodep = nobj;
745 *propp = pobj;
747 return (PICL_SUCCESS);
751 * This function locks the node of a table and returns the node object
752 * and the table object.
754 static int
755 lookup_and_lock_tablenode(int rw, picl_prophdl_t tblh, picl_obj_t **nodep,
756 picl_obj_t **tblobj)
758 picl_obj_t *pobj;
759 picl_obj_t *nobj;
761 pobj = hash_lookup_obj(&ptreetbl, tblh);
762 if (pobj == NULL)
763 return (ptree_hdl_error(tblh));
766 * Get the property's or table entry's node object
768 nobj = NULL;
769 if (pobj->obj_type != PICL_OBJ_TABLE)
770 return (PICL_NOTTABLE);
771 nobj = pobj->prop_node;
773 if (nobj && (lock_obj(rw, nobj) < 0)) /* Lock node */
774 return (PICL_FAILURE);
776 *nodep = nobj;
777 *tblobj = pobj;
779 return (PICL_SUCCESS);
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
786 static int
787 lookup_and_lock_tableprop_node(int rw, picl_prophdl_t tblproph,
788 picl_obj_t **nodep, picl_obj_t **tblpropp)
790 picl_obj_t *pobj;
791 picl_obj_t *nobj;
793 pobj = hash_lookup_obj(&ptreetbl, tblproph);
794 if (pobj == NULL)
795 return (ptree_hdl_error(tblproph));
798 * Get the property's or table entry's node object
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;
809 if (nobj && (lock_obj(rw, nobj) < 0)) /* Lock node */
810 return (PICL_FAILURE);
812 *tblpropp = pobj;
813 *nodep = nobj;
815 return (PICL_SUCCESS);
819 * Lock the node corresponding to the given handle and return its object
821 static int
822 lookup_and_lock_node(int rw, picl_nodehdl_t nodeh, picl_obj_t **nodep)
824 picl_obj_t *nobj;
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);
838 * Is the property name a restricted property name?
840 static int
841 picl_restricted(const char *name)
843 if (strcmp(name, PICL_PROP_CLASSNAME) == 0)
844 return (0); /* not restricted */
846 if ((name[0] == '_') && (strchr(&name[1], '_') == NULL))
847 return (1);
848 return (0);
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.
859 static int
860 check_propsize(int op, picl_obj_t *propp, size_t sz)
862 if (propp->prop_mode & PICL_VOLATILE) {
863 if (sz != propp->prop_size)
864 return (PICL_INVALIDARG);
865 else
866 return (PICL_SUCCESS);
870 * check size for non-volatile properties
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 */
886 /* FALLTHROUGH */
887 default:
888 if (propp->prop_size != sz)
889 return (PICL_INVALIDARG);
890 break;
892 return (PICL_SUCCESS);
895 void
896 cvt_ptree2picl(picl_hdl_t *handlep)
898 picl_obj_t *pobj;
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);
910 * The caller of the piclize() set of functions is assumed to hold
911 * the ptree_rwlock().
913 static void
914 piclize_obj(picl_obj_t *pobj)
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);
922 static void
923 piclize_table(picl_obj_t *tbl_obj)
925 picl_obj_t *rowp;
926 picl_obj_t *colp;
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);
933 static void
934 piclize_prop(picl_obj_t *propp)
936 picl_obj_t *tbl_obj;
937 picl_prophdl_t tblh;
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);
952 * Function to create PICL handles for a subtree and add them to
953 * the table
955 static void
956 piclize_node(picl_obj_t *nodep)
958 picl_obj_t *propp;
959 picl_obj_t *chdp;
961 piclize_obj(nodep);
962 propp = nodep->first_prop;
963 while (propp != NULL) {
964 piclize_prop(propp);
965 propp = propp->next_prop;
968 /* go through the children */
969 for (chdp = nodep->child_node; chdp != NULL; chdp = chdp->sibling_node)
970 piclize_node(chdp);
974 * Function to remove PICL handles
976 static void
977 unpiclize_obj(picl_obj_t *pobj)
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);
985 static void
986 unpiclize_table(picl_obj_t *tbl_obj)
988 picl_obj_t *rowp;
989 picl_obj_t *colp;
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);
997 static void
998 unpiclize_prop(picl_obj_t *propp)
1000 picl_obj_t *tbl_obj;
1001 picl_prophdl_t tblh;
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);
1015 * Function to remove PICL handles for a subtree and its
1016 * properties
1018 static void
1019 unpiclize_node(picl_obj_t *nodep)
1021 picl_obj_t *propp;
1022 picl_obj_t *chdp;
1025 if (!IS_PICLIZED(nodep))
1026 return;
1028 unpiclize_obj(nodep);
1029 propp = nodep->first_prop;
1030 while (propp != NULL) {
1031 unpiclize_prop(propp);
1032 propp = propp->next_prop;
1035 /* go through the children */
1036 for (chdp = nodep->child_node; chdp != NULL; chdp = chdp->sibling_node)
1037 unpiclize_node(chdp);
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.
1045 static int
1046 lookup_verify_ref_prop(picl_obj_t *propp, picl_obj_t **ret)
1048 picl_nodehdl_t refh;
1049 picl_obj_t *refobj;
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);
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
1066 static int
1067 lookup_verify_table_prop(picl_obj_t *propp, picl_obj_t **ret)
1069 picl_prophdl_t tblh;
1070 picl_obj_t *tbl_obj;
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);
1083 static int
1084 lookup_verify_prop_handle(picl_prophdl_t proph, picl_obj_t **ret)
1086 picl_obj_t *propp;
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);
1098 static int
1099 lookup_verify_node_handle(picl_nodehdl_t nodeh, picl_obj_t **ret)
1101 picl_obj_t *nodep;
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);
1113 static int
1114 lookup_prop_by_name(picl_obj_t *nodep, const char *pname, picl_obj_t **ret)
1116 picl_obj_t *propp;
1118 if (strcmp(pname, PICL_PROP_PARENT) == 0) {
1119 if (nodep->parent_node == NULL)
1120 return (PICL_PROPNOTFOUND);
1121 else
1122 return (PICL_SUCCESS);
1124 if (strcmp(pname, PICL_PROP_CHILD) == 0) {
1125 if (nodep->child_node == NULL)
1126 return (PICL_PROPNOTFOUND);
1127 else
1128 return (PICL_SUCCESS);
1130 if (strcmp(pname, PICL_PROP_PEER) == 0) {
1131 if (nodep->sibling_node == NULL)
1132 return (PICL_PROPNOTFOUND);
1133 else
1134 return (PICL_SUCCESS);
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);
1144 propp = propp->next_prop;
1146 return (PICL_PROPNOTFOUND);
1150 * This function locks the ptree, verifies that the handle is a reference
1151 * to a node of specified class name, releases the lock
1153 static int
1154 check_ref_handle(picl_nodehdl_t refh, char *clname)
1156 picl_obj_t *refobj;
1157 picl_obj_t *propp;
1158 int err;
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);
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);
1175 static int
1176 check_table_handle(picl_prophdl_t tblh)
1178 picl_obj_t *tbl_obj;
1179 int err;
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);
1191 * PICLTree Interface routines for plug-in modules
1194 ptree_get_root(picl_nodehdl_t *rooth)
1196 *rooth = ptree_root_hdl;
1197 return (PICL_SUCCESS);
1201 * Lock free create a property object
1203 static int
1204 create_propobj(const ptree_propinfo_t *pinfo, const void *valbuf,
1205 picl_obj_t **pobjp)
1207 picl_obj_t *pobj;
1209 if (pinfo->version != PTREE_PROPINFO_VERSION_1)
1210 return (PICL_NOTSUPPORTED);
1212 if (!(pinfo->piclinfo.accessmode & PICL_VOLATILE) &&
1213 (pinfo->piclinfo.type != PICL_PTYPE_VOID) &&
1214 (valbuf == NULL))
1215 return (PICL_INVALIDARG);
1217 pobj = malloc(sizeof (picl_obj_t));
1218 if (pobj == NULL)
1219 return (PICL_FAILURE);
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;
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);
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);
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;
1251 *pobjp = pobj;
1252 return (PICL_SUCCESS);
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.
1262 ptree_create_prop(const ptree_propinfo_t *pinfo, const void *valbuf,
1263 picl_prophdl_t *proph)
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];
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);
1282 refflag = 0;
1283 if ((pinfo->piclinfo.name[0] == '_') &&
1284 (strchr(&pinfo->piclinfo.name[1], '_') != NULL))
1285 refflag = 1;
1287 if (pinfo->piclinfo.type == PICL_PTYPE_REFERENCE) {
1288 if (refflag == 0)
1289 return (PICL_INVREFERENCE);
1291 * check valid reference handle for non-volatiles
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);
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);
1324 * No locks held when you get here
1326 err = create_propobj(pinfo, valbuf, &pobj);
1327 if (err != PICL_SUCCESS)
1328 return (err);
1330 alloc_and_add_to_ptree(pobj);
1331 *proph = pobj->ptree_hdl;
1332 return (PICL_SUCCESS);
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()
1340 static void
1341 destroy_table(picl_obj_t *pobj)
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;
1349 tblh = *(picl_prophdl_t *)pobj->prop_val;
1350 tbl_obj = hash_lookup_obj(&ptreetbl, tblh);
1351 if (tbl_obj == NULL)
1352 return;
1354 assert(tbl_obj->obj_type & PICL_OBJ_TABLE);
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);
1371 (void) hash_remove(&ptreetbl, tbl_obj->ptree_hdl);
1372 free(tbl_obj);
1377 * Lock free function that frees up a property object and removes the
1378 * handles from Ptree table
1380 static void
1381 destroy_propobj(picl_obj_t *propp)
1383 if (propp->prop_type == PICL_PTYPE_TABLE)
1384 destroy_table(propp);
1386 (void) hash_remove(&ptreetbl, propp->ptree_hdl);
1387 if (propp->prop_val)
1388 free(propp->prop_val);
1389 free(propp);
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
1398 ptree_destroy_prop(picl_prophdl_t proph)
1400 picl_obj_t *propp;
1402 (void) rw_wrlock(&ptree_rwlock); /* Exclusive Lock ptree */
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));
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);
1416 destroy_propobj(propp);
1418 (void) rw_unlock(&ptree_rwlock); /* Unlock ptree */
1419 return (PICL_SUCCESS);
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.
1428 ptree_add_prop(picl_nodehdl_t nodeh, picl_prophdl_t proph)
1430 int err;
1431 picl_obj_t *nodep;
1432 picl_obj_t *propp;
1433 picl_obj_t *tbl_obj;
1434 picl_obj_t *refobj;
1436 (void) rw_rdlock(&ptree_rwlock); /* RDLock ptree */
1439 * Verify property handle
1441 err = lookup_verify_prop_handle(proph, &propp);
1442 if (err != PICL_SUCCESS) {
1443 (void) rw_unlock(&ptree_rwlock); /* Unlock ptree */
1444 return (err);
1447 if (propp->prop_node != NULL) {
1448 (void) rw_unlock(&ptree_rwlock);
1449 return (PICL_INVALIDARG);
1452 nodep = NULL;
1454 * Exclusive Lock the node's properties
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);
1463 * check if prop already exists
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);
1473 * Verify property's value
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);
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);
1498 if (IS_PICLIZED(nodep) && !IS_PICLIZED(refobj)) {
1499 unlock_node(nodep);
1500 (void) rw_unlock(&ptree_rwlock);
1501 return (err);
1503 break;
1504 default:
1505 break;
1508 if (IS_PICLIZED(nodep))
1509 piclize_prop(propp);
1511 * Add prop to beginning of list
1513 propp->prop_node = nodep; /* set prop's nodep */
1514 propp->next_prop = nodep->first_prop;
1515 nodep->first_prop = propp;
1517 unlock_node(nodep); /* Unlock node */
1518 (void) rw_unlock(&ptree_rwlock); /* Unlock table */
1519 return (PICL_SUCCESS);
1523 * Lock free function that unlinks a property from its node
1525 static int
1526 unlink_prop(picl_obj_t *nodep, picl_obj_t *propp)
1528 picl_obj_t *iterp;
1530 iterp = nodep->first_prop;
1531 if (iterp == propp) { /* first property */
1532 nodep->first_prop = iterp->next_prop;
1533 return (PICL_SUCCESS);
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);
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.
1549 ptree_delete_prop(picl_prophdl_t proph)
1551 int err;
1552 picl_obj_t *nodep;
1553 picl_obj_t *propp;
1555 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
1557 * Lookup the property's node and lock it if there is one
1558 * return the objects for the property and the node
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);
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);
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);
1584 propp->prop_node = NULL; /* reset prop's nodep */
1585 propp->next_prop = NULL;
1587 unpiclize_prop(propp);
1589 unlock_node(nodep); /* Unlock node */
1590 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
1591 return (PICL_SUCCESS);
1595 * Create a table object and return its handle
1598 ptree_create_table(picl_prophdl_t *tblh)
1600 picl_obj_t *pobj;
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;
1614 alloc_and_add_to_ptree(pobj);
1615 *tblh = pobj->ptree_hdl;
1616 return (PICL_SUCCESS);
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
1624 ptree_add_row_to_table(picl_prophdl_t tblh, int nprops,
1625 const picl_prophdl_t *props)
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;
1636 if (nprops < 1)
1637 return (PICL_INVALIDARG);
1639 newrow = malloc(sizeof (picl_obj_t *) * nprops);
1640 if (newrow == NULL)
1641 return (PICL_FAILURE);
1643 (void) rw_rdlock(&ptree_rwlock); /* Lock ptree */
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);
1653 * make sure all are either props or table handles
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;
1661 if ((!(pobj->obj_type & PICL_OBJ_PROP)) &&
1662 (!(pobj->obj_type & PICL_OBJ_TABLE))) {
1663 err = PICL_NOTPROP;
1664 break;
1666 if (IS_PICLIZED(pobj) || (pobj->prop_table != NULL) ||
1667 (pobj->prop_node != NULL)) {
1668 err = PICL_INVALIDARG;
1669 break;
1673 if (err != PICL_SUCCESS) {
1674 free(newrow);
1675 unlock_node(nodep);
1676 (void) rw_unlock(&ptree_rwlock); /* Unlock table */
1677 return (err);
1681 * Mark all props as table entries, set up row linkages
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];
1696 newrow[nprops - 1]->next_row = NULL;
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;
1713 unlock_node(nodep); /* unlock node */
1714 (void) rw_unlock(&ptree_rwlock); /* Unlock ptree */
1715 free(newrow);
1716 return (PICL_SUCCESS);
1720 * This function returns the handle of the next property in the row
1723 ptree_get_next_by_row(picl_prophdl_t proph, picl_prophdl_t *nextrowh)
1725 int err;
1726 picl_obj_t *nodep;
1727 picl_obj_t *propp;
1729 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
1731 nodep = propp = NULL;
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
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);
1744 if (propp->next_row)
1745 *nextrowh = propp->next_row->ptree_hdl;
1746 else
1747 err = PICL_ENDOFLIST;
1749 unlock_node(nodep); /* unlock node */
1750 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
1751 return (err);
1755 ptree_get_next_by_col(picl_prophdl_t proph, picl_prophdl_t *nextcolh)
1757 int err;
1758 picl_obj_t *propp;
1759 picl_obj_t *nodep;
1761 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
1762 nodep = propp = NULL;
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
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);
1775 if (propp->next_col)
1776 *nextcolh = propp->next_col->ptree_hdl;
1777 else
1778 err = PICL_ENDOFLIST;
1780 unlock_node(nodep); /* unlock node */
1781 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
1782 return (err);
1786 * This function creates node object and adds its handle to the Ptree
1789 ptree_create_node(const char *name, const char *clname, picl_nodehdl_t *nodeh)
1791 picl_obj_t *pobj;
1792 ptree_propinfo_t propinfo;
1793 picl_prophdl_t phdl;
1794 picl_prophdl_t cphdl;
1795 int err;
1797 if ((name == NULL) || (*name == '\0') ||
1798 (clname == NULL) || (*clname == '\0'))
1799 return (PICL_INVALIDARG);
1801 if ((strlen(name) >= PICL_PROPNAMELEN_MAX) ||
1802 (strlen(clname) >= PICL_CLASSNAMELEN_MAX))
1803 return (PICL_VALUETOOBIG);
1806 * Create the picl object for node
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);
1823 (void) rwlock_init(&pobj->node_lock, USYNC_THREAD, NULL);
1825 alloc_and_add_to_ptree(pobj); /* commit the node */
1828 * create name property
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);
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);
1850 * create picl classname property
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);
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);
1868 *nodeh = pobj->ptree_hdl;
1869 return (PICL_SUCCESS);
1873 * Destroy a node/subtree freeing up space
1874 * Removed destroyed objects' handles from PTree table
1876 static void
1877 destroy_subtree(picl_obj_t *nodep)
1879 picl_obj_t *iterp;
1880 picl_obj_t *freep;
1881 picl_obj_t *chdp;
1883 if (nodep == NULL)
1884 return;
1886 chdp = nodep->child_node;
1887 while (chdp != NULL) {
1888 freep = chdp;
1889 chdp = chdp->sibling_node;
1890 destroy_subtree(freep);
1894 * Lock the node
1896 (void) lock_obj(WRLOCK_NODE, nodep);
1899 * destroy all properties associated with this node
1901 iterp = nodep->first_prop;
1902 while (iterp != NULL) {
1903 freep = iterp;
1904 iterp = iterp->next_prop;
1905 destroy_propobj(freep);
1908 (void) hash_remove(&ptreetbl, nodep->ptree_hdl);
1909 (void) rwlock_destroy(&nodep->node_lock);
1910 free(nodep->node_classname);
1911 free(nodep);
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.
1920 ptree_destroy_node(picl_nodehdl_t nodeh)
1922 picl_obj_t *nodep;
1923 picl_obj_t *parp;
1924 picl_obj_t *np;
1925 int err;
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);
1936 * Has this node/subtree been deleted?
1938 if (IS_PICLIZED(nodep)) {
1939 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
1940 return (PICL_CANTDESTROY);
1944 * update parent's child list to repair the tree when
1945 * parent is not null
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);
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;
1964 destroy_subtree(nodep);
1965 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
1966 return (PICL_SUCCESS);
1970 * This function deletes a node/subtree from the tree and removes the handles
1971 * from PICL table
1974 ptree_delete_node(picl_nodehdl_t nodeh)
1976 picl_obj_t *nodep;
1977 picl_obj_t *parp;
1978 picl_obj_t *np;
1979 int err;
1981 (void) rw_wrlock(&ptree_rwlock); /* exclusive wrlock ptree */
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);
1991 * unparent it
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;
2006 nodep->parent_node = NULL;
2007 nodep->sibling_node = NULL;
2009 unpiclize_node(nodep);
2011 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2012 return (PICL_SUCCESS);
2016 * This function adds a node as a child of another node
2019 ptree_add_node(picl_nodehdl_t parh, picl_nodehdl_t chdh)
2021 picl_obj_t *pnodep;
2022 picl_obj_t *cnodep;
2023 picl_obj_t *nodep;
2024 int err;
2026 (void) rw_wrlock(&ptree_rwlock); /* exclusive lock ptree */
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);
2035 err = lookup_verify_node_handle(chdh, &cnodep);
2036 if (err != PICL_SUCCESS) {
2037 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2038 return (err);
2041 /* is chdh already a child? */
2042 if (cnodep->parent_node != NULL) {
2043 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2044 return (PICL_CANTPARENT);
2048 * append child to children list
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;
2061 /* piclize */
2062 if (IS_PICLIZED(pnodep))
2063 piclize_node(cnodep);
2064 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2065 return (PICL_SUCCESS);
2068 static void
2069 copy_propinfo_ver_1(ptree_propinfo_t *pinfo, picl_obj_t *propp)
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;
2080 static void
2081 copy_reserved_propinfo_ver_1(ptree_propinfo_t *pinfo, const char *pname)
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;
2093 * This function returns the property information to a plug-in
2096 ptree_get_propinfo(picl_prophdl_t proph, ptree_propinfo_t *pinfo)
2098 int err;
2099 picl_obj_t *nodep;
2100 picl_obj_t *propp;
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);
2110 if (propp->pinfo_ver == PTREE_PROPINFO_VERSION_1)
2111 copy_propinfo_ver_1(pinfo, propp);
2112 else
2113 err = PICL_FAILURE;
2115 unlock_node(nodep); /* unlock node */
2116 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2117 return (err);
2121 * This function returns the property information to a plug-in
2124 xptree_get_propinfo_by_name(picl_nodehdl_t nodeh, const char *pname,
2125 ptree_propinfo_t *pinfo)
2127 int err;
2128 picl_obj_t *nodep;
2129 picl_obj_t *propp;
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);
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);
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;
2153 unlock_node(nodep); /* unlock node */
2154 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2155 return (err);
2159 * This function must be called only after a lookup_prop_by_name() returns
2160 * success and only if picl_restricted() returns true.
2162 static int
2163 read_reserved_propval_and_unlock(picl_obj_t *nodep, const char *pname,
2164 void *vbuf, size_t size)
2166 void *srcp;
2168 if (size != sizeof (picl_nodehdl_t))
2169 return (PICL_VALUETOOBIG);
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);
2180 (void) memcpy(vbuf, srcp, sizeof (picl_nodehdl_t));
2181 unlock_node(nodep);
2182 (void) rw_unlock(&ptree_rwlock);
2183 return (PICL_SUCCESS);
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
2192 static int
2193 read_propval_and_unlock(picl_obj_t *nodep, picl_obj_t *propp, void *vbuf,
2194 door_cred_t cred)
2196 int err;
2197 int (*volrd)(ptree_rarg_t *arg, void *buf);
2199 err = PICL_SUCCESS;
2200 if (propp->prop_mode & PICL_VOLATILE) {
2201 ptree_rarg_t rarg;
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;
2211 unlock_node(nodep); /* unlock node */
2212 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
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);
2224 unlock_node(nodep);
2225 (void) rw_unlock(&ptree_rwlock);
2226 return (err);
2230 xptree_get_propval_with_cred(picl_prophdl_t proph, void *vbuf, size_t size,
2231 door_cred_t cred)
2233 picl_obj_t *propp;
2234 picl_obj_t *nodep;
2235 int err;
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);
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);
2252 return (read_propval_and_unlock(nodep, propp, vbuf, cred));
2256 * This function gets the credentials and calls get_propval_with_cred.
2259 ptree_get_propval(picl_prophdl_t proph, void *vbuf, size_t size)
2261 return (xptree_get_propval_with_cred(proph, vbuf, size, picld_cred));
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
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)
2273 picl_obj_t *nodep;
2274 picl_obj_t *propp;
2275 int err;
2277 (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
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);
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);
2293 if (picl_restricted(pname))
2294 return (read_reserved_propval_and_unlock(nodep, pname, vbuf,
2295 size));
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);
2304 return (read_propval_and_unlock(nodep, propp, vbuf, cred));
2308 * This function is used by plugins to get a value of a property
2309 * looking it up by its name.
2312 ptree_get_propval_by_name(picl_nodehdl_t nodeh, const char *pname, void *vbuf,
2313 size_t size)
2315 return (xptree_get_propval_by_name_with_cred(nodeh, pname, vbuf, size,
2316 picld_cred));
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.
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)
2328 int err;
2329 int (*volwr)(ptree_warg_t *arg, const void *buf);
2331 err = PICL_SUCCESS;
2332 if (propp->prop_mode & PICL_VOLATILE) {
2333 ptree_warg_t warg;
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;
2343 unlock_node(nodep); /* unlock node */
2344 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
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);
2354 unlock_node(nodep); /* unlock node */
2355 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2356 return (err);
2360 xptree_update_propval_with_cred(picl_prophdl_t proph, const void *vbuf,
2361 size_t size, door_cred_t cred)
2363 picl_obj_t *nodep;
2364 picl_obj_t *propp;
2365 int err;
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);
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);
2382 return (write_propval_and_unlock(nodep, propp, vbuf, size, cred));
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
2390 ptree_update_propval(picl_prophdl_t proph, const void *vbuf, size_t size)
2392 return (xptree_update_propval_with_cred(proph, vbuf, size, picld_cred));
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.
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)
2405 picl_obj_t *nodep;
2406 picl_obj_t *propp;
2407 int err;
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);
2417 if (picl_restricted(pname)) {
2418 unlock_node(nodep);
2419 (void) rw_unlock(&ptree_rwlock);
2420 return (PICL_RESERVEDNAME);
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);
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);
2437 return (write_propval_and_unlock(nodep, propp, vbuf, size, cred));
2441 * This function updates the value of a property specified by its name
2444 ptree_update_propval_by_name(picl_nodehdl_t nodeh, const char *pname,
2445 const void *vbuf, size_t size)
2447 return (xptree_update_propval_by_name_with_cred(nodeh, pname, vbuf,
2448 size, picld_cred));
2452 * This function retrieves the handle of a property by its name
2455 ptree_get_prop_by_name(picl_nodehdl_t nodeh, const char *pname,
2456 picl_prophdl_t *proph)
2458 picl_obj_t *nodep;
2459 picl_obj_t *propp;
2460 int err;
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);
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);
2477 err = lookup_prop_by_name(nodep, pname, &propp);
2478 if (err == PICL_SUCCESS)
2479 *proph = propp->ptree_hdl;
2481 unlock_node(nodep); /* unlock node */
2482 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2483 return (err);
2487 * This function returns the handle of the first property
2490 ptree_get_first_prop(picl_nodehdl_t nodeh, picl_prophdl_t *proph)
2492 picl_obj_t *pobj;
2493 int err;
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);
2503 if (pobj->first_prop)
2504 *proph = pobj->first_prop->ptree_hdl;
2505 else
2506 err = PICL_ENDOFLIST;
2508 unlock_node(pobj); /* unlock node */
2509 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2510 return (err);
2514 * This function returns the handle of next property in the list
2517 ptree_get_next_prop(picl_prophdl_t proph, picl_prophdl_t *nextproph)
2519 picl_obj_t *nodep;
2520 picl_obj_t *propp;
2521 int err;
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);
2531 if (propp->next_prop) {
2532 *nextproph = propp->next_prop->ptree_hdl;
2533 } else
2534 err = PICL_ENDOFLIST;
2536 unlock_node(nodep); /* unlock node */
2537 (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2538 return (err);
2542 * These functions are called by ptree_get_node_by_path()
2543 * Append a prop expression entry to the list
2545 static prop_list_t *
2546 append_entry_to_list(prop_list_t *el, prop_list_t *list)
2548 prop_list_t *ptr;
2550 if (el == NULL)
2551 return (list);
2553 if (list == NULL) {
2554 list = el;
2555 return (list);
2559 * Add it to the end of list
2561 ptr = list;
2563 while (ptr->next != NULL)
2564 ptr = ptr->next;
2566 ptr->next = el;
2568 return (list);
2572 * Free the property expression list
2574 static void
2575 free_list(prop_list_t *list)
2577 prop_list_t *ptr;
2578 prop_list_t *tmp;
2580 for (ptr = list; ptr != NULL; ptr = tmp) {
2581 tmp = ptr->next;
2582 free(ptr);
2586 static int
2587 parse_prl(char *prl, char **name, char **baddr, prop_list_t **plist)
2589 char *propptr;
2590 char *ptr;
2591 char *pname;
2592 char *pval;
2593 prop_list_t *el;
2595 if (prl == NULL)
2596 return (PICL_FAILURE);
2598 if ((prl[0] == '@') || (prl[0] == '?'))
2599 return (PICL_FAILURE);
2601 *name = prl;
2604 * get property expression
2606 ptr = strchr(prl, '?');
2608 if (ptr != NULL) {
2609 *ptr = '\0';
2610 propptr = ptr + 1;
2611 } else
2612 propptr = NULL;
2615 * get bus value
2617 ptr = strchr(prl, '@');
2619 if (ptr != NULL) {
2620 *ptr = '\0';
2621 *baddr = ptr + 1;
2622 if (strlen(*baddr) == 0) /* no bus value after @ */
2623 return (PICL_FAILURE);
2627 * create the prop list
2629 while (propptr != NULL) {
2630 pname = propptr;
2631 pval = NULL;
2633 ptr = strchr(propptr, '?');
2635 if (ptr != NULL) { /* more ?<prop>=<propval> */
2636 *ptr = '\0';
2637 propptr = ptr + 1;
2638 } else
2639 propptr = NULL;
2641 if (strlen(pname) == 0) /* no prop exp after ? */
2642 return (PICL_FAILURE);
2644 ptr = strchr(pname, '=');
2645 if (ptr != NULL) { /* not void prop */
2646 *ptr = '\0';
2647 pval = ptr + 1;
2649 * <prop>= is treated as void property
2651 if (strlen(pval) == 0)
2652 pval = NULL;
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);
2662 return (PICL_SUCCESS);
2665 static int
2666 prop_match(ptree_propinfo_t pinfo, void *vbuf, char *val)
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;
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);
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);
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);
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);
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);
2745 static int
2746 check_propval(picl_nodehdl_t nodeh, char *pname, char *pval)
2748 int err;
2749 picl_prophdl_t proph;
2750 ptree_propinfo_t pinfo;
2751 void *vbuf;
2753 err = ptree_get_prop_by_name(nodeh, pname, &proph);
2754 if (err != PICL_SUCCESS)
2755 return (err);
2757 err = ptree_get_propinfo(proph, &pinfo);
2758 if (err != PICL_SUCCESS)
2759 return (err);
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);
2773 if (!prop_match(pinfo, vbuf, pval))
2774 return (PICL_FAILURE);
2776 return (PICL_SUCCESS);
2779 static int
2780 get_child_by_path(picl_nodehdl_t rooth, char *prl,
2781 picl_nodehdl_t *nodeh, char *pname)
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;
2793 if (prl == NULL)
2794 return (PICL_FAILURE);
2796 path = strdupa(prl);
2797 if (path == NULL)
2798 return (PICL_FAILURE);
2800 plist = NULL;
2801 nodename = NULL;
2802 baddr = NULL;
2804 err = parse_prl(path, &nodename, &baddr, &plist);
2805 if (err != PICL_SUCCESS) {
2806 free_list(plist);
2807 return (err);
2810 if (nodename == NULL)
2811 return (PICL_FAILURE);
2813 nameval = alloca(strlen(nodename) + 1);
2814 if (nameval == NULL) {
2815 free_list(plist);
2816 return (PICL_FAILURE);
2819 if (baddr != NULL) {
2820 busval = alloca(strlen(baddr) + 1);
2821 if (busval == NULL) {
2822 free_list(plist);
2823 return (PICL_FAILURE);
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);
2837 * compare name
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));
2844 if (err != PICL_SUCCESS)
2845 continue;
2846 if (strcmp(nameval, nodename) != 0)
2847 continue;
2851 * compare device address with bus-addr prop first
2852 * then with UnitAddress property
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;
2862 if (strcmp(busval, baddr) != 0)
2863 continue; /* not match */
2866 if (plist == NULL) { /* no prop expression */
2867 *nodeh = chdh;
2868 return (PICL_SUCCESS);
2872 * compare the property expression list
2874 ptr = plist;
2876 while (ptr != NULL) {
2877 err = check_propval(chdh, ptr->pname, ptr->pval);
2878 if (err != PICL_SUCCESS)
2879 break;
2881 ptr = ptr->next;
2883 if (ptr == NULL) {
2884 *nodeh = chdh;
2885 free_list(plist);
2886 return (PICL_SUCCESS);
2889 free_list(plist);
2890 return (PICL_NOTNODE);
2894 * This functions returns the handle of node specified by its path
2897 ptree_get_node_by_path(const char *piclprl, picl_nodehdl_t *handle)
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 */
2910 path = strdupa(piclprl);
2911 if (path == NULL)
2912 return (PICL_FAILURE);
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);
2929 err = ptree_get_root(&rooth);
2930 if (err != PICL_SUCCESS)
2931 return (err);
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);
2944 if (err != PICL_SUCCESS)
2945 return (err);
2949 * check if last token is empty or not
2950 * eg. /a/b/c/ or /a/b/c
2952 if (*ptr == '\0') {
2953 *handle = chdh;
2954 return (PICL_SUCCESS);
2957 len = strcspn(ptr, " \t\n");
2958 if (len == 0) {
2959 *handle = chdh;
2960 return (PICL_SUCCESS);
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);
2969 if (err != PICL_SUCCESS)
2970 return (err);
2972 *handle = chdh;
2973 return (PICL_SUCCESS);
2977 * Initialize propinfo
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 *))
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);
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
3003 ptree_create_and_add_prop(picl_nodehdl_t nodeh, ptree_propinfo_t *infop,
3004 void *vbuf, picl_prophdl_t *proph)
3006 int err;
3007 picl_prophdl_t tmph;
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);
3017 if (proph)
3018 *proph = tmph;
3019 return (PICL_SUCCESS);
3023 * Creates a node, adds it to its parent node, and returns the node
3024 * handle to the caller if successful
3027 ptree_create_and_add_node(picl_nodehdl_t rooth, const char *name,
3028 const char *classname, picl_nodehdl_t *nodeh)
3030 picl_nodehdl_t tmph;
3031 int err;
3033 err = ptree_create_node(name, classname, &tmph);
3035 if (err != PICL_SUCCESS)
3036 return (err);
3038 err = ptree_add_node(rooth, tmph);
3039 if (err != PICL_SUCCESS) {
3040 (void) ptree_destroy_node(tmph);
3041 return (err);
3044 *nodeh = tmph;
3045 return (PICL_SUCCESS);
3050 * recursively visit all nodes
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))
3056 int err;
3057 picl_nodehdl_t chdh;
3058 char classval[PICL_CLASSNAMELEN_MAX];
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);
3068 if ((classname == NULL) || (strcmp(classname, classval) == 0)) {
3069 err = callback_fn(chdh, c_args);
3070 if (err != PICL_WALK_CONTINUE)
3071 return (err);
3074 if ((err = do_walk(chdh, classname, c_args, callback_fn)) !=
3075 PICL_WALK_CONTINUE)
3076 return (err);
3078 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
3079 sizeof (chdh));
3081 if (err == PICL_PROPNOTFOUND) /* end of a branch */
3082 return (PICL_WALK_CONTINUE);
3083 return (err);
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.
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))
3096 int err;
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);
3106 static int
3107 compare_propval(picl_nodehdl_t nodeh, char *pname, picl_prop_type_t ptype,
3108 void *pval, size_t valsize)
3110 int err;
3111 picl_prophdl_t proph;
3112 ptree_propinfo_t propinfo;
3113 void *vbuf;
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);
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.
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)
3151 int err;
3152 picl_nodehdl_t chdh;
3154 if (pname == NULL)
3155 return (PICL_INVALIDARG);
3156 err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh,
3157 sizeof (chdh));
3159 while (err == PICL_SUCCESS) {
3160 if (compare_propval(chdh, pname, ptype, pval, valsize)) {
3161 if (retnodeh)
3162 *retnodeh = chdh;
3163 return (PICL_SUCCESS);
3166 err = ptree_find_node(chdh, pname, ptype, pval, valsize,
3167 retnodeh);
3168 if (err != PICL_NODENOTFOUND)
3169 return (err);
3171 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
3172 sizeof (chdh));
3174 if (err == PICL_PROPNOTFOUND)
3175 return (PICL_NODENOTFOUND);
3176 return (err);
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.
3190 ptree_get_frutree_parent(picl_nodehdl_t nodeh, picl_nodehdl_t *fruh)
3192 int err;
3193 picl_nodehdl_t nparh;
3194 picl_nodehdl_t fruparh;
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);
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);
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);
3218 err = ptree_get_propval_by_name(nparh, PICL_PROP_PARENT, &nparh,
3219 sizeof (nparh));
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);
3229 return (err);
3233 * This function is called by plug-ins to register with the daemon
3236 picld_plugin_register(picld_plugin_reg_t *regp)
3238 picld_plugin_reg_list_t *el;
3239 picld_plugin_reg_list_t *tmp;
3241 if (regp == NULL)
3242 return (PICL_FAILURE);
3244 if (regp->version != PICLD_PLUGIN_VERSION_1)
3245 return (PICL_NOTSUPPORTED);
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);
3257 el->reg.plugin_init = regp->plugin_init;
3258 el->reg.plugin_fini = regp->plugin_fini;
3259 el->next = NULL;
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;
3270 return (PICL_SUCCESS);
3274 * Call fini routines of the registered plugins
3276 static void
3277 plugin_fini(picld_plugin_reg_list_t *p)
3279 if (p == NULL)
3280 return;
3282 plugin_fini(p->next);
3283 if (p->reg.plugin_fini)
3284 (p->reg.plugin_fini)();
3288 * Create PICL Tree
3291 static void
3292 init_plugin_reg_list(void)
3294 plugin_reg_list = NULL;
3297 static int
3298 picltree_set_root(picl_nodehdl_t rooth)
3300 picl_obj_t *pobj;
3301 int err;
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);
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);
3318 static int
3319 picltree_init(void)
3321 (void) rwlock_init(&ptree_rwlock, USYNC_THREAD, NULL);
3322 (void) rwlock_init(&picltbl_rwlock, USYNC_THREAD, NULL);
3324 if (hash_init(&picltbl) < 0)
3325 return (PICL_FAILURE);
3326 if (hash_init(&ptreetbl) < 0)
3327 return (PICL_FAILURE);
3329 if (pthread_mutex_init(&ptreehdl_lock, NULL) != 0)
3330 return (PICL_FAILURE);
3332 if (pthread_mutex_init(&piclhdl_lock, NULL) != 0)
3333 return (PICL_FAILURE);
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);
3342 picl_root_obj = NULL;
3343 eventqp = NULL;
3344 evt_handlers = NULL;
3345 ptree_root_hdl = PICL_INVALID_PICLHDL;
3347 return (PICL_SUCCESS);
3350 static void
3351 add_unique_plugin_to_list(char *path, char *name)
3353 char *buf;
3354 picld_plugin_desc_t *pl;
3355 picld_plugin_desc_t *tmp;
3357 pl = plugin_desc;
3358 while (pl != NULL) {
3359 if (strcmp(pl->libname, name) == 0)
3360 return;
3361 else
3362 pl = pl->next;
3365 pl = malloc(sizeof (picld_plugin_desc_t));
3366 if (pl == NULL)
3367 return;
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;
3381 pl->next = NULL;
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;
3393 static void
3394 get_plugins_from_dir(char *dirname)
3396 struct dirent *ent;
3397 DIR *dir;
3398 int len;
3399 int solen = strlen(SO_VERS) + 1;
3401 if ((dir = opendir(dirname)) == NULL)
3402 return;
3404 while ((ent = readdir(dir)) != NULL) {
3405 if ((strcmp(ent->d_name, ".") == 0) ||
3406 (strcmp(ent->d_name, "..") == 0))
3407 continue;
3409 len = strlen(ent->d_name) + 1;
3410 if (len < solen)
3411 continue;
3413 if (strcmp(ent->d_name + (len - solen), SO_VERS) == 0)
3414 add_unique_plugin_to_list(dirname, ent->d_name);
3417 (void) closedir(dir);
3421 static void
3422 init_plugin_list(void)
3424 char nmbuf[SYS_NMLN];
3425 char pname[PATH_MAX];
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);
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);
3440 (void) snprintf(pname, PATH_MAX, "%s/", PICLD_COMMON_PLUGIN_DIR);
3441 if (access(pname, R_OK) == 0)
3442 get_plugins_from_dir(pname);
3445 static void
3446 load_plugins(void)
3448 picld_plugin_desc_t *pl;
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;
3457 pl = pl->next;
3463 static int
3464 add_root_props(picl_nodehdl_t rooth)
3466 int err;
3467 picl_prophdl_t proph;
3468 ptree_propinfo_t pinfo;
3469 float picl_vers;
3471 #define PICL_PROP_PICL_VERSION "PICLVersion"
3472 #define PICL_VERSION 1.1
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);
3480 picl_vers = PICL_VERSION;
3481 err = ptree_create_and_add_prop(rooth, &pinfo, &picl_vers, &proph);
3482 return (err);
3485 static int
3486 construct_picltree(void)
3488 int err;
3489 picld_plugin_reg_list_t *iter;
3490 picl_nodehdl_t rhdl;
3493 * Create "/" node
3495 if ((err = ptree_create_node(PICL_NODE_ROOT, PICL_CLASS_PICL,
3496 &rhdl)) != PICL_SUCCESS) {
3497 return (err);
3500 if (picltree_set_root(rhdl) != PICL_SUCCESS) {
3501 return (PICL_FAILURE);
3504 err = add_root_props(rhdl);
3505 if (err != PICL_SUCCESS)
3506 return (err);
3509 * Initialize the registered plug-in modules
3511 iter = plugin_reg_list;
3512 while (iter != NULL) {
3513 if (iter->reg.plugin_init)
3514 (iter->reg.plugin_init)();
3515 iter = iter->next;
3517 return (PICL_SUCCESS);
3520 void
3521 xptree_destroy(void)
3523 dbg_print(1, "xptree_destroy: picl_root_obj = %s\n",
3524 (picl_root_obj == NULL ? "NULL" : "not-NULL"));
3526 if (picl_root_obj == NULL)
3527 return;
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");
3533 (void) ptree_delete_node(picl_root_obj->ptree_hdl);
3534 (void) ptree_destroy_node(picl_root_obj->ptree_hdl);
3536 (void) rw_wrlock(&ptree_rwlock);
3537 picl_root_obj = NULL;
3538 (void) rw_unlock(&ptree_rwlock);
3541 /*ARGSUSED*/
3543 xptree_initialize(int flg)
3545 int err;
3546 pthread_attr_t attr;
3547 pthread_t tid;
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();
3556 picl_hdl_hi = 1;
3557 ptree_hdl_hi = 1;
3558 ptree_generation = 1;
3559 qempty_wait = 0;
3561 if (pthread_mutex_init(&ptree_refresh_mutex, NULL) != 0)
3562 return (PICL_FAILURE);
3564 if (picltree_init() != PICL_SUCCESS)
3565 return (PICL_FAILURE);
3567 init_plugin_reg_list();
3568 init_plugin_list();
3569 load_plugins();
3571 err = construct_picltree();
3572 if (err != PICL_SUCCESS)
3573 return (err);
3576 * Dispatch events after all plug-ins have initialized
3578 if (pthread_attr_init(&attr) != 0)
3579 return (PICL_FAILURE);
3581 (void) pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
3582 if (pthread_create(&tid, &attr, ptree_event_thread, NULL))
3583 return (PICL_FAILURE);
3585 return (PICL_SUCCESS);
3589 xptree_reinitialize(void)
3591 int err;
3594 * Wait for eventq to become empty
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");
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);
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);
3618 (void) pthread_mutex_lock(&evtq_lock);
3619 (void) pthread_cond_broadcast(&evtq_cv);
3620 (void) pthread_mutex_unlock(&evtq_lock);
3622 return (err);
3626 * This function is called by the PICL daemon on behalf of clients to
3627 * wait for a tree refresh
3630 xptree_refresh_notify(uint32_t secs)
3632 int curgen;
3633 int ret;
3634 timespec_t to;
3636 if (secs != 0) {
3637 if (pthread_mutex_lock(&ptree_refresh_mutex) != 0)
3638 return (PICL_FAILURE);
3640 curgen = ptree_generation;
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;
3657 (void) pthread_mutex_unlock(&ptree_refresh_mutex);
3660 return (PICL_SUCCESS);
3663 /*VARARGS2*/
3664 void
3665 dbg_print(int level, const char *fmt, ...)
3667 if (verbose_level >= level) {
3668 va_list ap;
3670 va_start(ap, fmt);
3671 (void) vprintf(fmt, ap);
3672 va_end(ap);
3676 /*ARGSUSED*/
3677 void
3678 dbg_exec(int level, void (*fn)(void *args), void *args)
3680 if (verbose_level > level)
3681 (*fn)(args);