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
post_req(door_arg_t * dargp,void * data_ptr,size_t data_size,door_desc_t * desc_ptr,uint_t desc_num,void * rbuf,size_t rsize)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
handshake(void)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
trysend_req(door_arg_t * dargp,void * data_ptr,size_t data_size,door_desc_t * desc_ptr,uint_t desc_num,void * rbuf,size_t rsize,unsigned int trycount)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
picl_initialize(void)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
picl_shutdown(void)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
picl_wait(unsigned int secs)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
picl_get_root(picl_nodehdl_t * rooth)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
picl_get_propval(picl_prophdl_t proph,void * valbuf,size_t nbytes)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
picl_get_propval_by_name(picl_nodehdl_t nodeh,const char * propname,void * valbuf,size_t nbytes)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
picl_set_propval(picl_prophdl_t proph,void * valbuf,size_t nbytes)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
picl_set_propval_by_name(picl_nodehdl_t nodeh,const char * propname,void * valbuf,size_t nbytes)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
picl_get_propinfo(picl_prophdl_t proph,picl_propinfo_t * pinfo)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
picl_get_first_prop(picl_nodehdl_t nodeh,picl_prophdl_t * proph)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
picl_get_next_prop(picl_prophdl_t proph,picl_prophdl_t * nextprop)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
picl_get_prop_by_name(picl_nodehdl_t nodeh,const char * name,picl_prophdl_t * proph)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
picl_get_next_by_row(picl_prophdl_t proph,picl_prophdl_t * rowproph)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
picl_get_next_by_col(picl_prophdl_t proph,picl_prophdl_t * colproph)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 *
picl_strerror(int err)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
do_walk(picl_nodehdl_t rooth,const char * classname,void * c_args,int (* callback_fn)(picl_nodehdl_t hdl,void * args))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
picl_walk_tree_by_class(picl_nodehdl_t rooth,const char * classname,void * c_args,int (* callback_fn)(picl_nodehdl_t hdl,void * args))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
picl_get_propinfo_by_name(picl_nodehdl_t nodeh,const char * prop_name,picl_propinfo_t * pinfo,picl_prophdl_t * proph)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
picl_get_node_by_path(const char * piclpath,picl_nodehdl_t * nodeh)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
picl_find_node(picl_nodehdl_t rooth,char * pname,picl_prop_type_t ptype,void * pval,size_t valsize,picl_nodehdl_t * retnodeh)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
picl_get_frutree_parent(picl_nodehdl_t devh,picl_nodehdl_t * fruh)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