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