2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/*
2N/A * This module implements the PTree interface and the PICL to PTree calls
2N/A */
2N/A
2N/A/*
2N/A * Note:
2N/A * PICL Node and Property Handles Table:
2N/A * A node or property in PICL tree has two handles: a ptree handle, which is
2N/A * used by plug-ins and the libpicltree interface, and a picl handle
2N/A * which is used by clients and the libpicl interface.
2N/A * The mapping of ptree handles to the internal PICL object (picl_obj_t) is
2N/A * kept in a ptree hash table (ptreetbl), and the mapping of a picl handle
2N/A * to its ptree handle is kept in the picl hash table (picltbl).
2N/A * The reader/writer lock, ptree_rwlock, is held when reading or modifying ptree
2N/A * hash table (ptreetbl) and/or the PICL tree structure (nodes and linkages
2N/A * between them). The reader/writer lock, picltbl_rwlock, is held when reading
2N/A * or modifying picl hash table (picltbl).
2N/A *
2N/A * The mutex, ptreehdl_lock, is used to control allocation of ptree handles.
2N/A * The mutex, piclhdl_lock, is used to control allocation of picl handles.
2N/A *
2N/A * The mutex, ptree_refresh_mutex, and the condition, ptree_refresh_cond,
2N/A * are used to synchronize PICL refreshes (ptree_refresh) and to wait/signal
2N/A * change in PICL tree structure.
2N/A *
2N/A * The counter, picl_hdl_hi, is the hi water mark for allocated picl handles.
2N/A * The counter, ptree_hdl_hi, is the hi water mark for allocated ptree handles.
2N/A * A stale handle error is returned for handle values below the hi water
2N/A * mark, and invalid handles are returned for handle values above the hi water
2N/A * mark or when the process id field of the handle does not match.
2N/A *
2N/A * Locking Scheme:
2N/A * The structure of the PICL tree is controlled by the ptree_rwlock. The
2N/A * properties of a node are controlled by individual node locks. The
2N/A * piclize-ing or unpiclize-ing of a node is controlled by picltbl_rwlock.
2N/A *
2N/A * Two-Phase Locking scheme: lock acquire phase and lock release phase.
2N/A *
2N/A * Lock Ordering:
2N/A * The ptree_rwlock and node locks are always acquired in the following order:
2N/A * lock ptree_rwlock
2N/A * lock node
2N/A *
2N/A * Lock Strategy:
2N/A * There are three locks:
2N/A * ptree_rwlock: a reader lock is obtained to do ptree hash table
2N/A * lookups and traverse tree. A writer lock is obtained
2N/A * when creating or destroying nodes from the ptree,
2N/A * or when modifying node linkages: parent, peer, child.
2N/A * picltbl_rwlock: a reader lock is obtained for picl hash table lookups.
2N/A * A writer lock is obtained when piclize-ing or
2N/A * unpiclize-ing nodes or properties.
2N/A * node_lock: This is a reader/writer lock for properties of a node.
2N/A * A reader lock is obtained before reading property
2N/A * values. A writer lock is obtained when adding or
2N/A * removing properties and when modifying a property value.
2N/A *
2N/A * Never hold more than one node lock at a time.
2N/A *
2N/A * Event Locking:
2N/A * There are two locks:
2N/A * evtq_lock: this lock protects the event queue. It is obtained
2N/A * to queue events that are posted and to unqueue
2N/A * events to be dispatched.
2N/A * evtq_cv: condition variable is protected by evtq_lock. It is
2N/A * used by the ptree event thread to wait for events
2N/A * until eventqp is not NULL.
2N/A * evtq_empty: condition variable protected by evtq_lock. It is
2N/A * used to signal when the eventq becomes empty. The
2N/A * reinitialization process waits on this condition.
2N/A * evthandler_lock: this protects the event handler list. It is obtained
2N/A * to add event handlers on registration and to remove
2N/A * event handlers on unregistration.
2N/A * (handler)->cv: condition variable per handler protected by
2N/A * evthandler_lock. It is used to wait until the
2N/A * event handler completes execution (execflg == 0)
2N/A * before unregistering the handler.
2N/A */
2N/A
2N/A#include <stdio.h>
2N/A#include <string.h>
2N/A#include <strings.h>
2N/A#include <stdlib.h>
2N/A#include <stdarg.h>
2N/A#include <alloca.h>
2N/A#include <assert.h>
2N/A#include <errno.h>
2N/A#include <unistd.h>
2N/A#include <limits.h>
2N/A#include <libintl.h>
2N/A#include <syslog.h>
2N/A#include <pthread.h>
2N/A#include <synch.h>
2N/A#include <setjmp.h>
2N/A#include <signal.h>
2N/A#include <dlfcn.h>
2N/A#include <dirent.h>
2N/A#include <door.h>
2N/A#include <time.h>
2N/A#include <inttypes.h>
2N/A#include <sys/systeminfo.h>
2N/A#include <sys/utsname.h>
2N/A#include <picl.h>
2N/A#include <picltree.h>
2N/A#include "picldefs.h"
2N/A#include "ptree_impl.h"
2N/A
2N/A#define SO_VERS ".so.1"
2N/A
2N/Astatic hash_t picltbl; /* client handles to picl obj */
2N/Astatic hash_t ptreetbl; /* ptree handles to picl obj */
2N/Astatic pthread_mutex_t ptreehdl_lock;
2N/Astatic pthread_mutex_t piclhdl_lock;
2N/Astatic pthread_mutex_t ptree_refresh_mutex;
2N/Astatic rwlock_t picltbl_rwlock; /* PICL handle table lock */
2N/Astatic rwlock_t ptree_rwlock; /* PICL tree lock */
2N/Astatic pthread_cond_t ptree_refresh_cond = PTHREAD_COND_INITIALIZER;
2N/Astatic uint32_t ptree_hdl_hi = 1;
2N/Astatic uint32_t picl_hdl_hi = 1;
2N/Astatic picl_obj_t *picl_root_obj = NULL;
2N/Astatic picl_nodehdl_t ptree_root_hdl = PICL_INVALID_PICLHDL;
2N/Astatic int ptree_generation = 0;
2N/Astatic pid_t picld_pid;
2N/Astatic door_cred_t picld_cred;
2N/Astatic int qempty_wait; /* evtq_empty condition waiter flag */
2N/A
2N/Astatic picld_plugin_reg_list_t *plugin_reg_list = NULL;
2N/Astatic picld_plugin_desc_t *plugin_desc;
2N/A
2N/Astatic eventq_t *eventqp; /* PICL events queue */
2N/Astatic pthread_mutex_t evtq_lock = PTHREAD_MUTEX_INITIALIZER;
2N/Astatic pthread_cond_t evtq_cv = PTHREAD_COND_INITIALIZER;
2N/Astatic pthread_cond_t evtq_empty = PTHREAD_COND_INITIALIZER;
2N/Astatic evt_handler_t *evt_handlers; /* Event handler list */
2N/Astatic pthread_mutex_t evthandler_lock = PTHREAD_MUTEX_INITIALIZER;
2N/A
2N/A/*
2N/A * PICL daemon verbose level
2N/A */
2N/Aint verbose_level;
2N/A
2N/A
2N/A/*
2N/A * Event handler free functions
2N/A */
2N/Astatic void
2N/Afree_handler(evt_handler_t *evhp)
2N/A{
2N/A if (evhp->ename)
2N/A free(evhp->ename);
2N/A (void) pthread_cond_broadcast(&evhp->cv);
2N/A (void) pthread_cond_destroy(&evhp->cv);
2N/A free(evhp);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * queue_event to events queue
2N/A */
2N/Astatic void
2N/Aqueue_event(eventq_t *evt)
2N/A{
2N/A eventq_t *tmpp;
2N/A
2N/A evt->next = NULL;
2N/A if (eventqp == NULL)
2N/A eventqp = evt;
2N/A else {
2N/A tmpp = eventqp;
2N/A while (tmpp->next != NULL)
2N/A tmpp = tmpp->next;
2N/A tmpp->next = evt;
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * unqueue_event from the specified eventq
2N/A */
2N/Astatic eventq_t *
2N/Aunqueue_event(eventq_t **qp)
2N/A{
2N/A eventq_t *evtp;
2N/A
2N/A evtp = *qp;
2N/A if (evtp != NULL)
2N/A *qp = evtp->next;
2N/A return (evtp);
2N/A}
2N/A
2N/A/*
2N/A * register an event handler by adding it to the list
2N/A */
2N/Aint
2N/Aptree_register_handler(const char *ename,
2N/A void (*evt_handler)(const char *ename, const void *earg, size_t size,
2N/A void *cookie), void *cookie)
2N/A{
2N/A evt_handler_t *ent;
2N/A evt_handler_t *iter;
2N/A
2N/A if (ename == NULL)
2N/A return (PICL_INVALIDARG);
2N/A
2N/A /*
2N/A * Initialize event handler entry
2N/A */
2N/A ent = malloc(sizeof (*ent));
2N/A if (ent == NULL)
2N/A return (PICL_FAILURE);
2N/A ent->ename = strdup(ename);
2N/A if (ent->ename == NULL) {
2N/A free(ent);
2N/A return (PICL_FAILURE);
2N/A }
2N/A ent->cookie = cookie;
2N/A ent->evt_handler = evt_handler;
2N/A ent->execflg = 0;
2N/A ent->wakeupflg = 0;
2N/A (void) pthread_cond_init(&ent->cv, NULL);
2N/A ent->next = NULL;
2N/A
2N/A /*
2N/A * add handler to the handler list
2N/A */
2N/A (void) pthread_mutex_lock(&evthandler_lock);
2N/A if (evt_handlers == NULL) {
2N/A evt_handlers = ent;
2N/A (void) pthread_mutex_unlock(&evthandler_lock);
2N/A return (PICL_SUCCESS);
2N/A }
2N/A iter = evt_handlers;
2N/A while (iter->next != NULL)
2N/A iter = iter->next;
2N/A iter->next = ent;
2N/A (void) pthread_mutex_unlock(&evthandler_lock);
2N/A
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * unregister handler
2N/A */
2N/Avoid
2N/Aptree_unregister_handler(const char *ename,
2N/A void (*evt_handler)(const char *ename, const void *earg, size_t size,
2N/A void *cookie), void *cookie)
2N/A{
2N/A evt_handler_t *evhdlrp, **evhdlrpp;
2N/A
2N/A if (ename == NULL)
2N/A return;
2N/A
2N/A /*
2N/A * unlink handler from handler list
2N/A */
2N/A (void) pthread_mutex_lock(&evthandler_lock);
2N/A
2N/Aretry:
2N/A for (evhdlrpp = &evt_handlers; (evhdlrp = *evhdlrpp) != NULL;
2N/A evhdlrpp = &evhdlrp->next) {
2N/A if ((evhdlrp->cookie != cookie) ||
2N/A (strcmp(evhdlrp->ename, ename) != 0) ||
2N/A (evhdlrp->evt_handler != evt_handler))
2N/A continue;
2N/A
2N/A /*
2N/A * If the handler is in execution, release the lock
2N/A * and wait for it to complete and retry.
2N/A */
2N/A if (evhdlrp->execflg) {
2N/A evhdlrp->wakeupflg = 1;
2N/A (void) pthread_cond_wait(&evhdlrp->cv,
2N/A &evthandler_lock);
2N/A goto retry;
2N/A }
2N/A
2N/A /*
2N/A * Unlink this handler from the linked list
2N/A */
2N/A *evhdlrpp = evhdlrp->next;
2N/A free_handler(evhdlrp);
2N/A break;
2N/A }
2N/A
2N/A (void) pthread_mutex_unlock(&evthandler_lock);
2N/A}
2N/A
2N/A/*
2N/A * Call all registered handlers for the event
2N/A */
2N/Astatic void
2N/Acall_event_handlers(eventq_t *ev)
2N/A{
2N/A evt_handler_t *iter;
2N/A void (*evhandler)(const char *, const void *, size_t, void *);
2N/A void (*completion_handler)(char *ename, void *earg, size_t size);
2N/A
2N/A (void) pthread_mutex_lock(&evthandler_lock);
2N/A iter = evt_handlers;
2N/A while (iter != NULL) {
2N/A if (strcmp(iter->ename, ev->ename) == 0) {
2N/A evhandler = iter->evt_handler;
2N/A iter->execflg = 1;
2N/A (void) pthread_mutex_unlock(&evthandler_lock);
2N/A if (evhandler) {
2N/A dbg_print(2, "ptree_evthr: Invoking evthdlr:%p"
2N/A " ename:%s\n", evhandler, ev->ename);
2N/A (*evhandler)(ev->ename, ev->earg, ev->size,
2N/A iter->cookie);
2N/A dbg_print(2, "ptree_evthr: done evthdlr:%p "
2N/A "ename:%s\n", evhandler, ev->ename);
2N/A }
2N/A (void) pthread_mutex_lock(&evthandler_lock);
2N/A iter->execflg = 0;
2N/A if (iter->wakeupflg) {
2N/A iter->wakeupflg = 0;
2N/A (void) pthread_cond_broadcast(&iter->cv);
2N/A }
2N/A }
2N/A iter = iter->next;
2N/A }
2N/A (void) pthread_mutex_unlock(&evthandler_lock);
2N/A if ((completion_handler = ev->completion_handler) != NULL) {
2N/A dbg_print(2,
2N/A "ptree_evthr: Invoking completion hdlr:%p ename:%s\n",
2N/A completion_handler, ev->ename);
2N/A (*completion_handler)((char *)ev->ename, (void *)ev->earg,
2N/A ev->size);
2N/A dbg_print(2, "ptree_evthr: done completion hdlr:%p ename:%s\n",
2N/A completion_handler, ev->ename);
2N/A }
2N/A (void) pthread_mutex_lock(&ptree_refresh_mutex);
2N/A ++ptree_generation;
2N/A (void) pthread_cond_broadcast(&ptree_refresh_cond);
2N/A (void) pthread_mutex_unlock(&ptree_refresh_mutex);
2N/A}
2N/A
2N/A/*
2N/A * This function is called by a plug-in to post an event
2N/A */
2N/Aint
2N/Aptree_post_event(const char *ename, const void *earg, size_t size,
2N/A void (*completion_handler)(char *ename, void *earg, size_t size))
2N/A{
2N/A eventq_t *evt;
2N/A
2N/A if (ename == NULL)
2N/A return (PICL_INVALIDARG);
2N/A
2N/A evt = malloc(sizeof (*evt));
2N/A if (evt == NULL)
2N/A return (PICL_FAILURE);
2N/A evt->ename = ename;
2N/A evt->earg = earg;
2N/A evt->size = size;
2N/A evt->completion_handler = completion_handler;
2N/A
2N/A (void) pthread_mutex_lock(&evtq_lock);
2N/A queue_event(evt);
2N/A (void) pthread_cond_broadcast(&evtq_cv);
2N/A (void) pthread_mutex_unlock(&evtq_lock);
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * PICLTREE event thread
2N/A */
2N/A/*ARGSUSED*/
2N/Astatic void *
2N/Aptree_event_thread(void *argp)
2N/A{
2N/A eventq_t *evt;
2N/A
2N/A for (;;) {
2N/A (void) pthread_mutex_lock(&evtq_lock);
2N/A while (eventqp == NULL) {
2N/A /*
2N/A * Signal empty queue
2N/A */
2N/A if (qempty_wait)
2N/A (void) pthread_cond_broadcast(&evtq_empty);
2N/A (void) pthread_cond_wait(&evtq_cv, &evtq_lock);
2N/A }
2N/A if ((evt = unqueue_event(&eventqp)) != NULL) {
2N/A (void) pthread_mutex_unlock(&evtq_lock);
2N/A call_event_handlers(evt);
2N/A free(evt);
2N/A } else
2N/A (void) pthread_mutex_unlock(&evtq_lock);
2N/A }
2N/A /*NOTREACHED*/
2N/A return (NULL);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Create a new element
2N/A */
2N/Astatic hash_elem_t *
2N/Ahash_newobj(uint32_t hdl_val, void *obj_val)
2N/A{
2N/A hash_elem_t *n;
2N/A
2N/A n = malloc(sizeof (*n));
2N/A if (n == NULL)
2N/A return (NULL);
2N/A n->hdl = hdl_val;
2N/A n->hash_obj = obj_val;
2N/A n->next = NULL;
2N/A return (n);
2N/A}
2N/A
2N/Astatic hash_elem_t *
2N/Ahash_newhdl(uint32_t picl_hdl, uint32_t ptreeh)
2N/A{
2N/A hash_elem_t *n;
2N/A
2N/A n = malloc(sizeof (*n));
2N/A if (n == NULL)
2N/A return (NULL);
2N/A n->hdl = picl_hdl;
2N/A n->hash_hdl = ptreeh;
2N/A n->next = NULL;
2N/A return (n);
2N/A}
2N/A
2N/A/*
2N/A * Initialize a hash table by setting all entries to NULL
2N/A */
2N/Astatic int
2N/Ahash_init(hash_t *htbl)
2N/A{
2N/A int i;
2N/A
2N/A htbl->hash_size = HASH_TBL_SIZE;
2N/A htbl->tbl = malloc(sizeof (hash_elem_t *) * HASH_TBL_SIZE);
2N/A if (htbl->tbl == NULL)
2N/A return (-1);
2N/A for (i = 0; i < htbl->hash_size; ++i)
2N/A htbl->tbl[i] = NULL;
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Lock free function to add an entry in the hash table
2N/A */
2N/Astatic int
2N/Ahash_add_newobj(hash_t *htbl, picl_hdl_t hdl, void *pobj)
2N/A{
2N/A int indx;
2N/A hash_elem_t *n;
2N/A uint32_t hash_val = HASH_VAL(hdl);
2N/A
2N/A n = hash_newobj(hash_val, pobj);
2N/A if (n == NULL)
2N/A return (-1);
2N/A indx = HASH_INDEX(htbl->hash_size, hash_val);
2N/A n->next = htbl->tbl[indx];
2N/A htbl->tbl[indx] = n;
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Ahash_add_newhdl(hash_t *htbl, picl_hdl_t piclh, picl_hdl_t ptreeh)
2N/A{
2N/A int indx;
2N/A hash_elem_t *n;
2N/A uint32_t picl_val = HASH_VAL(piclh);
2N/A uint32_t ptree_val = HASH_VAL(ptreeh);
2N/A
2N/A n = hash_newhdl(picl_val, ptree_val);
2N/A if (n == NULL)
2N/A return (-1);
2N/A
2N/A indx = HASH_INDEX(htbl->hash_size, picl_val);
2N/A n->next = htbl->tbl[indx];
2N/A htbl->tbl[indx] = n;
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Lock free function to remove the handle from the hash table
2N/A * Returns -1 if element not found, 0 if successful
2N/A */
2N/Astatic int
2N/Ahash_remove(hash_t *htbl, picl_hdl_t hdl)
2N/A{
2N/A hash_elem_t *nxt;
2N/A hash_elem_t *cur;
2N/A int i;
2N/A uint32_t hash_val = HASH_VAL(hdl);
2N/A
2N/A i = HASH_INDEX(htbl->hash_size, hash_val);
2N/A if (htbl->tbl[i] == NULL)
2N/A return (-1);
2N/A
2N/A cur = htbl->tbl[i];
2N/A if (cur->hdl == hash_val) {
2N/A htbl->tbl[i] = cur->next;
2N/A free(cur);
2N/A return (0);
2N/A }
2N/A nxt = cur->next;
2N/A while (nxt != NULL) {
2N/A if (nxt->hdl == hash_val) {
2N/A cur->next = nxt->next;
2N/A free(nxt);
2N/A return (0);
2N/A }
2N/A cur = nxt;
2N/A nxt = nxt->next;
2N/A }
2N/A return (-1);
2N/A}
2N/A
2N/A/*
2N/A * Lock free function to lookup the hash table for a given handle
2N/A * Returns NULL if not found
2N/A */
2N/Astatic void *
2N/Ahash_lookup_obj(hash_t *htbl, picl_hdl_t hdl)
2N/A{
2N/A hash_elem_t *tmp;
2N/A int i;
2N/A uint32_t hash_val;
2N/A
2N/A hash_val = HASH_VAL(hdl);
2N/A i = HASH_INDEX(htbl->hash_size, hash_val);
2N/A tmp = htbl->tbl[i];
2N/A while (tmp != NULL) {
2N/A if (tmp->hdl == hash_val)
2N/A return (tmp->hash_obj);
2N/A tmp = tmp->next;
2N/A }
2N/A return (NULL);
2N/A}
2N/A
2N/Astatic picl_hdl_t
2N/Ahash_lookup_hdl(hash_t *htbl, picl_hdl_t hdl)
2N/A{
2N/A hash_elem_t *tmp;
2N/A int i;
2N/A uint32_t hash_val;
2N/A
2N/A hash_val = HASH_VAL(hdl);
2N/A i = HASH_INDEX(htbl->hash_size, hash_val);
2N/A tmp = htbl->tbl[i];
2N/A while (tmp != NULL) {
2N/A if (tmp->hdl == hash_val)
2N/A return (MAKE_HANDLE(picld_pid, tmp->hash_hdl));
2N/A tmp = tmp->next;
2N/A }
2N/A return (PICL_INVALID_PICLHDL);
2N/A}
2N/A
2N/A/*
2N/A * Is the PICL handle stale or invalid handle?
2N/A */
2N/Astatic int
2N/Apicl_hdl_error(picl_hdl_t hdl)
2N/A{
2N/A uint32_t hash_val = HASH_VAL(hdl);
2N/A pid_t pid = GET_PID(hdl);
2N/A int err;
2N/A
2N/A (void) pthread_mutex_lock(&piclhdl_lock);
2N/A err = PICL_STALEHANDLE;
2N/A if ((pid != picld_pid) || (hash_val >= picl_hdl_hi) ||
2N/A (hash_val == NULL))
2N/A err = PICL_INVALIDHANDLE;
2N/A (void) pthread_mutex_unlock(&piclhdl_lock);
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Is the Ptree handle stale or invalid handle?
2N/A */
2N/Astatic int
2N/Aptree_hdl_error(picl_hdl_t hdl)
2N/A{
2N/A uint32_t hash_val = HASH_VAL(hdl);
2N/A pid_t pid = GET_PID(hdl);
2N/A int err;
2N/A
2N/A (void) pthread_mutex_lock(&ptreehdl_lock);
2N/A err = PICL_STALEHANDLE;
2N/A if ((pid != picld_pid) || (hash_val >= ptree_hdl_hi) ||
2N/A (hash_val == NULL))
2N/A err = PICL_INVALIDHANDLE;
2N/A (void) pthread_mutex_unlock(&ptreehdl_lock);
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * For a PICL handle, return the PTree handle and the PICL object
2N/A * Locks and releases the PICL table.
2N/A */
2N/Aint
2N/Acvt_picl2ptree(picl_hdl_t hdl, picl_hdl_t *ptree_hdl)
2N/A{
2N/A picl_hdl_t tmph;
2N/A int err;
2N/A
2N/A (void) rw_rdlock(&picltbl_rwlock); /* lock picl */
2N/A tmph = hash_lookup_hdl(&picltbl, hdl);
2N/A if (tmph == PICL_INVALID_PICLHDL) {
2N/A err = picl_hdl_error(hdl);
2N/A (void) rw_unlock(&picltbl_rwlock); /* unlock picl */
2N/A return (err);
2N/A }
2N/A *ptree_hdl = tmph;
2N/A (void) rw_unlock(&picltbl_rwlock); /* unlock picl */
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Allocate a ptree handle
2N/A */
2N/Astatic picl_hdl_t
2N/Aalloc_ptreehdl(void)
2N/A{
2N/A picl_hdl_t hdl;
2N/A
2N/A (void) pthread_mutex_lock(&ptreehdl_lock); /* lock ptreehdl */
2N/A hdl = MAKE_HANDLE(picld_pid, ptree_hdl_hi);
2N/A ++ptree_hdl_hi;
2N/A (void) pthread_mutex_unlock(&ptreehdl_lock); /* unlock ptreehdl */
2N/A return (hdl);
2N/A}
2N/A
2N/A/*
2N/A * Allocate a picl handle
2N/A * A PICL handle is ptree_hdl value with 1 in MSB of handle value.
2N/A * If a ptree handle already has 1 in MSB, then it cannot be piclized
2N/A * and the daemon must be restarted.
2N/A */
2N/Astatic picl_hdl_t
2N/Aalloc_piclhdl(void)
2N/A{
2N/A picl_hdl_t hdl;
2N/A
2N/A (void) pthread_mutex_lock(&piclhdl_lock); /* lock piclhdl */
2N/A hdl = MAKE_HANDLE(picld_pid, picl_hdl_hi);
2N/A ++picl_hdl_hi;
2N/A (void) pthread_mutex_unlock(&piclhdl_lock); /* unlock piclhdl */
2N/A return (hdl);
2N/A}
2N/A
2N/A/*
2N/A * Allocate and add handle to PTree hash table
2N/A */
2N/Astatic void
2N/Aalloc_and_add_to_ptree(picl_obj_t *pobj)
2N/A{
2N/A pobj->ptree_hdl = alloc_ptreehdl();
2N/A (void) rw_wrlock(&ptree_rwlock);
2N/A (void) hash_add_newobj(&ptreetbl, pobj->ptree_hdl, pobj);
2N/A (void) rw_unlock(&ptree_rwlock);
2N/A}
2N/A
2N/A/*
2N/A * Lock a picl node object
2N/A */
2N/Astatic int
2N/Alock_obj(int rw, picl_obj_t *nodep)
2N/A{
2N/A if (rw == RDLOCK_NODE)
2N/A (void) rw_rdlock(&nodep->node_lock);
2N/A else if (rw == WRLOCK_NODE)
2N/A (void) rw_wrlock(&nodep->node_lock);
2N/A else
2N/A return (-1);
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Release the picl node object.
2N/A * This function may be called with a NULL object pointer.
2N/A */
2N/Astatic void
2N/Aunlock_node(picl_obj_t *nodep)
2N/A{
2N/A if (nodep == NULL)
2N/A return;
2N/A (void) rw_unlock(&nodep->node_lock);
2N/A}
2N/A
2N/A/*
2N/A * This function locks the node of a property and returns the node object
2N/A * and the property object.
2N/A */
2N/Astatic int
2N/Alookup_and_lock_propnode(int rw, picl_prophdl_t proph, picl_obj_t **nodep,
2N/A picl_obj_t **propp)
2N/A{
2N/A picl_obj_t *pobj;
2N/A picl_obj_t *nobj;
2N/A
2N/A pobj = hash_lookup_obj(&ptreetbl, proph);
2N/A if (pobj == NULL)
2N/A return (ptree_hdl_error(proph));
2N/A
2N/A /*
2N/A * Get the property's or table entry's node object
2N/A */
2N/A nobj = NULL;
2N/A if (pobj->obj_type == PICL_OBJ_PROP)
2N/A nobj = pobj->prop_node;
2N/A else if (pobj->obj_type == (PICL_OBJ_PROP|PICL_OBJ_TABLEENTRY))
2N/A nobj = pobj->prop_table->prop_node;
2N/A else {
2N/A *propp = pobj; /* return the prop */
2N/A return (PICL_NOTPROP);
2N/A }
2N/A
2N/A if (nobj && (lock_obj(rw, nobj) < 0)) /* Lock node */
2N/A return (PICL_FAILURE);
2N/A
2N/A *nodep = nobj;
2N/A *propp = pobj;
2N/A
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * This function locks the node of a table and returns the node object
2N/A * and the table object.
2N/A */
2N/Astatic int
2N/Alookup_and_lock_tablenode(int rw, picl_prophdl_t tblh, picl_obj_t **nodep,
2N/A picl_obj_t **tblobj)
2N/A{
2N/A picl_obj_t *pobj;
2N/A picl_obj_t *nobj;
2N/A
2N/A pobj = hash_lookup_obj(&ptreetbl, tblh);
2N/A if (pobj == NULL)
2N/A return (ptree_hdl_error(tblh));
2N/A
2N/A /*
2N/A * Get the property's or table entry's node object
2N/A */
2N/A nobj = NULL;
2N/A if (pobj->obj_type != PICL_OBJ_TABLE)
2N/A return (PICL_NOTTABLE);
2N/A nobj = pobj->prop_node;
2N/A
2N/A if (nobj && (lock_obj(rw, nobj) < 0)) /* Lock node */
2N/A return (PICL_FAILURE);
2N/A
2N/A *nodep = nobj;
2N/A *tblobj = pobj;
2N/A
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * This locks the node of a table or a table entry and returns the
2N/A * node object and the table or table entry object
2N/A */
2N/Astatic int
2N/Alookup_and_lock_tableprop_node(int rw, picl_prophdl_t tblproph,
2N/A picl_obj_t **nodep, picl_obj_t **tblpropp)
2N/A{
2N/A picl_obj_t *pobj;
2N/A picl_obj_t *nobj;
2N/A
2N/A pobj = hash_lookup_obj(&ptreetbl, tblproph);
2N/A if (pobj == NULL)
2N/A return (ptree_hdl_error(tblproph));
2N/A
2N/A /*
2N/A * Get the property's or table entry's node object
2N/A */
2N/A nobj = NULL;
2N/A if ((pobj->obj_type != PICL_OBJ_TABLE) && /* not a table */
2N/A !(pobj->obj_type & PICL_OBJ_TABLEENTRY)) /* or an entry */
2N/A return (PICL_NOTTABLE);
2N/A if (pobj->obj_type == PICL_OBJ_TABLE)
2N/A nobj = pobj->prop_node;
2N/A else
2N/A nobj = pobj->prop_table->prop_node;
2N/A
2N/A if (nobj && (lock_obj(rw, nobj) < 0)) /* Lock node */
2N/A return (PICL_FAILURE);
2N/A
2N/A *tblpropp = pobj;
2N/A *nodep = nobj;
2N/A
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Lock the node corresponding to the given handle and return its object
2N/A */
2N/Astatic int
2N/Alookup_and_lock_node(int rw, picl_nodehdl_t nodeh, picl_obj_t **nodep)
2N/A{
2N/A picl_obj_t *nobj;
2N/A
2N/A nobj = hash_lookup_obj(&ptreetbl, nodeh);
2N/A if (nobj == NULL)
2N/A return (ptree_hdl_error(nodeh));
2N/A else if (nobj->obj_type != PICL_OBJ_NODE)
2N/A return (PICL_NOTNODE);
2N/A if (lock_obj(rw, nobj) < 0) /* Lock node */
2N/A return (PICL_FAILURE);
2N/A *nodep = nobj;
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Is the property name a restricted property name?
2N/A */
2N/Astatic int
2N/Apicl_restricted(const char *name)
2N/A{
2N/A if (strcmp(name, PICL_PROP_CLASSNAME) == 0)
2N/A return (0); /* not restricted */
2N/A
2N/A if ((name[0] == '_') && (strchr(&name[1], '_') == NULL))
2N/A return (1);
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Check the value size with the property size
2N/A * Return PICL_INVALIDARG if the size does not match exactly for strongly
2N/A * typed properties.
2N/A * For charstring reads allow sizes that match the value size
2N/A * For bytearray return PICL_VALUETOOBIG
2N/A * if the size is greater than the buffer size.
2N/A */
2N/Astatic int
2N/Acheck_propsize(int op, picl_obj_t *propp, size_t sz)
2N/A{
2N/A if (propp->prop_mode & PICL_VOLATILE) {
2N/A if (sz != propp->prop_size)
2N/A return (PICL_INVALIDARG);
2N/A else
2N/A return (PICL_SUCCESS);
2N/A }
2N/A
2N/A /*
2N/A * check size for non-volatile properties
2N/A */
2N/A switch (propp->prop_type) {
2N/A case PICL_PTYPE_CHARSTRING:
2N/A if ((op == PROP_READ) &&
2N/A (strlen(propp->prop_val) >= sz))
2N/A return (PICL_VALUETOOBIG);
2N/A if ((op == PROP_WRITE) && (sz > propp->prop_size))
2N/A return (PICL_VALUETOOBIG);
2N/A break;
2N/A case PICL_PTYPE_BYTEARRAY:
2N/A if (op == PROP_WRITE) {
2N/A if (sz > propp->prop_size)
2N/A return (PICL_VALUETOOBIG);
2N/A return (PICL_SUCCESS); /* allow small writes */
2N/A }
2N/A /* fall through for reads */
2N/A default:
2N/A if (propp->prop_size != sz)
2N/A return (PICL_INVALIDARG);
2N/A break;
2N/A }
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/Avoid
2N/Acvt_ptree2picl(picl_hdl_t *handlep)
2N/A{
2N/A picl_obj_t *pobj;
2N/A
2N/A (void) rw_rdlock(&ptree_rwlock);
2N/A pobj = hash_lookup_obj(&ptreetbl, *handlep);
2N/A if (pobj == NULL)
2N/A *handlep = PICL_INVALID_PICLHDL;
2N/A else
2N/A (void) memcpy(handlep, &pobj->picl_hdl, sizeof (*handlep));
2N/A (void) rw_unlock(&ptree_rwlock);
2N/A}
2N/A
2N/A/*
2N/A * The caller of the piclize() set of functions is assumed to hold
2N/A * the ptree_rwlock().
2N/A */
2N/Astatic void
2N/Apiclize_obj(picl_obj_t *pobj)
2N/A{
2N/A (void) rw_wrlock(&picltbl_rwlock);
2N/A pobj->picl_hdl = alloc_piclhdl();
2N/A (void) hash_add_newhdl(&picltbl, pobj->picl_hdl, pobj->ptree_hdl);
2N/A (void) rw_unlock(&picltbl_rwlock);
2N/A}
2N/A
2N/Astatic void
2N/Apiclize_table(picl_obj_t *tbl_obj)
2N/A{
2N/A picl_obj_t *rowp;
2N/A picl_obj_t *colp;
2N/A
2N/A for (rowp = tbl_obj->next_row; rowp != NULL; rowp = rowp->next_col)
2N/A for (colp = rowp; colp != NULL; colp = colp->next_row)
2N/A piclize_obj(colp);
2N/A}
2N/A
2N/Astatic void
2N/Apiclize_prop(picl_obj_t *propp)
2N/A{
2N/A picl_obj_t *tbl_obj;
2N/A picl_prophdl_t tblh;
2N/A
2N/A piclize_obj(propp);
2N/A if (!(propp->prop_mode & PICL_VOLATILE) &&
2N/A (propp->prop_type == PICL_PTYPE_TABLE)) {
2N/A tblh = *(picl_prophdl_t *)propp->prop_val;
2N/A tbl_obj = hash_lookup_obj(&ptreetbl, tblh);
2N/A if (tbl_obj == NULL)
2N/A return;
2N/A piclize_obj(tbl_obj);
2N/A piclize_table(tbl_obj);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Function to create PICL handles for a subtree and add them to
2N/A * the table
2N/A */
2N/Astatic void
2N/Apiclize_node(picl_obj_t *nodep)
2N/A{
2N/A picl_obj_t *propp;
2N/A picl_obj_t *chdp;
2N/A
2N/A piclize_obj(nodep);
2N/A propp = nodep->first_prop;
2N/A while (propp != NULL) {
2N/A piclize_prop(propp);
2N/A propp = propp->next_prop;
2N/A }
2N/A
2N/A /* go through the children */
2N/A for (chdp = nodep->child_node; chdp != NULL; chdp = chdp->sibling_node)
2N/A piclize_node(chdp);
2N/A}
2N/A
2N/A/*
2N/A * Function to remove PICL handles
2N/A */
2N/Astatic void
2N/Aunpiclize_obj(picl_obj_t *pobj)
2N/A{
2N/A (void) rw_wrlock(&picltbl_rwlock);
2N/A (void) hash_remove(&picltbl, pobj->picl_hdl);
2N/A pobj->picl_hdl = PICL_INVALID_PICLHDL;
2N/A (void) rw_unlock(&picltbl_rwlock);
2N/A}
2N/A
2N/Astatic void
2N/Aunpiclize_table(picl_obj_t *tbl_obj)
2N/A{
2N/A picl_obj_t *rowp;
2N/A picl_obj_t *colp;
2N/A
2N/A for (rowp = tbl_obj->next_row; rowp != NULL; rowp = rowp->next_col)
2N/A for (colp = rowp; colp != NULL; colp = colp->next_row)
2N/A unpiclize_obj(colp);
2N/A unpiclize_obj(tbl_obj);
2N/A}
2N/A
2N/Astatic void
2N/Aunpiclize_prop(picl_obj_t *propp)
2N/A{
2N/A picl_obj_t *tbl_obj;
2N/A picl_prophdl_t tblh;
2N/A
2N/A if (!IS_PICLIZED(propp))
2N/A return;
2N/A unpiclize_obj(propp);
2N/A if (!(propp->prop_mode & PICL_VOLATILE) &&
2N/A (propp->prop_type == PICL_PTYPE_TABLE)) {
2N/A tblh = *(picl_prophdl_t *)propp->prop_val;
2N/A tbl_obj = hash_lookup_obj(&ptreetbl, tblh);
2N/A unpiclize_table(tbl_obj);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Function to remove PICL handles for a subtree and its
2N/A * properties
2N/A */
2N/Astatic void
2N/Aunpiclize_node(picl_obj_t *nodep)
2N/A{
2N/A picl_obj_t *propp;
2N/A picl_obj_t *chdp;
2N/A
2N/A
2N/A if (!IS_PICLIZED(nodep))
2N/A return;
2N/A
2N/A unpiclize_obj(nodep);
2N/A propp = nodep->first_prop;
2N/A while (propp != NULL) {
2N/A unpiclize_prop(propp);
2N/A propp = propp->next_prop;
2N/A }
2N/A
2N/A /* go through the children */
2N/A for (chdp = nodep->child_node; chdp != NULL; chdp = chdp->sibling_node)
2N/A unpiclize_node(chdp);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * The caller holds the lock on the ptree_lock when calling this.
2N/A * If ret is not NULL then this function returns the referenced object.
2N/A */
2N/Astatic int
2N/Alookup_verify_ref_prop(picl_obj_t *propp, picl_obj_t **ret)
2N/A{
2N/A picl_nodehdl_t refh;
2N/A picl_obj_t *refobj;
2N/A
2N/A refh = *(picl_nodehdl_t *)propp->prop_val;
2N/A refobj = hash_lookup_obj(&ptreetbl, refh);
2N/A if (refobj == NULL)
2N/A return (ptree_hdl_error(refh));
2N/A else if (refobj->obj_type != PICL_OBJ_NODE)
2N/A return (PICL_INVREFERENCE);
2N/A if (ret)
2N/A *ret = refobj;
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * The caller holds the lock on ptree_lock when calling this.
2N/A * If ret is not NULL, then this function returns the table object
2N/A */
2N/Astatic int
2N/Alookup_verify_table_prop(picl_obj_t *propp, picl_obj_t **ret)
2N/A{
2N/A picl_prophdl_t tblh;
2N/A picl_obj_t *tbl_obj;
2N/A
2N/A tblh = *(picl_prophdl_t *)propp->prop_val;
2N/A tbl_obj = hash_lookup_obj(&ptreetbl, tblh);
2N/A if (tbl_obj == NULL)
2N/A return (ptree_hdl_error(tblh));
2N/A else if (!(tbl_obj->obj_type & PICL_OBJ_TABLE))
2N/A return (PICL_NOTTABLE);
2N/A if (ret)
2N/A *ret = tbl_obj;
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/Astatic int
2N/Alookup_verify_prop_handle(picl_prophdl_t proph, picl_obj_t **ret)
2N/A{
2N/A picl_obj_t *propp;
2N/A
2N/A propp = hash_lookup_obj(&ptreetbl, proph);
2N/A if (propp == NULL)
2N/A return (ptree_hdl_error(proph));
2N/A else if (!(propp->obj_type & PICL_OBJ_PROP))
2N/A return (PICL_NOTPROP);
2N/A if (ret)
2N/A *ret = propp;
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/Astatic int
2N/Alookup_verify_node_handle(picl_nodehdl_t nodeh, picl_obj_t **ret)
2N/A{
2N/A picl_obj_t *nodep;
2N/A
2N/A nodep = hash_lookup_obj(&ptreetbl, nodeh);
2N/A if (nodep == NULL)
2N/A return (ptree_hdl_error(nodeh));
2N/A else if (nodep->obj_type != PICL_OBJ_NODE)
2N/A return (PICL_NOTNODE);
2N/A if (ret)
2N/A *ret = nodep;
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/Astatic int
2N/Alookup_prop_by_name(picl_obj_t *nodep, const char *pname, picl_obj_t **ret)
2N/A{
2N/A picl_obj_t *propp;
2N/A
2N/A if (strcmp(pname, PICL_PROP_PARENT) == 0) {
2N/A if (nodep->parent_node == NULL)
2N/A return (PICL_PROPNOTFOUND);
2N/A else
2N/A return (PICL_SUCCESS);
2N/A }
2N/A if (strcmp(pname, PICL_PROP_CHILD) == 0) {
2N/A if (nodep->child_node == NULL)
2N/A return (PICL_PROPNOTFOUND);
2N/A else
2N/A return (PICL_SUCCESS);
2N/A }
2N/A if (strcmp(pname, PICL_PROP_PEER) == 0) {
2N/A if (nodep->sibling_node == NULL)
2N/A return (PICL_PROPNOTFOUND);
2N/A else
2N/A return (PICL_SUCCESS);
2N/A }
2N/A
2N/A propp = nodep->first_prop;
2N/A while (propp != NULL) {
2N/A if (strcmp(propp->prop_name, pname) == 0) {
2N/A if (ret)
2N/A *ret = propp;
2N/A return (PICL_SUCCESS);
2N/A }
2N/A propp = propp->next_prop;
2N/A }
2N/A return (PICL_PROPNOTFOUND);
2N/A}
2N/A
2N/A/*
2N/A * This function locks the ptree, verifies that the handle is a reference
2N/A * to a node of specified class name, releases the lock
2N/A */
2N/Astatic int
2N/Acheck_ref_handle(picl_nodehdl_t refh, char *clname)
2N/A{
2N/A picl_obj_t *refobj;
2N/A picl_obj_t *propp;
2N/A int err;
2N/A
2N/A (void) rw_rdlock(&ptree_rwlock); /* Lock ptree */
2N/A refobj = hash_lookup_obj(&ptreetbl, refh);
2N/A if ((refobj == NULL) || !(refobj->obj_type & PICL_OBJ_NODE)) {
2N/A (void) rw_unlock(&ptree_rwlock);
2N/A return (PICL_INVREFERENCE);
2N/A }
2N/A
2N/A err = lookup_prop_by_name(refobj, PICL_PROP_CLASSNAME, &propp);
2N/A if ((err != PICL_SUCCESS) || (propp->prop_val == NULL) ||
2N/A (strcmp(propp->prop_val, clname) != 0))
2N/A err = PICL_INVREFERENCE;
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A}
2N/A
2N/Astatic int
2N/Acheck_table_handle(picl_prophdl_t tblh)
2N/A{
2N/A picl_obj_t *tbl_obj;
2N/A int err;
2N/A
2N/A (void) rw_rdlock(&ptree_rwlock);
2N/A err = PICL_SUCCESS;
2N/A tbl_obj = hash_lookup_obj(&ptreetbl, tblh);
2N/A if ((tbl_obj == NULL) || !(tbl_obj->obj_type & PICL_OBJ_TABLE))
2N/A err = PICL_NOTTABLE;
2N/A (void) rw_unlock(&ptree_rwlock);
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * PICLTree Interface routines for plug-in modules
2N/A */
2N/Aint
2N/Aptree_get_root(picl_nodehdl_t *rooth)
2N/A{
2N/A *rooth = ptree_root_hdl;
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Lock free create a property object
2N/A */
2N/Astatic int
2N/Acreate_propobj(const ptree_propinfo_t *pinfo, const void *valbuf,
2N/A picl_obj_t **pobjp)
2N/A{
2N/A picl_obj_t *pobj;
2N/A
2N/A if (pinfo->version != PTREE_PROPINFO_VERSION_1)
2N/A return (PICL_NOTSUPPORTED);
2N/A
2N/A if (!(pinfo->piclinfo.accessmode & PICL_VOLATILE) &&
2N/A (pinfo->piclinfo.type != PICL_PTYPE_VOID) &&
2N/A (valbuf == NULL))
2N/A return (PICL_INVALIDARG);
2N/A
2N/A pobj = malloc(sizeof (picl_obj_t));
2N/A if (pobj == NULL)
2N/A return (PICL_FAILURE);
2N/A
2N/A pobj->obj_type = PICL_OBJ_PROP;
2N/A pobj->pinfo_ver = pinfo->version;
2N/A pobj->prop_type = pinfo->piclinfo.type;
2N/A pobj->prop_mode = pinfo->piclinfo.accessmode;
2N/A pobj->prop_size = pinfo->piclinfo.size;
2N/A (void) strcpy(pobj->prop_name, pinfo->piclinfo.name);
2N/A pobj->read_func = pinfo->read;
2N/A pobj->write_func = pinfo->write;
2N/A
2N/A pobj->prop_val = NULL;
2N/A if (!(pinfo->piclinfo.accessmode & PICL_VOLATILE)) {
2N/A pobj->prop_val = malloc(pinfo->piclinfo.size);
2N/A if (pobj->prop_val == NULL) {
2N/A free(pobj);
2N/A return (PICL_FAILURE);
2N/A }
2N/A if (pobj->prop_type == PICL_PTYPE_CHARSTRING)
2N/A (void) strlcpy(pobj->prop_val, valbuf,
2N/A pinfo->piclinfo.size);
2N/A else
2N/A (void) memcpy(pobj->prop_val, valbuf,
2N/A pinfo->piclinfo.size);
2N/A }
2N/A pobj->prop_node = NULL;
2N/A pobj->ptree_hdl = PICL_INVALID_PICLHDL;
2N/A pobj->picl_hdl = PICL_INVALID_PICLHDL;
2N/A pobj->next_prop = NULL;
2N/A pobj->next_row = NULL;
2N/A pobj->next_col = NULL;
2N/A
2N/A *pobjp = pobj;
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Check for valid arguments, create a property object,
2N/A * Lock ptree_rwlock, add the new property handle, release the lock
2N/A * For reference properties and table properties, the handles are verified
2N/A * before creating the property.
2N/A */
2N/Aint
2N/Aptree_create_prop(const ptree_propinfo_t *pinfo, const void *valbuf,
2N/A picl_prophdl_t *proph)
2N/A{
2N/A picl_obj_t *pobj;
2N/A picl_nodehdl_t refh;
2N/A picl_prophdl_t tblh;
2N/A int err;
2N/A char *ptr;
2N/A int refflag;
2N/A char classname[PICL_PROPNAMELEN_MAX];
2N/A
2N/A if (pinfo == NULL)
2N/A return (PICL_INVALIDARG);
2N/A if (pinfo->version != PTREE_PROPINFO_VERSION_1)
2N/A return (PICL_NOTSUPPORTED);
2N/A if (pinfo->piclinfo.size >= PICL_PROPSIZE_MAX)
2N/A return (PICL_VALUETOOBIG);
2N/A if (picl_restricted(pinfo->piclinfo.name))
2N/A return (PICL_RESERVEDNAME);
2N/A
2N/A refflag = 0;
2N/A if ((pinfo->piclinfo.name[0] == '_') &&
2N/A (strchr(&pinfo->piclinfo.name[1], '_') != NULL))
2N/A refflag = 1;
2N/A
2N/A if (pinfo->piclinfo.type == PICL_PTYPE_REFERENCE) {
2N/A if (refflag == 0)
2N/A return (PICL_INVREFERENCE);
2N/A /*
2N/A * check valid reference handle for non-volatiles
2N/A */
2N/A if (!(pinfo->piclinfo.accessmode & PICL_VOLATILE)) {
2N/A if (valbuf == NULL)
2N/A return (PICL_INVREFERENCE);
2N/A if (pinfo->piclinfo.size != sizeof (picl_nodehdl_t))
2N/A return (PICL_INVREFERENCE);
2N/A (void) strcpy(classname, pinfo->piclinfo.name);
2N/A ptr = strchr(&classname[1], '_');
2N/A *ptr = '\0';
2N/A refh = *(picl_hdl_t *)valbuf;
2N/A err = check_ref_handle(refh, &classname[1]);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A }
2N/A } else if (refflag == 1)
2N/A return (PICL_INVREFERENCE);
2N/A else if ((pinfo->piclinfo.type == PICL_PTYPE_TABLE) &&
2N/A (!(pinfo->piclinfo.accessmode & PICL_VOLATILE))) {
2N/A if (pinfo->piclinfo.size != sizeof (picl_prophdl_t))
2N/A return (PICL_INVALIDARG);
2N/A tblh = *(picl_prophdl_t *)valbuf;
2N/A err = check_table_handle(tblh);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A } else if ((strcmp(pinfo->piclinfo.name, PICL_PROP_CLASSNAME) == 0) &&
2N/A ((pinfo->piclinfo.type != PICL_PTYPE_CHARSTRING) ||
2N/A (strlen(valbuf) >= PICL_CLASSNAMELEN_MAX)))
2N/A return (PICL_RESERVEDNAME);
2N/A else if ((strcmp(pinfo->piclinfo.name, PICL_PROP_NAME) == 0) &&
2N/A (pinfo->piclinfo.type != PICL_PTYPE_CHARSTRING))
2N/A return (PICL_RESERVEDNAME);
2N/A /*
2N/A * No locks held when you get here
2N/A */
2N/A err = create_propobj(pinfo, valbuf, &pobj);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A alloc_and_add_to_ptree(pobj);
2N/A *proph = pobj->ptree_hdl;
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Lock free routine to destroy table entries
2N/A * This function removes the destroyed handles from the hash table
2N/A * Uses lock free routines: hash_lookup() and hash_remove()
2N/A */
2N/Astatic void
2N/Adestroy_table(picl_obj_t *pobj)
2N/A{
2N/A picl_prophdl_t tblh;
2N/A picl_obj_t *tbl_obj;
2N/A picl_obj_t *rowp;
2N/A picl_obj_t *colp;
2N/A picl_obj_t *freep;
2N/A
2N/A tblh = *(picl_prophdl_t *)pobj->prop_val;
2N/A tbl_obj = hash_lookup_obj(&ptreetbl, tblh);
2N/A if (tbl_obj == NULL)
2N/A return;
2N/A
2N/A assert(tbl_obj->obj_type & PICL_OBJ_TABLE);
2N/A
2N/A /* Delete all entries */
2N/A rowp = tbl_obj->next_row;
2N/A while (rowp != NULL) {
2N/A colp = rowp;
2N/A rowp = rowp->next_col;
2N/A while (colp != NULL) {
2N/A freep = colp;
2N/A colp = colp->next_row;
2N/A (void) hash_remove(&ptreetbl, freep->ptree_hdl);
2N/A if (freep->prop_val)
2N/A free(freep->prop_val);
2N/A free(freep);
2N/A }
2N/A }
2N/A
2N/A (void) hash_remove(&ptreetbl, tbl_obj->ptree_hdl);
2N/A free(tbl_obj);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Lock free function that frees up a property object and removes the
2N/A * handles from Ptree table
2N/A */
2N/Astatic void
2N/Adestroy_propobj(picl_obj_t *propp)
2N/A{
2N/A if (propp->prop_type == PICL_PTYPE_TABLE)
2N/A destroy_table(propp);
2N/A
2N/A (void) hash_remove(&ptreetbl, propp->ptree_hdl);
2N/A if (propp->prop_val)
2N/A free(propp->prop_val);
2N/A free(propp);
2N/A}
2N/A
2N/A/*
2N/A * This function destroys a previously deleted property.
2N/A * A deleted property does not have an associated node.
2N/A * All memory allocated for this property are freed
2N/A */
2N/Aint
2N/Aptree_destroy_prop(picl_prophdl_t proph)
2N/A{
2N/A picl_obj_t *propp;
2N/A
2N/A (void) rw_wrlock(&ptree_rwlock); /* Exclusive Lock ptree */
2N/A
2N/A propp = hash_lookup_obj(&ptreetbl, proph);
2N/A if (propp == NULL) {
2N/A (void) rw_unlock(&ptree_rwlock); /* Unlock ptree */
2N/A return (ptree_hdl_error(proph));
2N/A }
2N/A
2N/A /* Is the prop still attached to a node? */
2N/A if (propp->prop_node != NULL) {
2N/A (void) rw_unlock(&ptree_rwlock); /* Unlock ptree */
2N/A return (PICL_CANTDESTROY);
2N/A }
2N/A
2N/A destroy_propobj(propp);
2N/A
2N/A (void) rw_unlock(&ptree_rwlock); /* Unlock ptree */
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * This function adds a property to the property list of a node and adds
2N/A * it to the PICL table if the node has a PICL handle.
2N/A * This function locks the picl_rwlock and ptree_rwlock.
2N/A */
2N/Aint
2N/Aptree_add_prop(picl_nodehdl_t nodeh, picl_prophdl_t proph)
2N/A{
2N/A int err;
2N/A picl_obj_t *nodep;
2N/A picl_obj_t *propp;
2N/A picl_obj_t *tbl_obj;
2N/A picl_obj_t *refobj;
2N/A
2N/A (void) rw_rdlock(&ptree_rwlock); /* RDLock ptree */
2N/A
2N/A /*
2N/A * Verify property handle
2N/A */
2N/A err = lookup_verify_prop_handle(proph, &propp);
2N/A if (err != PICL_SUCCESS) {
2N/A (void) rw_unlock(&ptree_rwlock); /* Unlock ptree */
2N/A return (err);
2N/A }
2N/A
2N/A if (propp->prop_node != NULL) {
2N/A (void) rw_unlock(&ptree_rwlock);
2N/A return (PICL_INVALIDARG);
2N/A }
2N/A
2N/A nodep = NULL;
2N/A /*
2N/A * Exclusive Lock the node's properties
2N/A */
2N/A err = lookup_and_lock_node(WRLOCK_NODE, nodeh, &nodep);
2N/A if (err != PICL_SUCCESS) {
2N/A (void) rw_unlock(&ptree_rwlock); /* Unlock ptree */
2N/A return (err);
2N/A }
2N/A
2N/A /*
2N/A * check if prop already exists
2N/A */
2N/A err = lookup_prop_by_name(nodep, propp->prop_name, NULL);
2N/A if (err == PICL_SUCCESS) {
2N/A unlock_node(nodep); /* Unlock node */
2N/A (void) rw_unlock(&ptree_rwlock); /* Unlock table */
2N/A return (PICL_PROPEXISTS);
2N/A }
2N/A
2N/A /*
2N/A * Verify property's value
2N/A */
2N/A tbl_obj = NULL;
2N/A switch (propp->prop_type) {
2N/A case PICL_PTYPE_TABLE:
2N/A if (propp->prop_mode & PICL_VOLATILE)
2N/A break;
2N/A err = lookup_verify_table_prop(propp, &tbl_obj);
2N/A if (err != PICL_SUCCESS) {
2N/A unlock_node(nodep);
2N/A (void) rw_unlock(&ptree_rwlock);
2N/A return (err);
2N/A }
2N/A tbl_obj->prop_node = nodep; /* set table's nodep */
2N/A tbl_obj->table_prop = propp; /* set table prop */
2N/A break;
2N/A case PICL_PTYPE_REFERENCE:
2N/A if (propp->prop_mode & PICL_VOLATILE)
2N/A break;
2N/A err = lookup_verify_ref_prop(propp, &refobj);
2N/A if (err != PICL_SUCCESS) {
2N/A unlock_node(nodep);
2N/A (void) rw_unlock(&ptree_rwlock);
2N/A return (err);
2N/A }
2N/A if (IS_PICLIZED(nodep) && !IS_PICLIZED(refobj)) {
2N/A unlock_node(nodep);
2N/A (void) rw_unlock(&ptree_rwlock);
2N/A return (err);
2N/A }
2N/A break;
2N/A default:
2N/A break;
2N/A }
2N/A
2N/A if (IS_PICLIZED(nodep))
2N/A piclize_prop(propp);
2N/A /*
2N/A * Add prop to beginning of list
2N/A */
2N/A propp->prop_node = nodep; /* set prop's nodep */
2N/A propp->next_prop = nodep->first_prop;
2N/A nodep->first_prop = propp;
2N/A
2N/A unlock_node(nodep); /* Unlock node */
2N/A (void) rw_unlock(&ptree_rwlock); /* Unlock table */
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Lock free function that unlinks a property from its node
2N/A */
2N/Astatic int
2N/Aunlink_prop(picl_obj_t *nodep, picl_obj_t *propp)
2N/A{
2N/A picl_obj_t *iterp;
2N/A
2N/A iterp = nodep->first_prop;
2N/A if (iterp == propp) { /* first property */
2N/A nodep->first_prop = iterp->next_prop;
2N/A return (PICL_SUCCESS);
2N/A }
2N/A while ((iterp != NULL) && (iterp->next_prop != propp))
2N/A iterp = iterp->next_prop;
2N/A if (iterp == NULL)
2N/A return (PICL_PROPNOTFOUND);
2N/A iterp->next_prop = propp->next_prop;
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * This function deletes the specified property from the property list
2N/A * of its node and removes the handle from PICL table, if the node
2N/A * was piclized.
2N/A */
2N/Aint
2N/Aptree_delete_prop(picl_prophdl_t proph)
2N/A{
2N/A int err;
2N/A picl_obj_t *nodep;
2N/A picl_obj_t *propp;
2N/A
2N/A (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
2N/A /*
2N/A * Lookup the property's node and lock it if there is one
2N/A * return the objects for the property and the node
2N/A */
2N/A nodep = propp = NULL;
2N/A err = lookup_and_lock_propnode(WRLOCK_NODE, proph, &nodep, &propp);
2N/A if (err != PICL_SUCCESS) {
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A } else if (nodep == NULL) {
2N/A /* Nothing to do - already deleted! */
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (PICL_SUCCESS);
2N/A }
2N/A
2N/A if (propp->obj_type & PICL_OBJ_TABLEENTRY) {
2N/A unlock_node(nodep); /* Unlock node */
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (PICL_NOTPROP);
2N/A }
2N/A
2N/A err = unlink_prop(nodep, propp);
2N/A if (err != PICL_SUCCESS) {
2N/A unlock_node(nodep); /* Unlock node */
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A }
2N/A
2N/A propp->prop_node = NULL; /* reset prop's nodep */
2N/A propp->next_prop = NULL;
2N/A
2N/A unpiclize_prop(propp);
2N/A
2N/A unlock_node(nodep); /* Unlock node */
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Create a table object and return its handle
2N/A */
2N/Aint
2N/Aptree_create_table(picl_prophdl_t *tblh)
2N/A{
2N/A picl_obj_t *pobj;
2N/A
2N/A pobj = malloc(sizeof (picl_obj_t));
2N/A if (pobj == NULL)
2N/A return (PICL_FAILURE);
2N/A pobj->obj_type = PICL_OBJ_TABLE;
2N/A pobj->prop_val = NULL;
2N/A pobj->prop_node = NULL;
2N/A pobj->ptree_hdl = PICL_INVALID_PICLHDL;
2N/A pobj->picl_hdl = PICL_INVALID_PICLHDL;
2N/A pobj->table_prop = NULL;
2N/A pobj->next_row = NULL;
2N/A pobj->next_col = NULL;
2N/A
2N/A alloc_and_add_to_ptree(pobj);
2N/A *tblh = pobj->ptree_hdl;
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Add the properties in <props> array as a row in the table
2N/A * Add PICL handles if the table has a valid PICL handle
2N/A */
2N/Aint
2N/Aptree_add_row_to_table(picl_prophdl_t tblh, int nprops,
2N/A const picl_prophdl_t *props)
2N/A{
2N/A picl_obj_t *tbl_obj;
2N/A picl_obj_t *nodep;
2N/A picl_obj_t *lastrow;
2N/A picl_obj_t **newrow;
2N/A int i;
2N/A int err;
2N/A picl_obj_t *pobj;
2N/A int picl_it;
2N/A
2N/A if (nprops < 1)
2N/A return (PICL_INVALIDARG);
2N/A
2N/A newrow = malloc(sizeof (picl_obj_t *) * nprops);
2N/A if (newrow == NULL)
2N/A return (PICL_FAILURE);
2N/A
2N/A (void) rw_rdlock(&ptree_rwlock); /* Lock ptree */
2N/A
2N/A err = lookup_and_lock_tablenode(WRLOCK_NODE, tblh, &nodep, &tbl_obj);
2N/A if (err != PICL_SUCCESS) {
2N/A free(newrow);
2N/A (void) rw_unlock(&ptree_rwlock); /* Unlock table */
2N/A return (err);
2N/A }
2N/A
2N/A /*
2N/A * make sure all are either props or table handles
2N/A */
2N/A for (i = 0; i < nprops; ++i) {
2N/A pobj = newrow[i] = hash_lookup_obj(&ptreetbl, props[i]);
2N/A if (pobj == NULL) { /* no object */
2N/A err = ptree_hdl_error(props[i]);
2N/A break;
2N/A }
2N/A if ((!(pobj->obj_type & PICL_OBJ_PROP)) &&
2N/A (!(pobj->obj_type & PICL_OBJ_TABLE))) {
2N/A err = PICL_NOTPROP;
2N/A break;
2N/A }
2N/A if (IS_PICLIZED(pobj) || (pobj->prop_table != NULL) ||
2N/A (pobj->prop_node != NULL)) {
2N/A err = PICL_INVALIDARG;
2N/A break;
2N/A }
2N/A
2N/A }
2N/A if (err != PICL_SUCCESS) {
2N/A free(newrow);
2N/A unlock_node(nodep);
2N/A (void) rw_unlock(&ptree_rwlock); /* Unlock table */
2N/A return (err);
2N/A }
2N/A
2N/A /*
2N/A * Mark all props as table entries, set up row linkages
2N/A */
2N/A picl_it = 0;
2N/A if (IS_PICLIZED(tbl_obj))
2N/A picl_it = 1;
2N/A for (i = 0; i < nprops; ++i) {
2N/A newrow[i]->obj_type |= PICL_OBJ_TABLEENTRY;
2N/A newrow[i]->prop_table = tbl_obj;
2N/A newrow[i]->next_prop = NULL;
2N/A newrow[i]->next_col = NULL;
2N/A if (picl_it)
2N/A piclize_obj(newrow[i]);
2N/A if (i != nprops - 1)
2N/A newrow[i]->next_row = newrow[i+1];
2N/A }
2N/A newrow[nprops - 1]->next_row = NULL;
2N/A
2N/A if (tbl_obj->next_row == NULL) { /* add first row */
2N/A tbl_obj->next_row = newrow[0];
2N/A tbl_obj->next_col = newrow[0];
2N/A } else {
2N/A lastrow = tbl_obj->next_row;
2N/A while (lastrow->next_col != NULL)
2N/A lastrow = lastrow->next_col;
2N/A i = 0;
2N/A while (lastrow != NULL) {
2N/A lastrow->next_col = newrow[i];
2N/A lastrow = lastrow->next_row;
2N/A ++i;
2N/A }
2N/A }
2N/A
2N/A unlock_node(nodep); /* unlock node */
2N/A (void) rw_unlock(&ptree_rwlock); /* Unlock ptree */
2N/A free(newrow);
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * This function returns the handle of the next property in the row
2N/A */
2N/Aint
2N/Aptree_get_next_by_row(picl_prophdl_t proph, picl_prophdl_t *nextrowh)
2N/A{
2N/A int err;
2N/A picl_obj_t *nodep;
2N/A picl_obj_t *propp;
2N/A
2N/A (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
2N/A
2N/A nodep = propp = NULL;
2N/A /*
2N/A * proph could be a table handle or a table entry handle
2N/A * Look it up as a table entry handle first, check error code
2N/A * to see if it is a table handle
2N/A */
2N/A err = lookup_and_lock_tableprop_node(RDLOCK_NODE, proph, &nodep,
2N/A &propp);
2N/A if (err != PICL_SUCCESS) {
2N/A (void) rw_unlock(&ptree_rwlock);
2N/A return (err);
2N/A }
2N/A
2N/A if (propp->next_row)
2N/A *nextrowh = propp->next_row->ptree_hdl;
2N/A else
2N/A err = PICL_ENDOFLIST;
2N/A
2N/A unlock_node(nodep); /* unlock node */
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A}
2N/A
2N/Aint
2N/Aptree_get_next_by_col(picl_prophdl_t proph, picl_prophdl_t *nextcolh)
2N/A{
2N/A int err;
2N/A picl_obj_t *propp;
2N/A picl_obj_t *nodep;
2N/A
2N/A (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
2N/A nodep = propp = NULL;
2N/A /*
2N/A * proph could be a table handle or a table entry handle
2N/A * Look it up as a table entry handle first, check error code
2N/A * to see if it is a table handle
2N/A */
2N/A err = lookup_and_lock_tableprop_node(RDLOCK_NODE, proph, &nodep,
2N/A &propp);
2N/A if (err != PICL_SUCCESS) {
2N/A (void) rw_unlock(&ptree_rwlock);
2N/A return (err);
2N/A }
2N/A
2N/A if (propp->next_col)
2N/A *nextcolh = propp->next_col->ptree_hdl;
2N/A else
2N/A err = PICL_ENDOFLIST;
2N/A
2N/A unlock_node(nodep); /* unlock node */
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * This function creates node object and adds its handle to the Ptree
2N/A */
2N/Aint
2N/Aptree_create_node(const char *name, const char *clname, picl_nodehdl_t *nodeh)
2N/A{
2N/A picl_obj_t *pobj;
2N/A ptree_propinfo_t propinfo;
2N/A picl_prophdl_t phdl;
2N/A picl_prophdl_t cphdl;
2N/A int err;
2N/A
2N/A if ((name == NULL) || (*name == '\0') ||
2N/A (clname == NULL) || (*clname == '\0'))
2N/A return (PICL_INVALIDARG);
2N/A
2N/A if ((strlen(name) >= PICL_PROPNAMELEN_MAX) ||
2N/A (strlen(clname) >= PICL_CLASSNAMELEN_MAX))
2N/A return (PICL_VALUETOOBIG);
2N/A
2N/A /*
2N/A * Create the picl object for node
2N/A */
2N/A pobj = malloc(sizeof (picl_obj_t));
2N/A if (pobj == NULL)
2N/A return (PICL_FAILURE);
2N/A pobj->obj_type = PICL_OBJ_NODE;
2N/A pobj->first_prop = NULL;
2N/A pobj->ptree_hdl = PICL_INVALID_PICLHDL;
2N/A pobj->picl_hdl = PICL_INVALID_PICLHDL;
2N/A pobj->parent_node = NULL;
2N/A pobj->sibling_node = NULL;
2N/A pobj->child_node = NULL;
2N/A pobj->node_classname = strdup(clname);
2N/A if (pobj->node_classname == NULL) {
2N/A free(pobj);
2N/A return (PICL_FAILURE);
2N/A }
2N/A (void) rwlock_init(&pobj->node_lock, USYNC_THREAD, NULL);
2N/A
2N/A alloc_and_add_to_ptree(pobj); /* commit the node */
2N/A
2N/A /*
2N/A * create name property
2N/A */
2N/A propinfo.version = PTREE_PROPINFO_VERSION_1;
2N/A propinfo.piclinfo.type = PICL_PTYPE_CHARSTRING;
2N/A propinfo.piclinfo.accessmode = PICL_READ;
2N/A propinfo.piclinfo.size = strlen(name) + 1;
2N/A (void) strcpy(propinfo.piclinfo.name, PICL_PROP_NAME);
2N/A propinfo.read = NULL;
2N/A propinfo.write = NULL;
2N/A err = ptree_create_prop(&propinfo, (const void *)name, &phdl);
2N/A if (err != PICL_SUCCESS) {
2N/A (void) ptree_destroy_node(pobj->ptree_hdl);
2N/A return (err);
2N/A }
2N/A err = ptree_add_prop(pobj->ptree_hdl, phdl);
2N/A if (err != PICL_SUCCESS) {
2N/A (void) ptree_destroy_prop(phdl);
2N/A (void) ptree_destroy_node(pobj->ptree_hdl);
2N/A return (err);
2N/A }
2N/A
2N/A /*
2N/A * create picl classname property
2N/A */
2N/A propinfo.piclinfo.size = strlen(clname) + 1;
2N/A (void) strcpy(propinfo.piclinfo.name, PICL_PROP_CLASSNAME);
2N/A propinfo.read = NULL;
2N/A propinfo.write = NULL;
2N/A err = ptree_create_prop(&propinfo, (const void *)clname, &cphdl);
2N/A if (err != PICL_SUCCESS) {
2N/A (void) ptree_destroy_node(pobj->ptree_hdl);
2N/A return (err);
2N/A }
2N/A err = ptree_add_prop(pobj->ptree_hdl, cphdl);
2N/A if (err != PICL_SUCCESS) {
2N/A (void) ptree_destroy_prop(cphdl);
2N/A (void) ptree_destroy_node(pobj->ptree_hdl);
2N/A return (err);
2N/A }
2N/A
2N/A *nodeh = pobj->ptree_hdl;
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Destroy a node/subtree freeing up space
2N/A * Removed destroyed objects' handles from PTree table
2N/A */
2N/Astatic void
2N/Adestroy_subtree(picl_obj_t *nodep)
2N/A{
2N/A picl_obj_t *iterp;
2N/A picl_obj_t *freep;
2N/A picl_obj_t *chdp;
2N/A
2N/A if (nodep == NULL)
2N/A return;
2N/A
2N/A chdp = nodep->child_node;
2N/A while (chdp != NULL) {
2N/A freep = chdp;
2N/A chdp = chdp->sibling_node;
2N/A destroy_subtree(freep);
2N/A }
2N/A
2N/A /*
2N/A * Lock the node
2N/A */
2N/A (void) lock_obj(WRLOCK_NODE, nodep);
2N/A
2N/A /*
2N/A * destroy all properties associated with this node
2N/A */
2N/A iterp = nodep->first_prop;
2N/A while (iterp != NULL) {
2N/A freep = iterp;
2N/A iterp = iterp->next_prop;
2N/A destroy_propobj(freep);
2N/A }
2N/A
2N/A (void) hash_remove(&ptreetbl, nodep->ptree_hdl);
2N/A (void) rwlock_destroy(&nodep->node_lock);
2N/A free(nodep->node_classname);
2N/A free(nodep);
2N/A}
2N/A
2N/A/*
2N/A * This function destroys a previously deleted node/subtree. All the properties
2N/A * are freed and removed from the PTree table.
2N/A * Only one destroy is in progress at any time.
2N/A */
2N/Aint
2N/Aptree_destroy_node(picl_nodehdl_t nodeh)
2N/A{
2N/A picl_obj_t *nodep;
2N/A picl_obj_t *parp;
2N/A picl_obj_t *np;
2N/A int err;
2N/A
2N/A (void) rw_wrlock(&ptree_rwlock); /* exclusive wrlock ptree */
2N/A nodep = NULL;
2N/A err = lookup_verify_node_handle(nodeh, &nodep);
2N/A if (err != PICL_SUCCESS) {
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A }
2N/A
2N/A /*
2N/A * Has this node/subtree been deleted?
2N/A */
2N/A if (IS_PICLIZED(nodep)) {
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (PICL_CANTDESTROY);
2N/A }
2N/A
2N/A /*
2N/A * update parent's child list to repair the tree when
2N/A * parent is not null
2N/A */
2N/A parp = nodep->parent_node;
2N/A if (parp == NULL) { /* root */
2N/A destroy_subtree(nodep);
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (PICL_SUCCESS);
2N/A }
2N/A
2N/A np = parp->child_node;
2N/A if (np == nodep) { /* first child */
2N/A parp->child_node = nodep->sibling_node;
2N/A } else {
2N/A while ((np != NULL) && (np->sibling_node != nodep))
2N/A np = np->sibling_node;
2N/A if (np != NULL)
2N/A np->sibling_node = nodep->sibling_node;
2N/A }
2N/A
2N/A destroy_subtree(nodep);
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * This function deletes a node/subtree from the tree and removes the handles
2N/A * from PICL table
2N/A */
2N/Aint
2N/Aptree_delete_node(picl_nodehdl_t nodeh)
2N/A{
2N/A picl_obj_t *nodep;
2N/A picl_obj_t *parp;
2N/A picl_obj_t *np;
2N/A int err;
2N/A
2N/A (void) rw_wrlock(&ptree_rwlock); /* exclusive wrlock ptree */
2N/A
2N/A nodep = NULL;
2N/A err = lookup_verify_node_handle(nodeh, &nodep);
2N/A if (err != PICL_SUCCESS) {
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A }
2N/A
2N/A /*
2N/A * unparent it
2N/A */
2N/A parp = nodep->parent_node;
2N/A if (parp != NULL) {
2N/A np = parp->child_node;
2N/A if (np == nodep) /* first child */
2N/A parp->child_node = nodep->sibling_node;
2N/A else {
2N/A while ((np != NULL) && (np->sibling_node != nodep))
2N/A np = np->sibling_node;
2N/A if (np != NULL)
2N/A np->sibling_node = nodep->sibling_node;
2N/A }
2N/A }
2N/A
2N/A nodep->parent_node = NULL;
2N/A nodep->sibling_node = NULL;
2N/A
2N/A unpiclize_node(nodep);
2N/A
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * This function adds a node as a child of another node
2N/A */
2N/Aint
2N/Aptree_add_node(picl_nodehdl_t parh, picl_nodehdl_t chdh)
2N/A{
2N/A picl_obj_t *pnodep;
2N/A picl_obj_t *cnodep;
2N/A picl_obj_t *nodep;
2N/A int err;
2N/A
2N/A (void) rw_wrlock(&ptree_rwlock); /* exclusive lock ptree */
2N/A
2N/A pnodep = cnodep = NULL;
2N/A err = lookup_verify_node_handle(parh, &pnodep);
2N/A if (err != PICL_SUCCESS) {
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A }
2N/A
2N/A err = lookup_verify_node_handle(chdh, &cnodep);
2N/A if (err != PICL_SUCCESS) {
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A }
2N/A
2N/A /* is chdh already a child? */
2N/A if (cnodep->parent_node != NULL) {
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (PICL_CANTPARENT);
2N/A }
2N/A
2N/A /*
2N/A * append child to children list
2N/A */
2N/A cnodep->parent_node = pnodep;
2N/A if (pnodep->child_node == NULL)
2N/A pnodep->child_node = cnodep;
2N/A else {
2N/A for (nodep = pnodep->child_node; nodep->sibling_node != NULL;
2N/A nodep = nodep->sibling_node)
2N/A continue;
2N/A nodep->sibling_node = cnodep;
2N/A
2N/A }
2N/A
2N/A /* piclize */
2N/A if (IS_PICLIZED(pnodep))
2N/A piclize_node(cnodep);
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/Astatic void
2N/Acopy_propinfo_ver_1(ptree_propinfo_t *pinfo, picl_obj_t *propp)
2N/A{
2N/A pinfo->version = propp->pinfo_ver;
2N/A pinfo->piclinfo.type = propp->prop_type;
2N/A pinfo->piclinfo.accessmode = propp->prop_mode;
2N/A pinfo->piclinfo.size = propp->prop_size;
2N/A (void) strcpy(pinfo->piclinfo.name, propp->prop_name);
2N/A pinfo->read = propp->read_func;
2N/A pinfo->write = propp->write_func;
2N/A}
2N/A
2N/Astatic void
2N/Acopy_reserved_propinfo_ver_1(ptree_propinfo_t *pinfo, const char *pname)
2N/A{
2N/A pinfo->version = PTREE_PROPINFO_VERSION_1;
2N/A pinfo->piclinfo.type = PICL_PTYPE_REFERENCE;
2N/A pinfo->piclinfo.accessmode = PICL_READ;
2N/A pinfo->piclinfo.size = sizeof (picl_nodehdl_t);
2N/A (void) strcpy(pinfo->piclinfo.name, pname);
2N/A pinfo->read = NULL;
2N/A pinfo->write = NULL;
2N/A}
2N/A
2N/A/*
2N/A * This function returns the property information to a plug-in
2N/A */
2N/Aint
2N/Aptree_get_propinfo(picl_prophdl_t proph, ptree_propinfo_t *pinfo)
2N/A{
2N/A int err;
2N/A picl_obj_t *nodep;
2N/A picl_obj_t *propp;
2N/A
2N/A (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
2N/A nodep = propp = NULL;
2N/A err = lookup_and_lock_propnode(RDLOCK_NODE, proph, &nodep, &propp);
2N/A if (err != PICL_SUCCESS) {
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A }
2N/A
2N/A if (propp->pinfo_ver == PTREE_PROPINFO_VERSION_1)
2N/A copy_propinfo_ver_1(pinfo, propp);
2N/A else
2N/A err = PICL_FAILURE;
2N/A
2N/A unlock_node(nodep); /* unlock node */
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * This function returns the property information to a plug-in
2N/A */
2N/Aint
2N/Axptree_get_propinfo_by_name(picl_nodehdl_t nodeh, const char *pname,
2N/A ptree_propinfo_t *pinfo)
2N/A{
2N/A int err;
2N/A picl_obj_t *nodep;
2N/A picl_obj_t *propp;
2N/A
2N/A (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
2N/A nodep = propp = NULL;
2N/A err = lookup_and_lock_node(RDLOCK_NODE, nodeh, &nodep); /* lock node */
2N/A if (err != PICL_SUCCESS) {
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A }
2N/A
2N/A err = lookup_prop_by_name(nodep, pname, &propp);
2N/A if (err != PICL_SUCCESS) {
2N/A unlock_node(nodep);
2N/A (void) rw_unlock(&ptree_rwlock);
2N/A return (err);
2N/A }
2N/A
2N/A if (picl_restricted(pname))
2N/A copy_reserved_propinfo_ver_1(pinfo, pname);
2N/A else if (propp->pinfo_ver == PTREE_PROPINFO_VERSION_1)
2N/A copy_propinfo_ver_1(pinfo, propp);
2N/A else
2N/A err = PICL_FAILURE;
2N/A
2N/A unlock_node(nodep); /* unlock node */
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * This function must be called only after a lookup_prop_by_name() returns
2N/A * success and only if picl_restricted() returns true.
2N/A */
2N/Astatic int
2N/Aread_reserved_propval_and_unlock(picl_obj_t *nodep, const char *pname,
2N/A void *vbuf, size_t size)
2N/A{
2N/A void *srcp;
2N/A
2N/A if (size != sizeof (picl_nodehdl_t))
2N/A return (PICL_VALUETOOBIG);
2N/A
2N/A if (strcmp(pname, PICL_PROP_PARENT) == 0)
2N/A srcp = &nodep->parent_node->ptree_hdl;
2N/A else if (strcmp(pname, PICL_PROP_CHILD) == 0)
2N/A srcp = &nodep->child_node->ptree_hdl;
2N/A else if (strcmp(pname, PICL_PROP_PEER) == 0)
2N/A srcp = &nodep->sibling_node->ptree_hdl;
2N/A else
2N/A return (PICL_FAILURE);
2N/A
2N/A (void) memcpy(vbuf, srcp, sizeof (picl_nodehdl_t));
2N/A unlock_node(nodep);
2N/A (void) rw_unlock(&ptree_rwlock);
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Returns the property value in the buffer and releases the node and
2N/A * ptree locks.
2N/A * For volatile properties, this function releases the locks on ptree
2N/A * table and the node before calling the plug-in provided access function
2N/A */
2N/Astatic int
2N/Aread_propval_and_unlock(picl_obj_t *nodep, picl_obj_t *propp, void *vbuf,
2N/A door_cred_t cred)
2N/A{
2N/A int err;
2N/A int (*volrd)(ptree_rarg_t *arg, void *buf);
2N/A
2N/A err = PICL_SUCCESS;
2N/A if (propp->prop_mode & PICL_VOLATILE) {
2N/A ptree_rarg_t rarg;
2N/A
2N/A if (nodep)
2N/A rarg.nodeh = nodep->ptree_hdl;
2N/A else
2N/A rarg.nodeh = PICL_INVALID_PICLHDL;
2N/A rarg.proph = propp->ptree_hdl;
2N/A rarg.cred = cred;
2N/A volrd = propp->read_func;
2N/A
2N/A unlock_node(nodep); /* unlock node */
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A
2N/A if (volrd == NULL)
2N/A err = PICL_FAILURE;
2N/A else
2N/A err = (volrd)(&rarg, vbuf);
2N/A return (err);
2N/A } else if (propp->prop_type == PICL_PTYPE_CHARSTRING)
2N/A (void) strlcpy(vbuf, propp->prop_val, propp->prop_size);
2N/A else
2N/A (void) memcpy(vbuf, propp->prop_val, propp->prop_size);
2N/A
2N/A unlock_node(nodep);
2N/A (void) rw_unlock(&ptree_rwlock);
2N/A return (err);
2N/A}
2N/A
2N/Aint
2N/Axptree_get_propval_with_cred(picl_prophdl_t proph, void *vbuf, size_t size,
2N/A door_cred_t cred)
2N/A{
2N/A picl_obj_t *propp;
2N/A picl_obj_t *nodep;
2N/A int err;
2N/A
2N/A (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
2N/A nodep = propp = NULL;
2N/A err = lookup_and_lock_propnode(RDLOCK_NODE, proph, &nodep, &propp);
2N/A if (err != PICL_SUCCESS) {
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A }
2N/A
2N/A err = check_propsize(PROP_READ, propp, size);
2N/A if (err != PICL_SUCCESS) {
2N/A unlock_node(nodep); /* unlock node */
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A }
2N/A
2N/A return (read_propval_and_unlock(nodep, propp, vbuf, cred));
2N/A}
2N/A
2N/A/*
2N/A * This function gets the credentials and calls get_propval_with_cred.
2N/A */
2N/Aint
2N/Aptree_get_propval(picl_prophdl_t proph, void *vbuf, size_t size)
2N/A{
2N/A return (xptree_get_propval_with_cred(proph, vbuf, size, picld_cred));
2N/A}
2N/A
2N/A/*
2N/A * This function retrieves a property's value by by its name
2N/A * For volatile properties, the locks on ptree and node are released
2N/A * before calling the plug-in provided access function
2N/A */
2N/Aint
2N/Axptree_get_propval_by_name_with_cred(picl_nodehdl_t nodeh, const char *pname,
2N/A void *vbuf, size_t size, door_cred_t cred)
2N/A{
2N/A picl_obj_t *nodep;
2N/A picl_obj_t *propp;
2N/A int err;
2N/A
2N/A (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
2N/A
2N/A nodep = NULL;
2N/A err = lookup_and_lock_node(RDLOCK_NODE, nodeh, &nodep); /* lock node */
2N/A if (err != PICL_SUCCESS) {
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A }
2N/A
2N/A err = lookup_prop_by_name(nodep, pname, &propp);
2N/A if (err != PICL_SUCCESS) {
2N/A unlock_node(nodep);
2N/A (void) rw_unlock(&ptree_rwlock);
2N/A return (err);
2N/A }
2N/A
2N/A if (picl_restricted(pname))
2N/A return (read_reserved_propval_and_unlock(nodep, pname, vbuf,
2N/A size));
2N/A
2N/A err = check_propsize(PROP_READ, propp, size);
2N/A if (err != PICL_SUCCESS) {
2N/A unlock_node(nodep);
2N/A (void) rw_unlock(&ptree_rwlock);
2N/A return (err);
2N/A }
2N/A
2N/A return (read_propval_and_unlock(nodep, propp, vbuf, cred));
2N/A}
2N/A
2N/A/*
2N/A * This function is used by plugins to get a value of a property
2N/A * looking it up by its name.
2N/A */
2N/Aint
2N/Aptree_get_propval_by_name(picl_nodehdl_t nodeh, const char *pname, void *vbuf,
2N/A size_t size)
2N/A{
2N/A return (xptree_get_propval_by_name_with_cred(nodeh, pname, vbuf, size,
2N/A picld_cred));
2N/A}
2N/A
2N/A/*
2N/A * This function updates a property's value.
2N/A * For volatile properties, the locks on the node and the ptree table
2N/A * are released before calling the plug-in provided access function.
2N/A */
2N/Astatic int
2N/Awrite_propval_and_unlock(picl_obj_t *nodep, picl_obj_t *propp, const void *vbuf,
2N/A size_t size, door_cred_t cred)
2N/A{
2N/A int err;
2N/A int (*volwr)(ptree_warg_t *arg, const void *buf);
2N/A
2N/A err = PICL_SUCCESS;
2N/A if (propp->prop_mode & PICL_VOLATILE) {
2N/A ptree_warg_t warg;
2N/A
2N/A if (nodep)
2N/A warg.nodeh = nodep->ptree_hdl;
2N/A else
2N/A warg.nodeh = PICL_INVALID_PICLHDL;
2N/A warg.proph = propp->ptree_hdl;
2N/A warg.cred = cred;
2N/A volwr = propp->write_func;
2N/A
2N/A unlock_node(nodep); /* unlock node */
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A
2N/A if (volwr == NULL)
2N/A err = PICL_FAILURE;
2N/A else
2N/A err = (volwr)(&warg, vbuf);
2N/A return (err);
2N/A } else
2N/A (void) memcpy(propp->prop_val, vbuf, size);
2N/A
2N/A unlock_node(nodep); /* unlock node */
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A}
2N/A
2N/Aint
2N/Axptree_update_propval_with_cred(picl_prophdl_t proph, const void *vbuf,
2N/A size_t size, door_cred_t cred)
2N/A{
2N/A picl_obj_t *nodep;
2N/A picl_obj_t *propp;
2N/A int err;
2N/A
2N/A (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
2N/A nodep = propp = NULL;
2N/A err = lookup_and_lock_propnode(WRLOCK_NODE, proph, &nodep, &propp);
2N/A if (err != PICL_SUCCESS) {
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A }
2N/A
2N/A err = check_propsize(PROP_WRITE, propp, size);
2N/A if (err != PICL_SUCCESS) {
2N/A unlock_node(nodep); /* unlock node */
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A }
2N/A
2N/A return (write_propval_and_unlock(nodep, propp, vbuf, size, cred));
2N/A}
2N/A
2N/A/*
2N/A * Ptree function used by plug-ins to update a property's value
2N/A * calls update_propval_with_cred(), which releases locks for volatile props
2N/A */
2N/Aint
2N/Aptree_update_propval(picl_prophdl_t proph, const void *vbuf, size_t size)
2N/A{
2N/A return (xptree_update_propval_with_cred(proph, vbuf, size, picld_cred));
2N/A}
2N/A
2N/A/*
2N/A * This function writes/updates a property's value by looking it up
2N/A * by its name.
2N/A * For volatile properties this function releases the locks on the
2N/A * node and the ptree table.
2N/A */
2N/Aint
2N/Axptree_update_propval_by_name_with_cred(picl_nodehdl_t nodeh, const char *pname,
2N/A const void *vbuf, size_t size, door_cred_t cred)
2N/A{
2N/A picl_obj_t *nodep;
2N/A picl_obj_t *propp;
2N/A int err;
2N/A
2N/A (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
2N/A nodep = NULL;
2N/A err = lookup_and_lock_node(WRLOCK_NODE, nodeh, &nodep); /* lock node */
2N/A if (err != PICL_SUCCESS) {
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A }
2N/A
2N/A if (picl_restricted(pname)) {
2N/A unlock_node(nodep);
2N/A (void) rw_unlock(&ptree_rwlock);
2N/A return (PICL_RESERVEDNAME);
2N/A }
2N/A
2N/A err = lookup_prop_by_name(nodep, pname, &propp);
2N/A if (err != PICL_SUCCESS) {
2N/A unlock_node(nodep);
2N/A (void) rw_unlock(&ptree_rwlock);
2N/A return (err);
2N/A }
2N/A
2N/A err = check_propsize(PROP_WRITE, propp, size);
2N/A if (err != PICL_SUCCESS) {
2N/A unlock_node(nodep);
2N/A (void) rw_unlock(&ptree_rwlock);
2N/A return (err);
2N/A }
2N/A
2N/A return (write_propval_and_unlock(nodep, propp, vbuf, size, cred));
2N/A}
2N/A
2N/A/*
2N/A * This function updates the value of a property specified by its name
2N/A */
2N/Aint
2N/Aptree_update_propval_by_name(picl_nodehdl_t nodeh, const char *pname,
2N/A const void *vbuf, size_t size)
2N/A{
2N/A return (xptree_update_propval_by_name_with_cred(nodeh, pname, vbuf,
2N/A size, picld_cred));
2N/A}
2N/A
2N/A/*
2N/A * This function retrieves the handle of a property by its name
2N/A */
2N/Aint
2N/Aptree_get_prop_by_name(picl_nodehdl_t nodeh, const char *pname,
2N/A picl_prophdl_t *proph)
2N/A{
2N/A picl_obj_t *nodep;
2N/A picl_obj_t *propp;
2N/A int err;
2N/A
2N/A (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
2N/A nodep = NULL;
2N/A err = lookup_and_lock_node(RDLOCK_NODE, nodeh, &nodep); /* lock node */
2N/A if (err != PICL_SUCCESS) {
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A }
2N/A
2N/A if (picl_restricted(pname)) {
2N/A err = PICL_RESERVEDNAME;
2N/A unlock_node(nodep); /* unlock node */
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A }
2N/A
2N/A err = lookup_prop_by_name(nodep, pname, &propp);
2N/A if (err == PICL_SUCCESS)
2N/A *proph = propp->ptree_hdl;
2N/A
2N/A unlock_node(nodep); /* unlock node */
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * This function returns the handle of the first property
2N/A */
2N/Aint
2N/Aptree_get_first_prop(picl_nodehdl_t nodeh, picl_prophdl_t *proph)
2N/A{
2N/A picl_obj_t *pobj;
2N/A int err;
2N/A
2N/A (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
2N/A pobj = NULL;
2N/A err = lookup_and_lock_node(RDLOCK_NODE, nodeh, &pobj); /* lock node */
2N/A if (err != PICL_SUCCESS) {
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A }
2N/A
2N/A if (pobj->first_prop)
2N/A *proph = pobj->first_prop->ptree_hdl;
2N/A else
2N/A err = PICL_ENDOFLIST;
2N/A
2N/A unlock_node(pobj); /* unlock node */
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * This function returns the handle of next property in the list
2N/A */
2N/Aint
2N/Aptree_get_next_prop(picl_prophdl_t proph, picl_prophdl_t *nextproph)
2N/A{
2N/A picl_obj_t *nodep;
2N/A picl_obj_t *propp;
2N/A int err;
2N/A
2N/A (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
2N/A nodep = propp = NULL;
2N/A err = lookup_and_lock_propnode(RDLOCK_NODE, proph, &nodep, &propp);
2N/A if (err != PICL_SUCCESS) {
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A }
2N/A
2N/A if (propp->next_prop) {
2N/A *nextproph = propp->next_prop->ptree_hdl;
2N/A } else
2N/A err = PICL_ENDOFLIST;
2N/A
2N/A unlock_node(nodep); /* unlock node */
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * These functions are called by ptree_get_node_by_path()
2N/A * Append a prop expression entry to the list
2N/A */
2N/Astatic prop_list_t *
2N/Aappend_entry_to_list(prop_list_t *el, prop_list_t *list)
2N/A{
2N/A prop_list_t *ptr;
2N/A
2N/A if (el == NULL)
2N/A return (list);
2N/A
2N/A if (list == NULL) {
2N/A list = el;
2N/A return (list);
2N/A }
2N/A
2N/A /*
2N/A * Add it to the end of list
2N/A */
2N/A ptr = list;
2N/A
2N/A while (ptr->next != NULL)
2N/A ptr = ptr->next;
2N/A
2N/A ptr->next = el;
2N/A
2N/A return (list);
2N/A}
2N/A
2N/A/*
2N/A * Free the property expression list
2N/A */
2N/Astatic void
2N/Afree_list(prop_list_t *list)
2N/A{
2N/A prop_list_t *ptr;
2N/A prop_list_t *tmp;
2N/A
2N/A for (ptr = list; ptr != NULL; ptr = tmp) {
2N/A tmp = ptr->next;
2N/A free(ptr);
2N/A }
2N/A}
2N/A
2N/Astatic int
2N/Aparse_prl(char *prl, char **name, char **baddr, prop_list_t **plist)
2N/A{
2N/A char *propptr;
2N/A char *ptr;
2N/A char *pname;
2N/A char *pval;
2N/A prop_list_t *el;
2N/A
2N/A if (prl == NULL)
2N/A return (PICL_FAILURE);
2N/A
2N/A if ((prl[0] == '@') || (prl[0] == '?'))
2N/A return (PICL_FAILURE);
2N/A
2N/A *name = prl;
2N/A
2N/A /*
2N/A * get property expression
2N/A */
2N/A ptr = strchr(prl, '?');
2N/A
2N/A if (ptr != NULL) {
2N/A *ptr = '\0';
2N/A propptr = ptr + 1;
2N/A } else
2N/A propptr = NULL;
2N/A
2N/A /*
2N/A * get bus value
2N/A */
2N/A ptr = strchr(prl, '@');
2N/A
2N/A if (ptr != NULL) {
2N/A *ptr = '\0';
2N/A *baddr = ptr + 1;
2N/A if (strlen(*baddr) == 0) /* no bus value after @ */
2N/A return (PICL_FAILURE);
2N/A }
2N/A
2N/A /*
2N/A * create the prop list
2N/A */
2N/A while (propptr != NULL) {
2N/A pname = propptr;
2N/A pval = NULL;
2N/A
2N/A ptr = strchr(propptr, '?');
2N/A
2N/A if (ptr != NULL) { /* more ?<prop>=<propval> */
2N/A *ptr = '\0';
2N/A propptr = ptr + 1;
2N/A } else
2N/A propptr = NULL;
2N/A
2N/A if (strlen(pname) == 0) /* no prop exp after ? */
2N/A return (PICL_FAILURE);
2N/A
2N/A ptr = strchr(pname, '=');
2N/A if (ptr != NULL) { /* not void prop */
2N/A *ptr = '\0';
2N/A pval = ptr + 1;
2N/A /*
2N/A * <prop>= is treated as void property
2N/A */
2N/A if (strlen(pval) == 0)
2N/A pval = NULL;
2N/A }
2N/A
2N/A el = (prop_list_t *)malloc(sizeof (prop_list_t));
2N/A el->pname = pname;
2N/A el->pval = pval;
2N/A el->next = NULL;
2N/A *plist = append_entry_to_list(el, *plist);
2N/A }
2N/A
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/Astatic int
2N/Aprop_match(ptree_propinfo_t pinfo, void *vbuf, char *val)
2N/A{
2N/A int8_t cval;
2N/A uint8_t ucval;
2N/A int16_t sval;
2N/A uint16_t usval;
2N/A int32_t intval;
2N/A uint32_t uintval;
2N/A int64_t llval;
2N/A uint64_t ullval;
2N/A float fval;
2N/A double dval;
2N/A
2N/A switch (pinfo.piclinfo.type) {
2N/A case PICL_PTYPE_CHARSTRING:
2N/A if (strcasecmp(pinfo.piclinfo.name, PICL_PROP_CLASSNAME) == 0) {
2N/A if (strcmp(val, PICL_CLASS_PICL) == 0)
2N/A return (1);
2N/A }
2N/A if (strcmp(val, (char *)vbuf) == 0)
2N/A return (1);
2N/A else
2N/A return (0);
2N/A case PICL_PTYPE_INT:
2N/A switch (pinfo.piclinfo.size) {
2N/A case sizeof (int8_t):
2N/A cval = (int8_t)strtol(val, (char **)NULL, 0);
2N/A return (cval == *(char *)vbuf);
2N/A case sizeof (int16_t):
2N/A sval = (int16_t)strtol(val, (char **)NULL, 0);
2N/A return (sval == *(int16_t *)vbuf);
2N/A case sizeof (int32_t):
2N/A intval = (int32_t)strtol(val, (char **)NULL, 0);
2N/A return (intval == *(int32_t *)vbuf);
2N/A case sizeof (int64_t):
2N/A llval = strtoll(val, (char **)NULL, 0);
2N/A return (llval == *(int64_t *)vbuf);
2N/A default:
2N/A return (0);
2N/A }
2N/A case PICL_PTYPE_UNSIGNED_INT:
2N/A switch (pinfo.piclinfo.size) {
2N/A case sizeof (uint8_t):
2N/A ucval = (uint8_t)strtoul(val, (char **)NULL, 0);
2N/A return (ucval == *(uint8_t *)vbuf);
2N/A case sizeof (uint16_t):
2N/A usval = (uint16_t)strtoul(val, (char **)NULL, 0);
2N/A return (usval == *(uint16_t *)vbuf);
2N/A case sizeof (uint32_t):
2N/A uintval = (uint32_t)strtoul(val, (char **)NULL, 0);
2N/A return (uintval == *(uint32_t *)vbuf);
2N/A case sizeof (uint64_t):
2N/A ullval = strtoull(val, (char **)NULL, 0);
2N/A return (ullval == *(uint64_t *)vbuf);
2N/A default:
2N/A return (0);
2N/A }
2N/A case PICL_PTYPE_FLOAT:
2N/A switch (pinfo.piclinfo.size) {
2N/A case sizeof (float):
2N/A fval = (float)strtod(val, (char **)NULL);
2N/A return (fval == *(float *)vbuf);
2N/A case sizeof (double):
2N/A dval = strtod(val, (char **)NULL);
2N/A return (dval == *(double *)vbuf);
2N/A default:
2N/A return (0);
2N/A }
2N/A case PICL_PTYPE_VOID:
2N/A case PICL_PTYPE_TIMESTAMP:
2N/A case PICL_PTYPE_TABLE:
2N/A case PICL_PTYPE_REFERENCE:
2N/A case PICL_PTYPE_BYTEARRAY:
2N/A case PICL_PTYPE_UNKNOWN:
2N/A default:
2N/A return (0);
2N/A }
2N/A}
2N/A
2N/Astatic int
2N/Acheck_propval(picl_nodehdl_t nodeh, char *pname, char *pval)
2N/A{
2N/A int err;
2N/A picl_prophdl_t proph;
2N/A ptree_propinfo_t pinfo;
2N/A void *vbuf;
2N/A
2N/A err = ptree_get_prop_by_name(nodeh, pname, &proph);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A err = ptree_get_propinfo(proph, &pinfo);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A if (pval == NULL) { /* void type */
2N/A if (pinfo.piclinfo.type != PICL_PTYPE_VOID)
2N/A return (PICL_FAILURE);
2N/A } else {
2N/A vbuf = alloca(pinfo.piclinfo.size);
2N/A if (vbuf == NULL)
2N/A return (PICL_FAILURE);
2N/A err = ptree_get_propval(proph, vbuf,
2N/A pinfo.piclinfo.size);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A if (!prop_match(pinfo, vbuf, pval))
2N/A return (PICL_FAILURE);
2N/A }
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/Astatic int
2N/Aget_child_by_path(picl_nodehdl_t rooth, char *prl,
2N/A picl_nodehdl_t *nodeh, char *pname)
2N/A{
2N/A picl_nodehdl_t chdh;
2N/A int err;
2N/A char *nameval;
2N/A char *nodename;
2N/A char *path;
2N/A char *baddr;
2N/A char *busval;
2N/A prop_list_t *plist;
2N/A prop_list_t *ptr;
2N/A
2N/A if (prl == NULL)
2N/A return (PICL_FAILURE);
2N/A
2N/A path = strdupa(prl);
2N/A if (path == NULL)
2N/A return (PICL_FAILURE);
2N/A
2N/A plist = NULL;
2N/A nodename = NULL;
2N/A baddr = NULL;
2N/A
2N/A err = parse_prl(path, &nodename, &baddr, &plist);
2N/A if (err != PICL_SUCCESS) {
2N/A free_list(plist);
2N/A return (err);
2N/A }
2N/A
2N/A if (nodename == NULL)
2N/A return (PICL_FAILURE);
2N/A
2N/A nameval = alloca(strlen(nodename) + 1);
2N/A if (nameval == NULL) {
2N/A free_list(plist);
2N/A return (PICL_FAILURE);
2N/A }
2N/A
2N/A if (baddr != NULL) {
2N/A busval = alloca(strlen(baddr) + 1);
2N/A if (busval == NULL) {
2N/A free_list(plist);
2N/A return (PICL_FAILURE);
2N/A }
2N/A }
2N/A
2N/A for (err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh,
2N/A sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND;
2N/A err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
2N/A sizeof (picl_nodehdl_t))) {
2N/A if (err != PICL_SUCCESS) {
2N/A free_list(plist);
2N/A return (PICL_FAILURE);
2N/A }
2N/A
2N/A /*
2N/A * compare name
2N/A */
2N/A if ((strcmp(pname, PICL_PROP_CLASSNAME) != 0) ||
2N/A (strcmp(nodename, PICL_CLASS_PICL) != 0)) {
2N/A err = ptree_get_propval_by_name(chdh, pname,
2N/A nameval, (strlen(nodename) + 1));
2N/A
2N/A if (err != PICL_SUCCESS)
2N/A continue;
2N/A if (strcmp(nameval, nodename) != 0)
2N/A continue;
2N/A }
2N/A
2N/A /*
2N/A * compare device address with bus-addr prop first
2N/A * then with UnitAddress property
2N/A */
2N/A if (baddr != NULL) { /* compare bus-addr prop */
2N/A if ((ptree_get_propval_by_name(chdh, PICL_PROP_BUS_ADDR,
2N/A busval, (strlen(baddr) + 1)) != PICL_SUCCESS) &&
2N/A (ptree_get_propval_by_name(chdh,
2N/A PICL_PROP_UNIT_ADDRESS, busval,
2N/A (strlen(baddr) + 1)) != PICL_SUCCESS))
2N/A continue;
2N/A
2N/A if (strcmp(busval, baddr) != 0)
2N/A continue; /* not match */
2N/A }
2N/A
2N/A if (plist == NULL) { /* no prop expression */
2N/A *nodeh = chdh;
2N/A return (PICL_SUCCESS);
2N/A }
2N/A
2N/A /*
2N/A * compare the property expression list
2N/A */
2N/A ptr = plist;
2N/A
2N/A while (ptr != NULL) {
2N/A err = check_propval(chdh, ptr->pname, ptr->pval);
2N/A if (err != PICL_SUCCESS)
2N/A break;
2N/A
2N/A ptr = ptr->next;
2N/A }
2N/A if (ptr == NULL) {
2N/A *nodeh = chdh;
2N/A free_list(plist);
2N/A return (PICL_SUCCESS);
2N/A }
2N/A }
2N/A free_list(plist);
2N/A return (PICL_NOTNODE);
2N/A}
2N/A
2N/A/*
2N/A * This functions returns the handle of node specified by its path
2N/A */
2N/Aint
2N/Aptree_get_node_by_path(const char *piclprl, picl_nodehdl_t *handle)
2N/A{
2N/A picl_nodehdl_t rooth;
2N/A picl_nodehdl_t chdh;
2N/A char *path;
2N/A char *ptr;
2N/A char *defprop;
2N/A char *tokindex;
2N/A int err;
2N/A int len;
2N/A int npflg; /* namepath flag */
2N/A
2N/A
2N/A path = strdupa(piclprl);
2N/A if (path == NULL)
2N/A return (PICL_FAILURE);
2N/A
2N/A npflg = 1; /* default */
2N/A defprop = path;
2N/A if (path[0] == '/') {
2N/A ptr = &path[1];
2N/A } else if ((tokindex = strchr(path, ':')) != NULL) {
2N/A *tokindex = '\0';
2N/A ++tokindex;
2N/A if (*tokindex == '/')
2N/A ptr = tokindex + 1;
2N/A else
2N/A return (PICL_NOTNODE);
2N/A npflg = 0;
2N/A } else
2N/A return (PICL_NOTNODE);
2N/A
2N/A err = ptree_get_root(&rooth);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A for (chdh = rooth, tokindex = strchr(ptr, '/');
2N/A tokindex != NULL;
2N/A ptr = tokindex + 1, tokindex = strchr(ptr, '/')) {
2N/A *tokindex = '\0';
2N/A if (npflg)
2N/A err = get_child_by_path(chdh, ptr, &chdh,
2N/A PICL_PROP_NAME);
2N/A else
2N/A err = get_child_by_path(chdh, ptr, &chdh,
2N/A defprop);
2N/A
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A }
2N/A
2N/A /*
2N/A * check if last token is empty or not
2N/A * eg. /a/b/c/ or /a/b/c
2N/A */
2N/A if (*ptr == '\0') {
2N/A *handle = chdh;
2N/A return (PICL_SUCCESS);
2N/A }
2N/A
2N/A len = strcspn(ptr, " \t\n");
2N/A if (len == 0) {
2N/A *handle = chdh;
2N/A return (PICL_SUCCESS);
2N/A }
2N/A
2N/A ptr[len] = '\0';
2N/A if (npflg)
2N/A err = get_child_by_path(chdh, ptr, &chdh, PICL_PROP_NAME);
2N/A else
2N/A err = get_child_by_path(chdh, ptr, &chdh, defprop);
2N/A
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A *handle = chdh;
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Initialize propinfo
2N/A */
2N/Aint
2N/Aptree_init_propinfo(ptree_propinfo_t *infop, int version, int ptype, int pmode,
2N/A size_t psize, char *pname, int (*readfn)(ptree_rarg_t *, void *),
2N/A int (*writefn)(ptree_warg_t *, const void *))
2N/A{
2N/A if (version != PTREE_PROPINFO_VERSION_1)
2N/A return (PICL_NOTSUPPORTED);
2N/A if ((infop == NULL) || (pname == NULL))
2N/A return (PICL_INVALIDARG);
2N/A infop->version = version;
2N/A infop->piclinfo.type = ptype;
2N/A infop->piclinfo.accessmode = pmode;
2N/A infop->piclinfo.size = psize;
2N/A infop->read = readfn;
2N/A infop->write = writefn;
2N/A (void) strlcpy(infop->piclinfo.name, pname, PICL_PROPNAMELEN_MAX);
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Creates a property, adds it to the node, and returns the property
2N/A * handle to the caller if successful and proph is not NULL
2N/A */
2N/Aint
2N/Aptree_create_and_add_prop(picl_nodehdl_t nodeh, ptree_propinfo_t *infop,
2N/A void *vbuf, picl_prophdl_t *proph)
2N/A{
2N/A int err;
2N/A picl_prophdl_t tmph;
2N/A
2N/A err = ptree_create_prop(infop, vbuf, &tmph);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A err = ptree_add_prop(nodeh, tmph);
2N/A if (err != PICL_SUCCESS) {
2N/A (void) ptree_destroy_prop(tmph);
2N/A return (err);
2N/A }
2N/A if (proph)
2N/A *proph = tmph;
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Creates a node, adds it to its parent node, and returns the node
2N/A * handle to the caller if successful
2N/A */
2N/Aint
2N/Aptree_create_and_add_node(picl_nodehdl_t rooth, const char *name,
2N/A const char *classname, picl_nodehdl_t *nodeh)
2N/A{
2N/A picl_nodehdl_t tmph;
2N/A int err;
2N/A
2N/A err = ptree_create_node(name, classname, &tmph);
2N/A
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A err = ptree_add_node(rooth, tmph);
2N/A if (err != PICL_SUCCESS) {
2N/A (void) ptree_destroy_node(tmph);
2N/A return (err);
2N/A }
2N/A
2N/A *nodeh = tmph;
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * recursively visit all nodes
2N/A */
2N/Astatic int
2N/Ado_walk(picl_nodehdl_t rooth, const char *classname,
2N/A void *c_args, int (*callback_fn)(picl_nodehdl_t hdl, void *args))
2N/A{
2N/A int err;
2N/A picl_nodehdl_t chdh;
2N/A char classval[PICL_CLASSNAMELEN_MAX];
2N/A
2N/A err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh,
2N/A sizeof (chdh));
2N/A while (err == PICL_SUCCESS) {
2N/A err = ptree_get_propval_by_name(chdh, PICL_PROP_CLASSNAME,
2N/A classval, sizeof (classval));
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A if ((classname == NULL) || (strcmp(classname, classval) == 0)) {
2N/A err = callback_fn(chdh, c_args);
2N/A if (err != PICL_WALK_CONTINUE)
2N/A return (err);
2N/A }
2N/A
2N/A if ((err = do_walk(chdh, classname, c_args, callback_fn)) !=
2N/A PICL_WALK_CONTINUE)
2N/A return (err);
2N/A
2N/A err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
2N/A sizeof (chdh));
2N/A }
2N/A if (err == PICL_PROPNOTFOUND) /* end of a branch */
2N/A return (PICL_WALK_CONTINUE);
2N/A return (err);
2N/A
2N/A}
2N/A
2N/A/*
2N/A * This function visits all the nodes in the subtree rooted at <rooth>.
2N/A * For each node that matches the class name specified, the callback
2N/A * function is invoked.
2N/A */
2N/Aint
2N/Aptree_walk_tree_by_class(picl_nodehdl_t rooth, const char *classname,
2N/A void *c_args, int (*callback_fn)(picl_nodehdl_t hdl, void *args))
2N/A{
2N/A int err;
2N/A
2N/A if (callback_fn == NULL)
2N/A return (PICL_INVALIDARG);
2N/A err = do_walk(rooth, classname, c_args, callback_fn);
2N/A if ((err == PICL_WALK_CONTINUE) || (err == PICL_WALK_TERMINATE))
2N/A return (PICL_SUCCESS);
2N/A return (err);
2N/A}
2N/A
2N/Astatic int
2N/Acompare_propval(picl_nodehdl_t nodeh, char *pname, picl_prop_type_t ptype,
2N/A void *pval, size_t valsize)
2N/A{
2N/A int err;
2N/A picl_prophdl_t proph;
2N/A ptree_propinfo_t propinfo;
2N/A void *vbuf;
2N/A
2N/A err = ptree_get_prop_by_name(nodeh, pname, &proph);
2N/A if (err != PICL_SUCCESS)
2N/A return (0);
2N/A err = ptree_get_propinfo(proph, &propinfo);
2N/A if (err != PICL_SUCCESS)
2N/A return (0);
2N/A if (propinfo.piclinfo.type != ptype)
2N/A return (0);
2N/A if (propinfo.piclinfo.type == PICL_PTYPE_VOID)
2N/A return (1);
2N/A if (pval == NULL)
2N/A return (0);
2N/A if (valsize > propinfo.piclinfo.size)
2N/A return (0);
2N/A vbuf = alloca(propinfo.piclinfo.size);
2N/A if (vbuf == NULL)
2N/A return (0);
2N/A err = ptree_get_propval(proph, vbuf, propinfo.piclinfo.size);
2N/A if (err != PICL_SUCCESS)
2N/A return (0);
2N/A if (memcmp(vbuf, pval, valsize) == 0)
2N/A return (1);
2N/A return (0);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * This function traverses the subtree and finds a node that has a property
2N/A * of the specified name and type with the specified value.
2N/A * The matched node in the tree is returned in retnodeh. If there is
2N/A * no node with that property, then PICL_NODENOTFOUND is returned.
2N/A */
2N/Aint
2N/Aptree_find_node(picl_nodehdl_t rooth, char *pname, picl_prop_type_t ptype,
2N/A void *pval, size_t valsize, picl_nodehdl_t *retnodeh)
2N/A{
2N/A int err;
2N/A picl_nodehdl_t chdh;
2N/A
2N/A if (pname == NULL)
2N/A return (PICL_INVALIDARG);
2N/A err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh,
2N/A sizeof (chdh));
2N/A
2N/A while (err == PICL_SUCCESS) {
2N/A if (compare_propval(chdh, pname, ptype, pval, valsize)) {
2N/A if (retnodeh)
2N/A *retnodeh = chdh;
2N/A return (PICL_SUCCESS);
2N/A }
2N/A
2N/A err = ptree_find_node(chdh, pname, ptype, pval, valsize,
2N/A retnodeh);
2N/A if (err != PICL_NODENOTFOUND)
2N/A return (err);
2N/A
2N/A err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
2N/A sizeof (chdh));
2N/A }
2N/A if (err == PICL_PROPNOTFOUND)
2N/A return (PICL_NODENOTFOUND);
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * This function gets the frutree parent for a given node.
2N/A * Traverse up the tree and look for the following properties:
2N/A * Frutree parent reference properties:
2N/A * _fru_parent
2N/A * _location_parent
2N/A * _port_parent
2N/A * If the frutree reference property is found, return its value.
2N/A * Else, return the handle of /frutree/chassis.
2N/A */
2N/Aint
2N/Aptree_get_frutree_parent(picl_nodehdl_t nodeh, picl_nodehdl_t *fruh)
2N/A{
2N/A int err;
2N/A picl_nodehdl_t nparh;
2N/A picl_nodehdl_t fruparh;
2N/A
2N/A err = PICL_SUCCESS;
2N/A nparh = nodeh;
2N/A while (err == PICL_SUCCESS) {
2N/A err = ptree_get_propval_by_name(nparh, PICL_REFPROP_FRU_PARENT,
2N/A &fruparh, sizeof (fruparh));
2N/A if (err == PICL_SUCCESS) {
2N/A *fruh = fruparh;
2N/A return (PICL_SUCCESS);
2N/A }
2N/A err = ptree_get_propval_by_name(nparh,
2N/A PICL_REFPROP_LOC_PARENT, &fruparh, sizeof (fruparh));
2N/A if (err == PICL_SUCCESS) {
2N/A *fruh = fruparh;
2N/A return (PICL_SUCCESS);
2N/A }
2N/A err = ptree_get_propval_by_name(nparh, PICL_REFPROP_PORT_PARENT,
2N/A &fruparh, sizeof (fruparh));
2N/A if (err == PICL_SUCCESS) {
2N/A *fruh = fruparh;
2N/A return (PICL_SUCCESS);
2N/A }
2N/A
2N/A err = ptree_get_propval_by_name(nparh, PICL_PROP_PARENT, &nparh,
2N/A sizeof (nparh));
2N/A }
2N/A
2N/A if (err == PICL_PROPNOTFOUND) { /* return /frutree/chassis handle */
2N/A err = ptree_get_node_by_path(PICL_FRUTREE_CHASSIS, &fruparh);
2N/A if (err == PICL_SUCCESS) {
2N/A *fruh = fruparh;
2N/A return (PICL_SUCCESS);
2N/A }
2N/A }
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * This function is called by plug-ins to register with the daemon
2N/A */
2N/Aint
2N/Apicld_plugin_register(picld_plugin_reg_t *regp)
2N/A{
2N/A picld_plugin_reg_list_t *el;
2N/A picld_plugin_reg_list_t *tmp;
2N/A
2N/A if (regp == NULL)
2N/A return (PICL_FAILURE);
2N/A
2N/A if (regp->version != PICLD_PLUGIN_VERSION_1)
2N/A return (PICL_NOTSUPPORTED);
2N/A
2N/A el = malloc(sizeof (picld_plugin_reg_list_t));
2N/A if (el == NULL)
2N/A return (PICL_FAILURE);
2N/A el->reg.version = regp->version;
2N/A el->reg.critical = regp->critical;
2N/A if (regp->name)
2N/A el->reg.name = strdup(regp->name);
2N/A if (el->reg.name == NULL)
2N/A return (PICL_FAILURE);
2N/A
2N/A el->reg.plugin_init = regp->plugin_init;
2N/A el->reg.plugin_fini = regp->plugin_fini;
2N/A el->next = NULL;
2N/A
2N/A if (plugin_reg_list == NULL) {
2N/A plugin_reg_list = el;
2N/A } else { /* add to end */
2N/A tmp = plugin_reg_list;
2N/A while (tmp->next != NULL)
2N/A tmp = tmp->next;
2N/A tmp->next = el;
2N/A }
2N/A
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Call fini routines of the registered plugins
2N/A */
2N/Astatic void
2N/Aplugin_fini(picld_plugin_reg_list_t *p)
2N/A{
2N/A if (p == NULL)
2N/A return;
2N/A
2N/A plugin_fini(p->next);
2N/A if (p->reg.plugin_fini)
2N/A (p->reg.plugin_fini)();
2N/A}
2N/A
2N/A/*
2N/A * Create PICL Tree
2N/A */
2N/A
2N/Astatic void
2N/Ainit_plugin_reg_list(void)
2N/A{
2N/A plugin_reg_list = NULL;
2N/A}
2N/A
2N/Astatic int
2N/Apicltree_set_root(picl_nodehdl_t rooth)
2N/A{
2N/A picl_obj_t *pobj;
2N/A int err;
2N/A
2N/A (void) rw_rdlock(&ptree_rwlock); /* lock ptree */
2N/A pobj = NULL;
2N/A err = lookup_and_lock_node(RDLOCK_NODE, rooth, &pobj); /* lock node */
2N/A if (err != PICL_SUCCESS) {
2N/A (void) rw_unlock(&ptree_rwlock);
2N/A return (PICL_FAILURE);
2N/A }
2N/A piclize_node(pobj);
2N/A picl_root_obj = pobj;
2N/A ptree_root_hdl = pobj->ptree_hdl;
2N/A unlock_node(pobj); /* unlock node */
2N/A (void) rw_unlock(&ptree_rwlock); /* unlock ptree */
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/Astatic int
2N/Apicltree_init(void)
2N/A{
2N/A (void) rwlock_init(&ptree_rwlock, USYNC_THREAD, NULL);
2N/A (void) rwlock_init(&picltbl_rwlock, USYNC_THREAD, NULL);
2N/A
2N/A if (hash_init(&picltbl) < 0)
2N/A return (PICL_FAILURE);
2N/A if (hash_init(&ptreetbl) < 0)
2N/A return (PICL_FAILURE);
2N/A
2N/A if (pthread_mutex_init(&ptreehdl_lock, NULL) != 0)
2N/A return (PICL_FAILURE);
2N/A
2N/A if (pthread_mutex_init(&piclhdl_lock, NULL) != 0)
2N/A return (PICL_FAILURE);
2N/A
2N/A if (pthread_mutex_init(&evtq_lock, NULL) != 0)
2N/A return (PICL_FAILURE);
2N/A if (pthread_cond_init(&evtq_cv, NULL) != 0)
2N/A return (PICL_FAILURE);
2N/A if (pthread_mutex_init(&evthandler_lock, NULL) != 0)
2N/A return (PICL_FAILURE);
2N/A
2N/A picl_root_obj = NULL;
2N/A eventqp = NULL;
2N/A evt_handlers = NULL;
2N/A ptree_root_hdl = PICL_INVALID_PICLHDL;
2N/A
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/Astatic void
2N/Aadd_unique_plugin_to_list(char *path, char *name)
2N/A{
2N/A char *buf;
2N/A picld_plugin_desc_t *pl;
2N/A picld_plugin_desc_t *tmp;
2N/A
2N/A pl = plugin_desc;
2N/A while (pl != NULL) {
2N/A if (strcmp(pl->libname, name) == 0)
2N/A return;
2N/A else
2N/A pl = pl->next;
2N/A }
2N/A
2N/A pl = malloc(sizeof (picld_plugin_desc_t));
2N/A if (pl == NULL)
2N/A return;
2N/A
2N/A pl->libname = strdup(name);
2N/A if (pl->libname == NULL)
2N/A return;
2N/A buf = alloca(strlen(name) + strlen(path) + 2);
2N/A if (buf == NULL)
2N/A return;
2N/A (void) strcpy(buf, path);
2N/A (void) strcat(buf, name);
2N/A pl->pathname = strdup(buf);
2N/A if (pl->pathname == NULL)
2N/A return;
2N/A
2N/A pl->next = NULL;
2N/A
2N/A if (plugin_desc == NULL)
2N/A plugin_desc = pl;
2N/A else {
2N/A tmp = plugin_desc;
2N/A while (tmp->next != NULL)
2N/A tmp = tmp->next;
2N/A tmp->next = pl;
2N/A }
2N/A}
2N/A
2N/Astatic void
2N/Aget_plugins_from_dir(char *dirname)
2N/A{
2N/A struct dirent *ent;
2N/A DIR *dir;
2N/A int len;
2N/A int solen = strlen(SO_VERS) + 1;
2N/A
2N/A if ((dir = opendir(dirname)) == NULL)
2N/A return;
2N/A
2N/A while ((ent = readdir(dir)) != NULL) {
2N/A if ((strcmp(ent->d_name, ".") == 0) ||
2N/A (strcmp(ent->d_name, "..") == 0))
2N/A continue;
2N/A
2N/A len = strlen(ent->d_name) + 1;
2N/A if (len < solen)
2N/A continue;
2N/A
2N/A if (strcmp(ent->d_name + (len - solen), SO_VERS) == 0)
2N/A add_unique_plugin_to_list(dirname, ent->d_name);
2N/A }
2N/A
2N/A (void) closedir(dir);
2N/A}
2N/A
2N/A
2N/Astatic void
2N/Ainit_plugin_list(void)
2N/A{
2N/A char nmbuf[SYS_NMLN];
2N/A char pname[PATH_MAX];
2N/A
2N/A plugin_desc = NULL;
2N/A if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) {
2N/A (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
2N/A if (access(pname, R_OK) == 0)
2N/A get_plugins_from_dir(pname);
2N/A }
2N/A
2N/A if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) {
2N/A (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
2N/A if (access(pname, R_OK) == 0)
2N/A get_plugins_from_dir(pname);
2N/A }
2N/A
2N/A (void) snprintf(pname, PATH_MAX, "%s/", PICLD_COMMON_PLUGIN_DIR);
2N/A if (access(pname, R_OK) == 0)
2N/A get_plugins_from_dir(pname);
2N/A}
2N/A
2N/Astatic void
2N/Aload_plugins(void)
2N/A{
2N/A picld_plugin_desc_t *pl;
2N/A
2N/A pl = plugin_desc;
2N/A while (pl != NULL) {
2N/A pl->dlh = dlopen(pl->pathname, RTLD_LAZY|RTLD_LOCAL);
2N/A if (pl->dlh == NULL) {
2N/A syslog(LOG_CRIT, dlerror());
2N/A return;
2N/A }
2N/A pl = pl->next;
2N/A }
2N/A}
2N/A
2N/A
2N/A
2N/Astatic int
2N/Aadd_root_props(picl_nodehdl_t rooth)
2N/A{
2N/A int err;
2N/A picl_prophdl_t proph;
2N/A ptree_propinfo_t pinfo;
2N/A float picl_vers;
2N/A
2N/A#define PICL_PROP_PICL_VERSION "PICLVersion"
2N/A#define PICL_VERSION 1.1
2N/A
2N/A err = ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION_1,
2N/A PICL_PTYPE_FLOAT, PICL_READ, sizeof (picl_vers),
2N/A PICL_PROP_PICL_VERSION, NULL, NULL);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A picl_vers = PICL_VERSION;
2N/A err = ptree_create_and_add_prop(rooth, &pinfo, &picl_vers, &proph);
2N/A return (err);
2N/A}
2N/A
2N/Astatic int
2N/Aconstruct_picltree(void)
2N/A{
2N/A int err;
2N/A picld_plugin_reg_list_t *iter;
2N/A picl_nodehdl_t rhdl;
2N/A
2N/A /*
2N/A * Create "/" node
2N/A */
2N/A if ((err = ptree_create_node(PICL_NODE_ROOT, PICL_CLASS_PICL,
2N/A &rhdl)) != PICL_SUCCESS) {
2N/A return (err);
2N/A }
2N/A
2N/A if (picltree_set_root(rhdl) != PICL_SUCCESS) {
2N/A return (PICL_FAILURE);
2N/A }
2N/A
2N/A err = add_root_props(rhdl);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A /*
2N/A * Initialize the registered plug-in modules
2N/A */
2N/A iter = plugin_reg_list;
2N/A while (iter != NULL) {
2N/A if (iter->reg.plugin_init)
2N/A (iter->reg.plugin_init)();
2N/A iter = iter->next;
2N/A }
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/Avoid
2N/Axptree_destroy(void)
2N/A{
2N/A dbg_print(1, "xptree_destroy: picl_root_obj = %s\n",
2N/A (picl_root_obj == NULL ? "NULL" : "not-NULL"));
2N/A
2N/A if (picl_root_obj == NULL)
2N/A return;
2N/A
2N/A dbg_print(1, "xptree_destroy: call plugin_fini\n");
2N/A plugin_fini(plugin_reg_list);
2N/A dbg_print(1, "xptree_destroy: plugin_fini DONE\n");
2N/A
2N/A (void) ptree_delete_node(picl_root_obj->ptree_hdl);
2N/A (void) ptree_destroy_node(picl_root_obj->ptree_hdl);
2N/A
2N/A (void) rw_wrlock(&ptree_rwlock);
2N/A picl_root_obj = NULL;
2N/A (void) rw_unlock(&ptree_rwlock);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Aint
2N/Axptree_initialize(int flg)
2N/A{
2N/A int err;
2N/A pthread_attr_t attr;
2N/A pthread_t tid;
2N/A
2N/A picld_pid = getpid();
2N/A picld_cred.dc_euid = geteuid();
2N/A picld_cred.dc_egid = getegid();
2N/A picld_cred.dc_ruid = getuid();
2N/A picld_cred.dc_rgid = getgid();
2N/A picld_cred.dc_pid = getpid();
2N/A
2N/A picl_hdl_hi = 1;
2N/A ptree_hdl_hi = 1;
2N/A ptree_generation = 1;
2N/A qempty_wait = 0;
2N/A
2N/A if (pthread_mutex_init(&ptree_refresh_mutex, NULL) != 0)
2N/A return (PICL_FAILURE);
2N/A
2N/A if (picltree_init() != PICL_SUCCESS)
2N/A return (PICL_FAILURE);
2N/A
2N/A init_plugin_reg_list();
2N/A init_plugin_list();
2N/A load_plugins();
2N/A
2N/A err = construct_picltree();
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A /*
2N/A * Dispatch events after all plug-ins have initialized
2N/A */
2N/A if (pthread_attr_init(&attr) != 0)
2N/A return (PICL_FAILURE);
2N/A
2N/A (void) pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
2N/A if (pthread_create(&tid, &attr, ptree_event_thread, NULL))
2N/A return (PICL_FAILURE);
2N/A
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/Aint
2N/Axptree_reinitialize(void)
2N/A{
2N/A int err;
2N/A
2N/A /*
2N/A * Wait for eventq to become empty
2N/A */
2N/A dbg_print(1, "xptree_reinitialize: wait for evtq empty\n");
2N/A (void) pthread_mutex_lock(&evtq_lock);
2N/A qempty_wait = 1;
2N/A while (eventqp != NULL)
2N/A (void) pthread_cond_wait(&evtq_empty, &evtq_lock);
2N/A qempty_wait = 0;
2N/A (void) pthread_mutex_unlock(&evtq_lock);
2N/A dbg_print(1, "xptree_reinitialize: evtq empty is EMPTY\n");
2N/A
2N/A (void) rw_wrlock(&ptree_rwlock);
2N/A picl_root_obj = NULL;
2N/A ptree_root_hdl = PICL_INVALID_PICLHDL;
2N/A (void) rw_unlock(&ptree_rwlock);
2N/A (void) pthread_mutex_lock(&ptree_refresh_mutex);
2N/A ++ptree_generation;
2N/A (void) pthread_mutex_unlock(&ptree_refresh_mutex);
2N/A
2N/A err = construct_picltree();
2N/A (void) pthread_mutex_lock(&ptree_refresh_mutex);
2N/A (void) pthread_cond_broadcast(&ptree_refresh_cond);
2N/A (void) pthread_mutex_unlock(&ptree_refresh_mutex);
2N/A
2N/A (void) pthread_mutex_lock(&evtq_lock);
2N/A (void) pthread_cond_broadcast(&evtq_cv);
2N/A (void) pthread_mutex_unlock(&evtq_lock);
2N/A
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * This function is called by the PICL daemon on behalf of clients to
2N/A * wait for a tree refresh
2N/A */
2N/Aint
2N/Axptree_refresh_notify(uint32_t secs)
2N/A{
2N/A int curgen;
2N/A int ret;
2N/A timespec_t to;
2N/A
2N/A if (secs != 0) {
2N/A if (pthread_mutex_lock(&ptree_refresh_mutex) != 0)
2N/A return (PICL_FAILURE);
2N/A
2N/A curgen = ptree_generation;
2N/A
2N/A while (curgen == ptree_generation) {
2N/A if (secs == UINT32_MAX) /* wait forever */
2N/A (void) pthread_cond_wait(&ptree_refresh_cond,
2N/A &ptree_refresh_mutex);
2N/A else {
2N/A to.tv_sec = secs;
2N/A to.tv_nsec = 0;
2N/A ret = pthread_cond_reltimedwait_np(
2N/A &ptree_refresh_cond,
2N/A &ptree_refresh_mutex, &to);
2N/A if (ret == ETIMEDOUT)
2N/A break;
2N/A }
2N/A }
2N/A
2N/A (void) pthread_mutex_unlock(&ptree_refresh_mutex);
2N/A }
2N/A
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*VARARGS2*/
2N/Avoid
2N/Adbg_print(int level, const char *fmt, ...)
2N/A{
2N/A if (verbose_level >= level) {
2N/A va_list ap;
2N/A
2N/A va_start(ap, fmt);
2N/A (void) vprintf(fmt, ap);
2N/A va_end(ap);
2N/A }
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Avoid
2N/Adbg_exec(int level, void (*fn)(void *args), void *args)
2N/A{
2N/A if (verbose_level > level)
2N/A (*fn)(args);
2N/A}