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