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