xref: /illumos-gate/usr/src/lib/libpicl/picl.c (revision 7dbbfe7762f9eabac3999ee1a8b38311d428f7a8)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * This module implements the PICL Interface used by PICL clients
29  * to access services of the PICL daemon
30  *
31  * Locking Strategy
32  * A single reader/writer lock (icl_lock) protects the access to the interface
33  * to the picl daemon, and the reference count, refcnt, variable.
34  * A reader lock is obtained to send a request to the daemon.
35  * A writer lock is obtained to initialize, reinitialize, or shutdown
36  * the interface.
37  */
38 
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <alloca.h>
44 #include <fcntl.h>
45 #include <libintl.h>
46 #include <errno.h>
47 #include <sys/mman.h>
48 #include <door.h>
49 #include <sys/door.h>
50 #include <sys/time.h>
51 #include <assert.h>
52 #include <synch.h>
53 #include <limits.h>
54 #include <picl.h>
55 #include "picl2door.h"
56 
57 /*
58  * Module variables
59  */
60 static	int		door_handle = -1;
61 static	uint32_t	refcnt = 0;
62 static	rwlock_t	picl_lock = DEFAULTRWLOCK;
63 
64 static	char 		*picl_errmsg[] = {
65 	"No error",
66 	"General system failure",
67 	"Daemon not responding",
68 	"Unknown PICL service",
69 	"Session not initialized",
70 	"Invalid arguments",
71 	"Argument too big",
72 	"Property not found",
73 	"Not a table property handle",
74 	"Not a node handle",
75 	"Not a property handle",
76 	"End of property list",
77 	"Property already exists",
78 	"Property not writable",
79 	"Insufficient permissions",
80 	"Invalid handle",
81 	"Stale handle",
82 	"Unsupported version",
83 	"Wait timed out",
84 	"Attempting to destroy before delete",
85 	"PICL Tree is busy",
86 	"Already has a parent",
87 	"Property name is reserved",
88 	"Invalid reference value",
89 	"Continue tree walk",
90 	"Terminate tree walk",
91 	"Node not found",
92 	"Not enough space available",
93 	"Property not readable",
94 	"Property value unavailable"
95 };
96 
97 #define	N_ERRORS 		(sizeof (picl_errmsg)/sizeof (picl_errmsg[0]))
98 #define	SEND_REQ_TRYCOUNT	1
99 
100 /*
101  * This function sends the client request to the daemon using a door call.
102  * If door_handle is -1, it returns PICL_NOTINITIALIZED.
103  * If the door_call fails, it returns PICL_NORESPONSE. Otherwise, it
104  * checks the response from the daemon for error. If an error is returned
105  * this function returns the error code returned and unmaps any
106  * memory mapped by the door call. For successful results, the caller is
107  * responsible to unmap the mapped memory after retrieving the results.
108  *
109  * This function does not attempt to reinitialize the interface if the
110  * initial door_call fails. It is called from handshake() , shutdown()
111  * and trysend_req() routines.
112  */
113 static int
114 post_req(door_arg_t *dargp, void *data_ptr, size_t data_size,
115     door_desc_t *desc_ptr, uint_t desc_num, void *rbuf, size_t rsize)
116 {
117 	int		err;
118 	picl_service_t	*ret;
119 	int		req_cnum;
120 
121 	req_cnum = ((picl_service_t *)data_ptr)->in.cnum;
122 	dargp->data_ptr = data_ptr;
123 	dargp->data_size = data_size;
124 	dargp->desc_ptr = desc_ptr;
125 	dargp->desc_num = desc_num;
126 	dargp->rbuf = rbuf;
127 	dargp->rsize = rsize;
128 
129 	if (door_call(door_handle, dargp) < 0)
130 		return (PICL_NORESPONSE);
131 
132 	/*LINTED*/
133 	ret = (picl_service_t *)dargp->rbuf;
134 	if (ret->in.cnum == req_cnum)
135 		return (PICL_SUCCESS);
136 	else if ((ret->in.cnum == PICL_CNUM_ERROR) &&
137 	    (ret->ret_error.in_cnum == req_cnum))
138 		err = ret->ret_error.errnum;
139 	else
140 	    err = PICL_UNKNOWNSERVICE;
141 	if (dargp->rbuf != rbuf)
142 		(void) munmap(dargp->rbuf, dargp->rsize);
143 	return (err);
144 }
145 
146 /*
147  * This function posts an INIT message to the daemon to
148  * verify communication channel.
149  */
150 static int
151 handshake(void)
152 {
153 	int		err;
154 	door_arg_t	darg;
155 	picl_reqinit_t	req;
156 	picl_retinit_t	outargs;
157 
158 	req.cnum = PICL_CNUM_INIT;
159 	req.clrev = PICL_VERSION_1;
160 
161 	if ((err = post_req(&darg, &req, sizeof (picl_reqinit_t), NULL,
162 	    0, &outargs, sizeof (picl_retinit_t))) != PICL_SUCCESS)
163 		return (err);
164 
165 	if (darg.rbuf != (char *)&outargs)
166 		(void) munmap(darg.rbuf, darg.rsize);
167 	return (PICL_SUCCESS);
168 }
169 
170 /*
171  * This function calls post_req() to make door_call and reinitializes
172  * the interface is post_req() fails.
173  */
174 static int
175 trysend_req(door_arg_t *dargp, void *data_ptr, size_t data_size,
176     door_desc_t *desc_ptr, uint_t desc_num, void *rbuf, size_t rsize,
177 	unsigned int trycount)
178 {
179 	int	err;
180 	int	write_locked;
181 
182 	write_locked = 0;
183 	(void) rw_rdlock(&picl_lock);
184 	if (refcnt == 0) {
185 		(void) rw_unlock(&picl_lock);	/* read unlock */
186 		return (PICL_NOTINITIALIZED);
187 	}
188 
189 	while ((err = post_req(dargp, data_ptr, data_size, desc_ptr, desc_num,
190 	    rbuf, rsize)) == PICL_NORESPONSE) {
191 		if (trycount == 0)	/* no more retry */
192 			break;
193 
194 		if (write_locked == 1) {	/* close and open door */
195 			(void) close(door_handle);
196 			if ((door_handle = open(PICLD_DOOR, O_RDONLY)) < 0) {
197 				err = PICL_NORESPONSE;
198 				break;
199 			}
200 			--trycount;
201 			continue;
202 		}
203 		/*
204 		 * Upgrade read to a write lock
205 		 */
206 		(void) rw_unlock(&picl_lock);
207 		(void) rw_wrlock(&picl_lock);
208 
209 		/*
210 		 * if picl_shutdown happens during lock upgrade
211 		 */
212 		if (refcnt == 0) {
213 			err =  PICL_NOTINITIALIZED;
214 			break;
215 		}
216 		write_locked = 1;
217 		continue;
218 	}
219 	(void) rw_unlock(&picl_lock);	/* read or write unlock */
220 	return (err);
221 }
222 
223 /*
224  * Initialize the PICL interface
225  * Increment the reference count.
226  */
227 int
228 picl_initialize(void)
229 {
230 	int	err;
231 
232 	(void) rw_wrlock(&picl_lock);
233 	if (refcnt > 0) {		/* previously initialized */
234 		err = handshake();
235 		if (err == PICL_SUCCESS) {
236 			++refcnt;
237 			(void) rw_unlock(&picl_lock);	/* write unlock */
238 			return (err);
239 		}
240 		if (err != PICL_NORESPONSE) {
241 			(void) rw_unlock(&picl_lock);	/* write unlock */
242 			return (err);
243 		}
244 		(void) close(door_handle);	/* close bad door */
245 	}
246 
247 	/*
248 	 * Open picld door and initialize door_handle
249 	 */
250 	if ((door_handle = open(PICLD_DOOR, O_RDONLY)) < 0) {
251 		(void) rw_unlock(&picl_lock); /* write unlock */
252 		return (PICL_NORESPONSE);
253 	}
254 
255 	err = handshake();
256 	if (err != PICL_SUCCESS)
257 		(void) close(door_handle);
258 	else
259 		++refcnt;
260 	(void) rw_unlock(&picl_lock);	/* write unlock */
261 	return (err);
262 }
263 
264 /*
265  * Shutdown the PICL interface
266  * Decrement the reference count and close the door_handle if refcnt is zero
267  */
268 int
269 picl_shutdown(void)
270 {
271 	int		err;
272 	door_arg_t	darg;
273 	picl_reqfini_t	req_fini;
274 	picl_retfini_t	outargs;
275 
276 	(void) rw_wrlock(&picl_lock);	/* write lock */
277 	if (refcnt == 0) {
278 		(void) rw_unlock(&picl_lock);	/* write unlock */
279 		return (PICL_NOTINITIALIZED);
280 	}
281 	req_fini.cnum = PICL_CNUM_FINI;
282 	err = post_req(&darg, &req_fini, sizeof (picl_reqfini_t),
283 	    NULL, 0, &outargs, sizeof (picl_retfini_t));
284 	--refcnt;
285 	if (refcnt == 0)
286 		(void) close(door_handle);
287 	(void) rw_unlock(&picl_lock);	/* write unlock */
288 	if (err != PICL_SUCCESS)
289 		return (err);
290 	if (darg.rbuf != (char *)&outargs)
291 		(void) munmap(darg.rbuf, darg.rsize);
292 	return (PICL_SUCCESS);
293 }
294 
295 /*
296  * This function waits for the specified number of seconds for a PICL
297  * tree refresh.
298  */
299 int
300 picl_wait(unsigned int secs)
301 {
302 	door_arg_t	darg;
303 	picl_reqwait_t	req_wait;
304 	picl_retwait_t	outargs;
305 	picl_service_t	*ret;
306 	int		err;
307 
308 	req_wait.cnum = PICL_CNUM_WAIT;
309 	req_wait.secs = secs;
310 	err = trysend_req(&darg, &req_wait, sizeof (picl_reqwait_t),
311 	    NULL, 0, &outargs, sizeof (picl_retwait_t), SEND_REQ_TRYCOUNT);
312 	if (err != PICL_SUCCESS)
313 		return (err);
314 
315 	/*LINTED*/
316 	ret = (picl_service_t *)darg.rbuf;
317 	err = ret->ret_wait.retcode;
318 	if (darg.rbuf != (char *)&outargs)
319 		(void) munmap(darg.rbuf, darg.rsize);
320 	return (err);
321 }
322 
323 /*
324  * This function copies the handle of the root node of the PICL tree into
325  * the buffer <rooth>
326  */
327 int
328 picl_get_root(picl_nodehdl_t *rooth)
329 {
330 	door_arg_t	darg;
331 	picl_reqroot_t	req_root;
332 	picl_retroot_t	outargs;
333 	picl_service_t	*ret;
334 	int	err;
335 
336 	req_root.cnum = PICL_CNUM_GETROOT;
337 	err = trysend_req(&darg, &req_root, sizeof (picl_reqroot_t), NULL,
338 	    0, &outargs, sizeof (picl_retroot_t), SEND_REQ_TRYCOUNT);
339 	if (err != PICL_SUCCESS)
340 		return (err);
341 	/*LINTED*/
342 	ret = (picl_service_t *)darg.rbuf;
343 	*rooth = ret->ret_root.rnode;
344 	if (darg.rbuf != (char *)&outargs)
345 		(void) munmap(darg.rbuf, darg.rsize);
346 	return (PICL_SUCCESS);
347 }
348 
349 /*
350  * This function copies the value of the property specified by its handle
351  * into the buffer <valbuf>.
352  */
353 int
354 picl_get_propval(picl_prophdl_t proph, void *valbuf, size_t nbytes)
355 {
356 	door_arg_t		darg;
357 	picl_reqattrval_t	req_attrval;
358 	picl_service_t		*ret;
359 	picl_retattrval_t	*outargs;
360 	int			err;
361 
362 	req_attrval.cnum = PICL_CNUM_GETATTRVAL;
363 	req_attrval.attr = proph;
364 	req_attrval.bufsize = (uint32_t)nbytes;
365 	if ((size_t)req_attrval.bufsize != nbytes)
366 		return (PICL_VALUETOOBIG);
367 	outargs = alloca(sizeof (picl_retattrval_t) + nbytes);
368 
369 	err = trysend_req(&darg, &req_attrval, sizeof (picl_reqattrval_t),
370 	    NULL, 0, outargs, sizeof (picl_retattrval_t) + nbytes,
371 	    SEND_REQ_TRYCOUNT);
372 	if (err != PICL_SUCCESS)
373 		return (err);
374 
375 	/*LINTED*/
376 	ret = (picl_service_t *)darg.rbuf;
377 	if (ret->ret_attrval.nbytes > (uint32_t)nbytes)
378 		err = PICL_VALUETOOBIG;
379 	else
380 		(void) memcpy(valbuf, ret->ret_attrval.ret_buf,
381 		    (size_t)ret->ret_attrval.nbytes);
382 	if (darg.rbuf != (char *)outargs)
383 		(void) munmap(darg.rbuf, darg.rsize);
384 	return (err);
385 }
386 
387 /*
388  * This function copies the value of the property specified by its
389  * name into the buffer <valbuf>
390  */
391 int
392 picl_get_propval_by_name(picl_nodehdl_t nodeh, const char *propname,
393     void *valbuf, size_t nbytes)
394 {
395 	door_arg_t		darg;
396 	picl_reqattrvalbyname_t	req_attrvalbyname;
397 	picl_service_t		*ret;
398 	picl_retattrvalbyname_t	*outargs;
399 	int			err;
400 
401 	req_attrvalbyname.cnum = PICL_CNUM_GETATTRVALBYNAME;
402 	req_attrvalbyname.nodeh = nodeh;
403 	(void) strcpy(req_attrvalbyname.propname, propname);
404 	req_attrvalbyname.bufsize = (uint32_t)nbytes;
405 	if ((size_t)req_attrvalbyname.bufsize != nbytes)
406 		return (PICL_VALUETOOBIG);
407 	outargs = alloca(sizeof (picl_retattrvalbyname_t) + nbytes);
408 
409 	err = trysend_req(&darg, &req_attrvalbyname,
410 	    sizeof (picl_reqattrvalbyname_t), NULL, 0, outargs,
411 	    sizeof (picl_retattrvalbyname_t) + nbytes, SEND_REQ_TRYCOUNT);
412 	if (err != PICL_SUCCESS)
413 		return (err);
414 
415 	/*LINTED*/
416 	ret = (picl_service_t *)darg.rbuf;
417 	if (ret->ret_attrvalbyname.nbytes > (uint32_t)nbytes)
418 		err = PICL_VALUETOOBIG;
419 	else
420 		(void) memcpy(valbuf, ret->ret_attrvalbyname.ret_buf,
421 		    (size_t)ret->ret_attrvalbyname.nbytes);
422 	if (darg.rbuf != (char *)outargs)
423 		(void) munmap(darg.rbuf, darg.rsize);
424 	return (err);
425 }
426 
427 /*
428  * This function sets the value of the property specified by its
429  * handle with the value specified in <valbuf>.
430  */
431 int
432 picl_set_propval(picl_prophdl_t proph, void *valbuf, size_t nbytes)
433 {
434 	door_arg_t		darg;
435 	picl_reqsetattrval_t	ret_setattrval;
436 	picl_reqsetattrval_t	*inargs;
437 	int			err;
438 
439 	if (nbytes >= (size_t)PICL_PROPSIZE_MAX)
440 		return (PICL_VALUETOOBIG);
441 
442 	inargs = alloca(sizeof (picl_reqsetattrval_t) + nbytes);
443 	inargs->cnum = PICL_CNUM_SETATTRVAL;
444 	inargs->attr = proph;
445 	inargs->bufsize = (uint32_t)nbytes;
446 	if ((size_t)inargs->bufsize != nbytes)
447 		return (PICL_VALUETOOBIG);
448 	(void) memcpy(inargs->valbuf, valbuf, nbytes);
449 
450 	err = trysend_req(&darg, inargs, sizeof (picl_reqsetattrval_t) +
451 	    nbytes, NULL, 0, &ret_setattrval,
452 	    sizeof (picl_retsetattrval_t), SEND_REQ_TRYCOUNT);
453 	if (err != PICL_SUCCESS)
454 		return (err);
455 
456 	if (darg.rbuf != (char *)&ret_setattrval)
457 		(void) munmap(darg.rbuf, darg.rsize);
458 	return (PICL_SUCCESS);
459 }
460 
461 /*
462  * This function sets the value of the property specified by its
463  * name with the value given in <valbuf>
464  */
465 int
466 picl_set_propval_by_name(picl_nodehdl_t nodeh, const char *propname,
467     void *valbuf, size_t nbytes)
468 {
469 	door_arg_t			darg;
470 	picl_retsetattrvalbyname_t	ret_setattrvalbyname;
471 	picl_reqsetattrvalbyname_t	*inargs;
472 	int				err;
473 
474 	if (nbytes >= (size_t)PICL_PROPSIZE_MAX)
475 		return (PICL_VALUETOOBIG);
476 
477 	inargs = alloca(sizeof (picl_reqsetattrvalbyname_t) + nbytes);
478 	inargs->cnum = PICL_CNUM_SETATTRVALBYNAME;
479 	inargs->nodeh = nodeh;
480 	(void) strcpy(inargs->propname, propname);
481 	inargs->bufsize = (uint32_t)nbytes;
482 	if ((size_t)inargs->bufsize != nbytes)
483 		return (PICL_VALUETOOBIG);
484 	(void) memcpy(inargs->valbuf, valbuf, nbytes);
485 
486 	err = trysend_req(&darg, inargs,
487 	    sizeof (picl_reqsetattrvalbyname_t) + nbytes, NULL, 0,
488 	    &ret_setattrvalbyname, sizeof (picl_retsetattrvalbyname_t),
489 	    SEND_REQ_TRYCOUNT);
490 	if (err != PICL_SUCCESS)
491 		return (err);
492 
493 	if (darg.rbuf != (char *)&ret_setattrvalbyname)
494 		(void) munmap(darg.rbuf, darg.rsize);
495 	return (PICL_SUCCESS);
496 }
497 
498 /*
499  * This function copies the information of the specified property
500  * into <pinfo>
501  */
502 int
503 picl_get_propinfo(picl_prophdl_t proph, picl_propinfo_t *pinfo)
504 {
505 	door_arg_t		darg;
506 	picl_reqattrinfo_t	req_attrinfo;
507 	picl_service_t		*ret;
508 	picl_retattrinfo_t	outargs;
509 	int			err;
510 
511 	req_attrinfo.cnum = PICL_CNUM_GETATTRINFO;
512 	req_attrinfo.attr = proph;
513 
514 	err = trysend_req(&darg, &req_attrinfo,
515 	    sizeof (picl_reqattrinfo_t), NULL, 0, &outargs,
516 	    sizeof (picl_retattrinfo_t), SEND_REQ_TRYCOUNT);
517 	if (err != PICL_SUCCESS)
518 		return (err);
519 
520 	/*LINTED*/
521 	ret = (picl_service_t *)darg.rbuf;
522 	pinfo->type = ret->ret_attrinfo.type;
523 	pinfo->accessmode = ret->ret_attrinfo.accessmode;
524 	pinfo->size = (size_t)ret->ret_attrinfo.size;
525 	(void) strcpy(pinfo->name, ret->ret_attrinfo.name);
526 	if (darg.rbuf != (char *)&outargs)
527 		(void) munmap(darg.rbuf, darg.rsize);
528 	return (PICL_SUCCESS);
529 }
530 
531 /*
532  * This function copies the handle of the first property of a node into
533  * <proph>
534  */
535 int
536 picl_get_first_prop(picl_nodehdl_t nodeh, picl_prophdl_t *proph)
537 {
538 	door_arg_t		darg;
539 	picl_reqfirstattr_t	req_firstattr;
540 	picl_service_t		*ret;
541 	picl_retfirstattr_t	outargs;
542 	int			err;
543 
544 	req_firstattr.cnum = PICL_CNUM_GETFIRSTATTR;
545 	req_firstattr.nodeh = nodeh;
546 
547 	err = trysend_req(&darg, &req_firstattr,
548 	    sizeof (picl_reqfirstattr_t), NULL, 0, &outargs,
549 	    sizeof (picl_retfirstattr_t), SEND_REQ_TRYCOUNT);
550 	if (err != PICL_SUCCESS)
551 		return (err);
552 
553 	/*LINTED*/
554 	ret = (picl_service_t *)darg.rbuf;
555 	*proph = ret->ret_firstattr.attr;
556 	if (darg.rbuf != (char *)&outargs)
557 		(void) munmap(darg.rbuf, darg.rsize);
558 	return (PICL_SUCCESS);
559 }
560 
561 /*
562  * This function copies the handle of the next property in list
563  * into <nextprop>.
564  */
565 int
566 picl_get_next_prop(picl_prophdl_t proph, picl_prophdl_t *nextprop)
567 {
568 	door_arg_t		darg;
569 	picl_reqnextattr_t	req_nextattr;
570 	picl_service_t		*ret;
571 	picl_retnextattr_t	outargs;
572 	int			err;
573 
574 
575 	req_nextattr.cnum = PICL_CNUM_GETNEXTATTR;
576 	req_nextattr.attr = proph;
577 
578 	err = trysend_req(&darg, &req_nextattr,
579 	    sizeof (picl_reqnextattr_t), NULL, 0,  &outargs,
580 	    sizeof (picl_retnextattr_t), SEND_REQ_TRYCOUNT);
581 	if (err != PICL_SUCCESS)
582 		return (err);
583 
584 	/*LINTED*/
585 	ret = (picl_service_t *)darg.rbuf;
586 	*nextprop = ret->ret_nextattr.nextattr;
587 	if (darg.rbuf != (char *)&outargs)
588 		(void) munmap(darg.rbuf, darg.rsize);
589 	return (PICL_SUCCESS);
590 }
591 
592 /*
593  * This function copies the handle of the property specified by its
594  * name into <proph>.
595  */
596 int
597 picl_get_prop_by_name(picl_nodehdl_t nodeh, const char *name,
598     picl_prophdl_t *proph)
599 {
600 	door_arg_t		darg;
601 	picl_reqattrbyname_t	req_attrbyname;
602 	picl_service_t		*ret;
603 	picl_retattrbyname_t	outargs;
604 	int			err;
605 
606 	req_attrbyname.cnum = PICL_CNUM_GETATTRBYNAME;
607 	req_attrbyname.nodeh = nodeh;
608 	(void) strcpy(req_attrbyname.propname, name);
609 
610 	err = trysend_req(&darg, &req_attrbyname,
611 	    sizeof (picl_reqattrbyname_t), NULL, 0, &outargs,
612 	    sizeof (picl_retattrbyname_t), SEND_REQ_TRYCOUNT);
613 	if (err != PICL_SUCCESS)
614 		return (err);
615 
616 	/*LINTED*/
617 	ret = (picl_service_t *)darg.rbuf;
618 	*proph = ret->ret_attrbyname.attr;
619 	if (darg.rbuf != (char *)&outargs)
620 		(void) munmap(darg.rbuf, darg.rsize);
621 	return (PICL_SUCCESS);
622 }
623 
624 /*
625  * This function copies the handle of the next property on the same
626  * row of the table into <rowproph>.
627  * When proph is the table handle, the handle of the property that is
628  * in first row and first column is copied.
629  */
630 int
631 picl_get_next_by_row(picl_prophdl_t proph, picl_prophdl_t *rowproph)
632 {
633 	door_arg_t		darg;
634 	picl_reqattrbyrow_t	req_attrbyrow;
635 	picl_service_t		*ret;
636 	picl_retattrbyrow_t	outargs;
637 	int			err;
638 
639 	req_attrbyrow.cnum = PICL_CNUM_GETATTRBYROW;
640 	req_attrbyrow.attr = proph;
641 
642 	err = trysend_req(&darg, &req_attrbyrow,
643 	    sizeof (picl_reqattrbyrow_t), NULL, 0, &outargs,
644 	    sizeof (picl_retattrbyrow_t), SEND_REQ_TRYCOUNT);
645 	if (err != PICL_SUCCESS)
646 		return (err);
647 
648 	/*LINTED*/
649 	ret = (picl_service_t *)darg.rbuf;
650 	*rowproph = ret->ret_attrbyrow.rowattr;
651 	if (darg.rbuf != (char *)&outargs)
652 		(void) munmap(darg.rbuf, darg.rsize);
653 	return (PICL_SUCCESS);
654 }
655 
656 /*
657  * This function copies the handle of the next property on the same
658  * column of the table into <colproph>.
659  * When proph is the table handle, the handle of the property that is
660  * in the first row and first column is copied.
661  */
662 int
663 picl_get_next_by_col(picl_prophdl_t proph, picl_prophdl_t *colproph)
664 {
665 	door_arg_t		darg;
666 	picl_reqattrbycol_t	req_attrbycol;
667 	picl_service_t		*ret;
668 	picl_retattrbycol_t	outargs;
669 	int			err;
670 
671 	req_attrbycol.cnum = PICL_CNUM_GETATTRBYCOL;
672 	req_attrbycol.attr = proph;
673 
674 	err = trysend_req(&darg, (char *)&req_attrbycol,
675 	    sizeof (picl_reqattrbycol_t), NULL, 0, (char *)&outargs,
676 	    sizeof (picl_retattrbycol_t), SEND_REQ_TRYCOUNT);
677 	if (err != PICL_SUCCESS)
678 		return (err);
679 
680 	/*LINTED*/
681 	ret = (picl_service_t *)darg.rbuf;
682 	*colproph = ret->ret_attrbycol.colattr;
683 	if (darg.rbuf != (char *)&outargs)
684 		(void) munmap(darg.rbuf, darg.rsize);
685 	return (PICL_SUCCESS);
686 }
687 
688 /*
689  * This function returns the picl error messages corresponding to the
690  * error number.
691  */
692 char *
693 picl_strerror(int err)
694 {
695 	if ((err < N_ERRORS) && (err >= 0)) {
696 		return (gettext(picl_errmsg[err]));
697 	}
698 	return ((char *)NULL);
699 }
700 
701 /*
702  * recursively visit all nodes
703  */
704 static int
705 do_walk(picl_nodehdl_t rooth, const char *classname,
706     void *c_args, int (*callback_fn)(picl_nodehdl_t hdl, void *args))
707 {
708 	int		err;
709 	picl_nodehdl_t	chdh;
710 	char		classval[PICL_CLASSNAMELEN_MAX];
711 
712 	err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh,
713 	    sizeof (chdh));
714 	while (err == PICL_SUCCESS) {
715 		err = picl_get_propval_by_name(chdh, PICL_PROP_CLASSNAME,
716 		    classval, sizeof (classval));
717 		if (err != PICL_SUCCESS)
718 			return (err);
719 
720 		if ((classname == NULL) || (strcmp(classname, classval) == 0)) {
721 			err = callback_fn(chdh, c_args);
722 			if (err != PICL_WALK_CONTINUE)
723 				return (err);
724 		}
725 
726 		if ((err = do_walk(chdh, classname, c_args, callback_fn)) !=
727 		    PICL_WALK_CONTINUE)
728 			return (err);
729 
730 		err = picl_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
731 		    sizeof (chdh));
732 	}
733 	if (err == PICL_PROPNOTFOUND)	/* end of a branch */
734 		return (PICL_WALK_CONTINUE);
735 	return (err);
736 
737 }
738 
739 /*
740  * This function walks the tree by class and invokes the callback
741  * function on class name matches.
742  */
743 int
744 picl_walk_tree_by_class(picl_nodehdl_t rooth, const char *classname,
745     void *c_args, int (*callback_fn)(picl_nodehdl_t hdl, void *args))
746 {
747 	int		err;
748 
749 	if (callback_fn == NULL)
750 		return (PICL_INVALIDARG);
751 	err = do_walk(rooth, classname, c_args, callback_fn);
752 	if ((err == PICL_WALK_CONTINUE) || (err == PICL_WALK_TERMINATE))
753 		return (PICL_SUCCESS);
754 	return (err);
755 }
756 
757 /*
758  * This function gets propinfo and prop handle of the named property
759  */
760 int
761 picl_get_propinfo_by_name(picl_nodehdl_t nodeh, const char *prop_name,
762     picl_propinfo_t *pinfo, picl_prophdl_t *proph)
763 {
764 	int		err;
765 	picl_prophdl_t	tmpproph;
766 	picl_propinfo_t	tmppinfo;
767 
768 	err = picl_get_prop_by_name(nodeh, prop_name, &tmpproph);
769 	if (err != PICL_SUCCESS)
770 		return (err);
771 
772 	err = picl_get_propinfo(tmpproph, &tmppinfo);
773 	if (err != PICL_SUCCESS)
774 		return (err);
775 
776 	*proph = tmpproph;
777 	*pinfo = tmppinfo;
778 	return (PICL_SUCCESS);
779 }
780 
781 int
782 picl_get_node_by_path(const char *piclpath, picl_nodehdl_t *nodeh)
783 {
784 	door_arg_t		darg;
785 	picl_reqnodebypath_t	req;
786 	picl_retnodebypath_t	out;
787 	picl_service_t		*ret;
788 	int	err;
789 
790 	req.cnum = PICL_CNUM_NODEBYPATH;
791 	req.psize = PATH_MAX;
792 	if (strlen(piclpath) >= PATH_MAX)
793 		return (PICL_VALUETOOBIG);
794 	(void) strncpy(req.pathbuf, piclpath, PATH_MAX);
795 
796 	err = trysend_req(&darg, &req, sizeof (req), NULL, 0, &out,
797 	    sizeof (out), SEND_REQ_TRYCOUNT);
798 	if (err != PICL_SUCCESS)
799 		return (err);
800 
801 	/*LINTED*/
802 	ret = (picl_service_t *)darg.rbuf;
803 	*nodeh = ret->ret_nodebypath.nodeh;
804 	if (darg.rbuf != (char *)&out)
805 		(void) munmap(darg.rbuf, darg.rsize);
806 	return (err);
807 }
808 
809 int
810 picl_find_node(picl_nodehdl_t rooth, char *pname, picl_prop_type_t ptype,
811     void *pval, size_t valsize, picl_nodehdl_t *retnodeh)
812 {
813 	door_arg_t		darg;
814 	picl_reqfindnode_t	*req;
815 	picl_service_t		*ret;
816 	picl_retfindnode_t	out;
817 	int			err;
818 
819 	req = alloca(sizeof (picl_reqfindnode_t) + valsize);
820 	req->cnum = PICL_CNUM_FINDNODE;
821 	req->nodeh = rooth;
822 	if (strlen(pname) >= PICL_PROPNAMELEN_MAX)
823 		return (PICL_VALUETOOBIG);
824 	(void) strncpy(req->propname, pname, PICL_PROPNAMELEN_MAX);
825 	req->ptype = ptype;
826 	req->valsize = (uint32_t)valsize;
827 	if ((size_t)req->valsize != valsize)
828 		return (PICL_VALUETOOBIG);
829 	(void) memcpy(req->valbuf, pval, valsize);
830 
831 	err = trysend_req(&darg, req, sizeof (picl_reqfindnode_t) + valsize,
832 	    NULL, 0, &out, sizeof (out), SEND_REQ_TRYCOUNT);
833 	if (err != PICL_SUCCESS)
834 		return (err);
835 
836 	/*LINTED*/
837 	ret = (picl_service_t *)darg.rbuf;
838 	*retnodeh = ret->ret_findnode.rnodeh;
839 	if (darg.rbuf != (char *)&out)
840 		(void) munmap(darg.rbuf, darg.rsize);
841 	return (err);
842 }
843 
844 int
845 picl_get_frutree_parent(picl_nodehdl_t devh, picl_nodehdl_t *fruh)
846 {
847 	door_arg_t		darg;
848 	picl_reqfruparent_t	req;
849 	picl_retfruparent_t	out;
850 	picl_service_t		*ret;
851 	int			err;
852 
853 	req.cnum = PICL_CNUM_FRUTREEPARENT;
854 	req.devh = devh;
855 
856 	err = trysend_req(&darg, &req, sizeof (req), NULL, 0, &out,
857 	    sizeof (out), SEND_REQ_TRYCOUNT);
858 	if (err != PICL_SUCCESS)
859 		return (err);
860 
861 	/*LINTED*/
862 	ret = (picl_service_t *)darg.rbuf;
863 	*fruh = ret->ret_fruparent.fruh;
864 	if (darg.rbuf != (char *)&out)
865 		(void) munmap(darg.rbuf, darg.rsize);
866 	return (err);
867 }
868