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