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, Version 1.0 only
2N/A * (the "License"). You may not use this file except in compliance
2N/A * 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 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A/*
2N/A * This module implements the PICL Interface used by PICL clients
2N/A * to access services of the PICL daemon
2N/A *
2N/A * Locking Strategy
2N/A * A single reader/writer lock (icl_lock) protects the access to the interface
2N/A * to the picl daemon, and the reference count, refcnt, variable.
2N/A * A reader lock is obtained to send a request to the daemon.
2N/A * A writer lock is obtained to initialize, reinitialize, or shutdown
2N/A * the interface.
2N/A */
2N/A
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <string.h>
2N/A#include <unistd.h>
2N/A#include <alloca.h>
2N/A#include <fcntl.h>
2N/A#include <libintl.h>
2N/A#include <errno.h>
2N/A#include <sys/mman.h>
2N/A#include <door.h>
2N/A#include <sys/door.h>
2N/A#include <sys/time.h>
2N/A#include <assert.h>
2N/A#include <synch.h>
2N/A#include <limits.h>
2N/A#include <picl.h>
2N/A#include "picl2door.h"
2N/A
2N/A/*
2N/A * Module variables
2N/A */
2N/Astatic int door_handle = -1;
2N/Astatic uint32_t refcnt = 0;
2N/Astatic rwlock_t picl_lock = DEFAULTRWLOCK;
2N/A
2N/Astatic char *picl_errmsg[] = {
2N/A "No error",
2N/A "General system failure",
2N/A "Daemon not responding",
2N/A "Unknown PICL service",
2N/A "Session not initialized",
2N/A "Invalid arguments",
2N/A "Argument too big",
2N/A "Property not found",
2N/A "Not a table property handle",
2N/A "Not a node handle",
2N/A "Not a property handle",
2N/A "End of property list",
2N/A "Property already exists",
2N/A "Property not writable",
2N/A "Insufficient permissions",
2N/A "Invalid handle",
2N/A "Stale handle",
2N/A "Unsupported version",
2N/A "Wait timed out",
2N/A "Attempting to destroy before delete",
2N/A "PICL Tree is busy",
2N/A "Already has a parent",
2N/A "Property name is reserved",
2N/A "Invalid reference value",
2N/A "Continue tree walk",
2N/A "Terminate tree walk",
2N/A "Node not found",
2N/A "Not enough space available",
2N/A "Property not readable",
2N/A "Property value unavailable"
2N/A};
2N/A
2N/A#define N_ERRORS (sizeof (picl_errmsg)/sizeof (picl_errmsg[0]))
2N/A#define SEND_REQ_TRYCOUNT 1
2N/A
2N/A/*
2N/A * This function sends the client request to the daemon using a door call.
2N/A * If door_handle is -1, it returns PICL_NOTINITIALIZED.
2N/A * If the door_call fails, it returns PICL_NORESPONSE. Otherwise, it
2N/A * checks the response from the daemon for error. If an error is returned
2N/A * this function returns the error code returned and unmaps any
2N/A * memory mapped by the door call. For successful results, the caller is
2N/A * responsible to unmap the mapped memory after retrieving the results.
2N/A *
2N/A * This function does not attempt to reinitialize the interface if the
2N/A * initial door_call fails. It is called from handshake() , shutdown()
2N/A * and trysend_req() routines.
2N/A */
2N/Astatic int
2N/Apost_req(door_arg_t *dargp, void *data_ptr, size_t data_size,
2N/A door_desc_t *desc_ptr, uint_t desc_num, void *rbuf, size_t rsize)
2N/A{
2N/A int err;
2N/A picl_service_t *ret;
2N/A int req_cnum;
2N/A
2N/A req_cnum = ((picl_service_t *)data_ptr)->in.cnum;
2N/A dargp->data_ptr = data_ptr;
2N/A dargp->data_size = data_size;
2N/A dargp->desc_ptr = desc_ptr;
2N/A dargp->desc_num = desc_num;
2N/A dargp->rbuf = rbuf;
2N/A dargp->rsize = rsize;
2N/A
2N/A if (door_call(door_handle, dargp) < 0)
2N/A return (PICL_NORESPONSE);
2N/A
2N/A /*LINTED*/
2N/A ret = (picl_service_t *)dargp->rbuf;
2N/A if (ret->in.cnum == req_cnum)
2N/A return (PICL_SUCCESS);
2N/A else if ((ret->in.cnum == PICL_CNUM_ERROR) &&
2N/A (ret->ret_error.in_cnum == req_cnum))
2N/A err = ret->ret_error.errnum;
2N/A else
2N/A err = PICL_UNKNOWNSERVICE;
2N/A if (dargp->rbuf != rbuf)
2N/A (void) munmap(dargp->rbuf, dargp->rsize);
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * This function posts an INIT message to the daemon to
2N/A * verify communication channel.
2N/A */
2N/Astatic int
2N/Ahandshake(void)
2N/A{
2N/A int err;
2N/A door_arg_t darg;
2N/A picl_reqinit_t req;
2N/A picl_retinit_t outargs;
2N/A
2N/A req.cnum = PICL_CNUM_INIT;
2N/A req.clrev = PICL_VERSION_1;
2N/A
2N/A if ((err = post_req(&darg, &req, sizeof (picl_reqinit_t), NULL,
2N/A 0, &outargs, sizeof (picl_retinit_t))) != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A if (darg.rbuf != (char *)&outargs)
2N/A (void) munmap(darg.rbuf, darg.rsize);
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * This function calls post_req() to make door_call and reinitializes
2N/A * the interface is post_req() fails.
2N/A */
2N/Astatic int
2N/Atrysend_req(door_arg_t *dargp, void *data_ptr, size_t data_size,
2N/A door_desc_t *desc_ptr, uint_t desc_num, void *rbuf, size_t rsize,
2N/A unsigned int trycount)
2N/A{
2N/A int err;
2N/A int write_locked;
2N/A
2N/A write_locked = 0;
2N/A (void) rw_rdlock(&picl_lock);
2N/A if (refcnt == 0) {
2N/A (void) rw_unlock(&picl_lock); /* read unlock */
2N/A return (PICL_NOTINITIALIZED);
2N/A }
2N/A
2N/A while ((err = post_req(dargp, data_ptr, data_size, desc_ptr, desc_num,
2N/A rbuf, rsize)) == PICL_NORESPONSE) {
2N/A if (trycount == 0) /* no more retry */
2N/A break;
2N/A
2N/A if (write_locked == 1) { /* close and open door */
2N/A (void) close(door_handle);
2N/A if ((door_handle = open(PICLD_DOOR, O_RDONLY)) < 0) {
2N/A err = PICL_NORESPONSE;
2N/A break;
2N/A }
2N/A --trycount;
2N/A continue;
2N/A }
2N/A /*
2N/A * Upgrade read to a write lock
2N/A */
2N/A (void) rw_unlock(&picl_lock);
2N/A (void) rw_wrlock(&picl_lock);
2N/A
2N/A /*
2N/A * if picl_shutdown happens during lock upgrade
2N/A */
2N/A if (refcnt == 0) {
2N/A err = PICL_NOTINITIALIZED;
2N/A break;
2N/A }
2N/A write_locked = 1;
2N/A continue;
2N/A }
2N/A (void) rw_unlock(&picl_lock); /* read or write unlock */
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Initialize the PICL interface
2N/A * Increment the reference count.
2N/A */
2N/Aint
2N/Apicl_initialize(void)
2N/A{
2N/A int err;
2N/A
2N/A (void) rw_wrlock(&picl_lock);
2N/A if (refcnt > 0) { /* previously initialized */
2N/A err = handshake();
2N/A if (err == PICL_SUCCESS) {
2N/A ++refcnt;
2N/A (void) rw_unlock(&picl_lock); /* write unlock */
2N/A return (err);
2N/A }
2N/A if (err != PICL_NORESPONSE) {
2N/A (void) rw_unlock(&picl_lock); /* write unlock */
2N/A return (err);
2N/A }
2N/A (void) close(door_handle); /* close bad door */
2N/A }
2N/A
2N/A /*
2N/A * Open picld door and initialize door_handle
2N/A */
2N/A if ((door_handle = open(PICLD_DOOR, O_RDONLY)) < 0) {
2N/A (void) rw_unlock(&picl_lock); /* write unlock */
2N/A return (PICL_NORESPONSE);
2N/A }
2N/A
2N/A err = handshake();
2N/A if (err != PICL_SUCCESS)
2N/A (void) close(door_handle);
2N/A else
2N/A ++refcnt;
2N/A (void) rw_unlock(&picl_lock); /* write unlock */
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Shutdown the PICL interface
2N/A * Decrement the reference count and close the door_handle if refcnt is zero
2N/A */
2N/Aint
2N/Apicl_shutdown(void)
2N/A{
2N/A int err;
2N/A door_arg_t darg;
2N/A picl_reqfini_t req_fini;
2N/A picl_retfini_t outargs;
2N/A
2N/A (void) rw_wrlock(&picl_lock); /* write lock */
2N/A if (refcnt == 0) {
2N/A (void) rw_unlock(&picl_lock); /* write unlock */
2N/A return (PICL_NOTINITIALIZED);
2N/A }
2N/A req_fini.cnum = PICL_CNUM_FINI;
2N/A err = post_req(&darg, &req_fini, sizeof (picl_reqfini_t),
2N/A NULL, 0, &outargs, sizeof (picl_retfini_t));
2N/A --refcnt;
2N/A if (refcnt == 0)
2N/A (void) close(door_handle);
2N/A (void) rw_unlock(&picl_lock); /* write unlock */
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A if (darg.rbuf != (char *)&outargs)
2N/A (void) munmap(darg.rbuf, darg.rsize);
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * This function waits for the specified number of seconds for a PICL
2N/A * tree refresh.
2N/A */
2N/Aint
2N/Apicl_wait(unsigned int secs)
2N/A{
2N/A door_arg_t darg;
2N/A picl_reqwait_t req_wait;
2N/A picl_retwait_t outargs;
2N/A picl_service_t *ret;
2N/A int err;
2N/A
2N/A req_wait.cnum = PICL_CNUM_WAIT;
2N/A req_wait.secs = secs;
2N/A err = trysend_req(&darg, &req_wait, sizeof (picl_reqwait_t),
2N/A NULL, 0, &outargs, sizeof (picl_retwait_t), SEND_REQ_TRYCOUNT);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A /*LINTED*/
2N/A ret = (picl_service_t *)darg.rbuf;
2N/A err = ret->ret_wait.retcode;
2N/A if (darg.rbuf != (char *)&outargs)
2N/A (void) munmap(darg.rbuf, darg.rsize);
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * This function copies the handle of the root node of the PICL tree into
2N/A * the buffer <rooth>
2N/A */
2N/Aint
2N/Apicl_get_root(picl_nodehdl_t *rooth)
2N/A{
2N/A door_arg_t darg;
2N/A picl_reqroot_t req_root;
2N/A picl_retroot_t outargs;
2N/A picl_service_t *ret;
2N/A int err;
2N/A
2N/A req_root.cnum = PICL_CNUM_GETROOT;
2N/A err = trysend_req(&darg, &req_root, sizeof (picl_reqroot_t), NULL,
2N/A 0, &outargs, sizeof (picl_retroot_t), SEND_REQ_TRYCOUNT);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A /*LINTED*/
2N/A ret = (picl_service_t *)darg.rbuf;
2N/A *rooth = ret->ret_root.rnode;
2N/A if (darg.rbuf != (char *)&outargs)
2N/A (void) munmap(darg.rbuf, darg.rsize);
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * This function copies the value of the property specified by its handle
2N/A * into the buffer <valbuf>.
2N/A */
2N/Aint
2N/Apicl_get_propval(picl_prophdl_t proph, void *valbuf, size_t nbytes)
2N/A{
2N/A door_arg_t darg;
2N/A picl_reqattrval_t req_attrval;
2N/A picl_service_t *ret;
2N/A picl_retattrval_t *outargs;
2N/A int err;
2N/A
2N/A req_attrval.cnum = PICL_CNUM_GETATTRVAL;
2N/A req_attrval.attr = proph;
2N/A req_attrval.bufsize = (uint32_t)nbytes;
2N/A if ((size_t)req_attrval.bufsize != nbytes)
2N/A return (PICL_VALUETOOBIG);
2N/A outargs = alloca(sizeof (picl_retattrval_t) + nbytes);
2N/A
2N/A err = trysend_req(&darg, &req_attrval, sizeof (picl_reqattrval_t),
2N/A NULL, 0, outargs, sizeof (picl_retattrval_t) + nbytes,
2N/A SEND_REQ_TRYCOUNT);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A /*LINTED*/
2N/A ret = (picl_service_t *)darg.rbuf;
2N/A if (ret->ret_attrval.nbytes > (uint32_t)nbytes)
2N/A err = PICL_VALUETOOBIG;
2N/A else
2N/A (void) memcpy(valbuf, ret->ret_attrval.ret_buf,
2N/A (size_t)ret->ret_attrval.nbytes);
2N/A if (darg.rbuf != (char *)outargs)
2N/A (void) munmap(darg.rbuf, darg.rsize);
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * This function copies the value of the property specified by its
2N/A * name into the buffer <valbuf>
2N/A */
2N/Aint
2N/Apicl_get_propval_by_name(picl_nodehdl_t nodeh, const char *propname,
2N/A void *valbuf, size_t nbytes)
2N/A{
2N/A door_arg_t darg;
2N/A picl_reqattrvalbyname_t req_attrvalbyname;
2N/A picl_service_t *ret;
2N/A picl_retattrvalbyname_t *outargs;
2N/A int err;
2N/A
2N/A req_attrvalbyname.cnum = PICL_CNUM_GETATTRVALBYNAME;
2N/A req_attrvalbyname.nodeh = nodeh;
2N/A (void) strcpy(req_attrvalbyname.propname, propname);
2N/A req_attrvalbyname.bufsize = (uint32_t)nbytes;
2N/A if ((size_t)req_attrvalbyname.bufsize != nbytes)
2N/A return (PICL_VALUETOOBIG);
2N/A outargs = alloca(sizeof (picl_retattrvalbyname_t) + nbytes);
2N/A
2N/A err = trysend_req(&darg, &req_attrvalbyname,
2N/A sizeof (picl_reqattrvalbyname_t), NULL, 0, outargs,
2N/A sizeof (picl_retattrvalbyname_t) + nbytes, SEND_REQ_TRYCOUNT);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A /*LINTED*/
2N/A ret = (picl_service_t *)darg.rbuf;
2N/A if (ret->ret_attrvalbyname.nbytes > (uint32_t)nbytes)
2N/A err = PICL_VALUETOOBIG;
2N/A else
2N/A (void) memcpy(valbuf, ret->ret_attrvalbyname.ret_buf,
2N/A (size_t)ret->ret_attrvalbyname.nbytes);
2N/A if (darg.rbuf != (char *)outargs)
2N/A (void) munmap(darg.rbuf, darg.rsize);
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * This function sets the value of the property specified by its
2N/A * handle with the value specified in <valbuf>.
2N/A */
2N/Aint
2N/Apicl_set_propval(picl_prophdl_t proph, void *valbuf, size_t nbytes)
2N/A{
2N/A door_arg_t darg;
2N/A picl_reqsetattrval_t ret_setattrval;
2N/A picl_reqsetattrval_t *inargs;
2N/A int err;
2N/A
2N/A if (nbytes >= (size_t)PICL_PROPSIZE_MAX)
2N/A return (PICL_VALUETOOBIG);
2N/A
2N/A inargs = alloca(sizeof (picl_reqsetattrval_t) + nbytes);
2N/A inargs->cnum = PICL_CNUM_SETATTRVAL;
2N/A inargs->attr = proph;
2N/A inargs->bufsize = (uint32_t)nbytes;
2N/A if ((size_t)inargs->bufsize != nbytes)
2N/A return (PICL_VALUETOOBIG);
2N/A (void) memcpy(inargs->valbuf, valbuf, nbytes);
2N/A
2N/A err = trysend_req(&darg, inargs, sizeof (picl_reqsetattrval_t) +
2N/A nbytes, NULL, 0, &ret_setattrval,
2N/A sizeof (picl_retsetattrval_t), SEND_REQ_TRYCOUNT);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A if (darg.rbuf != (char *)&ret_setattrval)
2N/A (void) munmap(darg.rbuf, darg.rsize);
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * This function sets the value of the property specified by its
2N/A * name with the value given in <valbuf>
2N/A */
2N/Aint
2N/Apicl_set_propval_by_name(picl_nodehdl_t nodeh, const char *propname,
2N/A void *valbuf, size_t nbytes)
2N/A{
2N/A door_arg_t darg;
2N/A picl_retsetattrvalbyname_t ret_setattrvalbyname;
2N/A picl_reqsetattrvalbyname_t *inargs;
2N/A int err;
2N/A
2N/A if (nbytes >= (size_t)PICL_PROPSIZE_MAX)
2N/A return (PICL_VALUETOOBIG);
2N/A
2N/A inargs = alloca(sizeof (picl_reqsetattrvalbyname_t) + nbytes);
2N/A inargs->cnum = PICL_CNUM_SETATTRVALBYNAME;
2N/A inargs->nodeh = nodeh;
2N/A (void) strcpy(inargs->propname, propname);
2N/A inargs->bufsize = (uint32_t)nbytes;
2N/A if ((size_t)inargs->bufsize != nbytes)
2N/A return (PICL_VALUETOOBIG);
2N/A (void) memcpy(inargs->valbuf, valbuf, nbytes);
2N/A
2N/A err = trysend_req(&darg, inargs,
2N/A sizeof (picl_reqsetattrvalbyname_t) + nbytes, NULL, 0,
2N/A &ret_setattrvalbyname, sizeof (picl_retsetattrvalbyname_t),
2N/A SEND_REQ_TRYCOUNT);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A if (darg.rbuf != (char *)&ret_setattrvalbyname)
2N/A (void) munmap(darg.rbuf, darg.rsize);
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * This function copies the information of the specified property
2N/A * into <pinfo>
2N/A */
2N/Aint
2N/Apicl_get_propinfo(picl_prophdl_t proph, picl_propinfo_t *pinfo)
2N/A{
2N/A door_arg_t darg;
2N/A picl_reqattrinfo_t req_attrinfo;
2N/A picl_service_t *ret;
2N/A picl_retattrinfo_t outargs;
2N/A int err;
2N/A
2N/A req_attrinfo.cnum = PICL_CNUM_GETATTRINFO;
2N/A req_attrinfo.attr = proph;
2N/A
2N/A err = trysend_req(&darg, &req_attrinfo,
2N/A sizeof (picl_reqattrinfo_t), NULL, 0, &outargs,
2N/A sizeof (picl_retattrinfo_t), SEND_REQ_TRYCOUNT);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A /*LINTED*/
2N/A ret = (picl_service_t *)darg.rbuf;
2N/A pinfo->type = ret->ret_attrinfo.type;
2N/A pinfo->accessmode = ret->ret_attrinfo.accessmode;
2N/A pinfo->size = (size_t)ret->ret_attrinfo.size;
2N/A (void) strcpy(pinfo->name, ret->ret_attrinfo.name);
2N/A if (darg.rbuf != (char *)&outargs)
2N/A (void) munmap(darg.rbuf, darg.rsize);
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * This function copies the handle of the first property of a node into
2N/A * <proph>
2N/A */
2N/Aint
2N/Apicl_get_first_prop(picl_nodehdl_t nodeh, picl_prophdl_t *proph)
2N/A{
2N/A door_arg_t darg;
2N/A picl_reqfirstattr_t req_firstattr;
2N/A picl_service_t *ret;
2N/A picl_retfirstattr_t outargs;
2N/A int err;
2N/A
2N/A req_firstattr.cnum = PICL_CNUM_GETFIRSTATTR;
2N/A req_firstattr.nodeh = nodeh;
2N/A
2N/A err = trysend_req(&darg, &req_firstattr,
2N/A sizeof (picl_reqfirstattr_t), NULL, 0, &outargs,
2N/A sizeof (picl_retfirstattr_t), SEND_REQ_TRYCOUNT);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A /*LINTED*/
2N/A ret = (picl_service_t *)darg.rbuf;
2N/A *proph = ret->ret_firstattr.attr;
2N/A if (darg.rbuf != (char *)&outargs)
2N/A (void) munmap(darg.rbuf, darg.rsize);
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * This function copies the handle of the next property in list
2N/A * into <nextprop>.
2N/A */
2N/Aint
2N/Apicl_get_next_prop(picl_prophdl_t proph, picl_prophdl_t *nextprop)
2N/A{
2N/A door_arg_t darg;
2N/A picl_reqnextattr_t req_nextattr;
2N/A picl_service_t *ret;
2N/A picl_retnextattr_t outargs;
2N/A int err;
2N/A
2N/A
2N/A req_nextattr.cnum = PICL_CNUM_GETNEXTATTR;
2N/A req_nextattr.attr = proph;
2N/A
2N/A err = trysend_req(&darg, &req_nextattr,
2N/A sizeof (picl_reqnextattr_t), NULL, 0, &outargs,
2N/A sizeof (picl_retnextattr_t), SEND_REQ_TRYCOUNT);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A /*LINTED*/
2N/A ret = (picl_service_t *)darg.rbuf;
2N/A *nextprop = ret->ret_nextattr.nextattr;
2N/A if (darg.rbuf != (char *)&outargs)
2N/A (void) munmap(darg.rbuf, darg.rsize);
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * This function copies the handle of the property specified by its
2N/A * name into <proph>.
2N/A */
2N/Aint
2N/Apicl_get_prop_by_name(picl_nodehdl_t nodeh, const char *name,
2N/A picl_prophdl_t *proph)
2N/A{
2N/A door_arg_t darg;
2N/A picl_reqattrbyname_t req_attrbyname;
2N/A picl_service_t *ret;
2N/A picl_retattrbyname_t outargs;
2N/A int err;
2N/A
2N/A req_attrbyname.cnum = PICL_CNUM_GETATTRBYNAME;
2N/A req_attrbyname.nodeh = nodeh;
2N/A (void) strcpy(req_attrbyname.propname, name);
2N/A
2N/A err = trysend_req(&darg, &req_attrbyname,
2N/A sizeof (picl_reqattrbyname_t), NULL, 0, &outargs,
2N/A sizeof (picl_retattrbyname_t), SEND_REQ_TRYCOUNT);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A /*LINTED*/
2N/A ret = (picl_service_t *)darg.rbuf;
2N/A *proph = ret->ret_attrbyname.attr;
2N/A if (darg.rbuf != (char *)&outargs)
2N/A (void) munmap(darg.rbuf, darg.rsize);
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * This function copies the handle of the next property on the same
2N/A * row of the table into <rowproph>.
2N/A * When proph is the table handle, the handle of the property that is
2N/A * in first row and first column is copied.
2N/A */
2N/Aint
2N/Apicl_get_next_by_row(picl_prophdl_t proph, picl_prophdl_t *rowproph)
2N/A{
2N/A door_arg_t darg;
2N/A picl_reqattrbyrow_t req_attrbyrow;
2N/A picl_service_t *ret;
2N/A picl_retattrbyrow_t outargs;
2N/A int err;
2N/A
2N/A req_attrbyrow.cnum = PICL_CNUM_GETATTRBYROW;
2N/A req_attrbyrow.attr = proph;
2N/A
2N/A err = trysend_req(&darg, &req_attrbyrow,
2N/A sizeof (picl_reqattrbyrow_t), NULL, 0, &outargs,
2N/A sizeof (picl_retattrbyrow_t), SEND_REQ_TRYCOUNT);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A /*LINTED*/
2N/A ret = (picl_service_t *)darg.rbuf;
2N/A *rowproph = ret->ret_attrbyrow.rowattr;
2N/A if (darg.rbuf != (char *)&outargs)
2N/A (void) munmap(darg.rbuf, darg.rsize);
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * This function copies the handle of the next property on the same
2N/A * column of the table into <colproph>.
2N/A * When proph is the table handle, the handle of the property that is
2N/A * in the first row and first column is copied.
2N/A */
2N/Aint
2N/Apicl_get_next_by_col(picl_prophdl_t proph, picl_prophdl_t *colproph)
2N/A{
2N/A door_arg_t darg;
2N/A picl_reqattrbycol_t req_attrbycol;
2N/A picl_service_t *ret;
2N/A picl_retattrbycol_t outargs;
2N/A int err;
2N/A
2N/A req_attrbycol.cnum = PICL_CNUM_GETATTRBYCOL;
2N/A req_attrbycol.attr = proph;
2N/A
2N/A err = trysend_req(&darg, (char *)&req_attrbycol,
2N/A sizeof (picl_reqattrbycol_t), NULL, 0, (char *)&outargs,
2N/A sizeof (picl_retattrbycol_t), SEND_REQ_TRYCOUNT);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A /*LINTED*/
2N/A ret = (picl_service_t *)darg.rbuf;
2N/A *colproph = ret->ret_attrbycol.colattr;
2N/A if (darg.rbuf != (char *)&outargs)
2N/A (void) munmap(darg.rbuf, darg.rsize);
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * This function returns the picl error messages corresponding to the
2N/A * error number.
2N/A */
2N/Achar *
2N/Apicl_strerror(int err)
2N/A{
2N/A if ((err < N_ERRORS) && (err >= 0)) {
2N/A return (gettext(picl_errmsg[err]));
2N/A }
2N/A return ((char *)NULL);
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 = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh,
2N/A sizeof (chdh));
2N/A while (err == PICL_SUCCESS) {
2N/A err = picl_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 = picl_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 walks the tree by class and invokes the callback
2N/A * function on class name matches.
2N/A */
2N/Aint
2N/Apicl_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/A/*
2N/A * This function gets propinfo and prop handle of the named property
2N/A */
2N/Aint
2N/Apicl_get_propinfo_by_name(picl_nodehdl_t nodeh, const char *prop_name,
2N/A picl_propinfo_t *pinfo, picl_prophdl_t *proph)
2N/A{
2N/A int err;
2N/A picl_prophdl_t tmpproph;
2N/A picl_propinfo_t tmppinfo;
2N/A
2N/A err = picl_get_prop_by_name(nodeh, prop_name, &tmpproph);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A err = picl_get_propinfo(tmpproph, &tmppinfo);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A *proph = tmpproph;
2N/A *pinfo = tmppinfo;
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/Aint
2N/Apicl_get_node_by_path(const char *piclpath, picl_nodehdl_t *nodeh)
2N/A{
2N/A door_arg_t darg;
2N/A picl_reqnodebypath_t req;
2N/A picl_retnodebypath_t out;
2N/A picl_service_t *ret;
2N/A int err;
2N/A
2N/A req.cnum = PICL_CNUM_NODEBYPATH;
2N/A req.psize = PATH_MAX;
2N/A if (strlen(piclpath) >= PATH_MAX)
2N/A return (PICL_VALUETOOBIG);
2N/A (void) strncpy(req.pathbuf, piclpath, PATH_MAX);
2N/A
2N/A err = trysend_req(&darg, &req, sizeof (req), NULL, 0, &out,
2N/A sizeof (out), SEND_REQ_TRYCOUNT);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A /*LINTED*/
2N/A ret = (picl_service_t *)darg.rbuf;
2N/A *nodeh = ret->ret_nodebypath.nodeh;
2N/A if (darg.rbuf != (char *)&out)
2N/A (void) munmap(darg.rbuf, darg.rsize);
2N/A return (err);
2N/A}
2N/A
2N/Aint
2N/Apicl_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 door_arg_t darg;
2N/A picl_reqfindnode_t *req;
2N/A picl_service_t *ret;
2N/A picl_retfindnode_t out;
2N/A int err;
2N/A
2N/A req = alloca(sizeof (picl_reqfindnode_t) + valsize);
2N/A req->cnum = PICL_CNUM_FINDNODE;
2N/A req->nodeh = rooth;
2N/A if (strlen(pname) >= PICL_PROPNAMELEN_MAX)
2N/A return (PICL_VALUETOOBIG);
2N/A (void) strncpy(req->propname, pname, PICL_PROPNAMELEN_MAX);
2N/A req->ptype = ptype;
2N/A req->valsize = (uint32_t)valsize;
2N/A if ((size_t)req->valsize != valsize)
2N/A return (PICL_VALUETOOBIG);
2N/A (void) memcpy(req->valbuf, pval, valsize);
2N/A
2N/A err = trysend_req(&darg, req, sizeof (picl_reqfindnode_t) + valsize,
2N/A NULL, 0, &out, sizeof (out), SEND_REQ_TRYCOUNT);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A /*LINTED*/
2N/A ret = (picl_service_t *)darg.rbuf;
2N/A *retnodeh = ret->ret_findnode.rnodeh;
2N/A if (darg.rbuf != (char *)&out)
2N/A (void) munmap(darg.rbuf, darg.rsize);
2N/A return (err);
2N/A}
2N/A
2N/Aint
2N/Apicl_get_frutree_parent(picl_nodehdl_t devh, picl_nodehdl_t *fruh)
2N/A{
2N/A door_arg_t darg;
2N/A picl_reqfruparent_t req;
2N/A picl_retfruparent_t out;
2N/A picl_service_t *ret;
2N/A int err;
2N/A
2N/A req.cnum = PICL_CNUM_FRUTREEPARENT;
2N/A req.devh = devh;
2N/A
2N/A err = trysend_req(&darg, &req, sizeof (req), NULL, 0, &out,
2N/A sizeof (out), SEND_REQ_TRYCOUNT);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A /*LINTED*/
2N/A ret = (picl_service_t *)darg.rbuf;
2N/A *fruh = ret->ret_fruparent.fruh;
2N/A if (darg.rbuf != (char *)&out)
2N/A (void) munmap(darg.rbuf, darg.rsize);
2N/A return (err);
2N/A}