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