4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
50 #include <sys/utsname.h>
51 #include <sys/systeminfo.h>
59 #include "picl2door.h"
61 #include "ptree_impl.h"
66 #define MUST_BE_ROOT gettext("this program must be run as root\n")
67 #define CD_ROOT_FAILED gettext("chdir to root failed\n")
68 #define INIT_FAILED gettext("ptree initialization failed\n")
69 #define DAEMON_RUNNING gettext("PICL daemon already running\n")
70 #define DOOR_FAILED gettext("Failed creating picld door\n")
71 #define SIGACT_FAILED \
72 gettext("Failed to install signal handler for %s: %s\n")
78 #define DOS_PICL_REQUESTS_LIMIT 10000
79 #define SLIDING_INTERVAL_MILLISECONDS 1000
80 #define PICLD_MAJOR_REV 0x1
81 #define PICLD_MINOR_REV 0x0
82 #define DOS_SLEEPTIME_MS 1000
83 #define MAX_POOL_SIZE _POSIX_THREAD_THREADS_MAX
84 #define MAX_CONCURRENT_WAITS (_POSIX_THREAD_THREADS_MAX - 2)
85 #define MAX_USER_WAITS 4
90 #define PICLD_VERSION(x, y) ((x << 8) | y)
91 #define PICL_CLIENT_REV(x) (x & 0xff)
92 #define MILLI_TO_NANO(x) (x * 1000000)
94 extern char **environ
;
99 static int logflag
= 1;
100 static int doreinit
= 0;
101 static int door_id
= -1;
102 static pthread_mutex_t door_mutex
= PTHREAD_MUTEX_INITIALIZER
;
103 static pthread_cond_t door_cv
= PTHREAD_COND_INITIALIZER
;
104 static int service_requests
= 0;
105 static hrtime_t orig_time
;
106 static hrtime_t sliding_interval_ms
;
107 static uint32_t dos_req_limit
;
108 static uint32_t dos_ms
;
109 static pthread_mutex_t dos_mutex
= PTHREAD_MUTEX_INITIALIZER
;
110 static rwlock_t init_lk
;
111 static int pool_count
= 0;
112 static pthread_mutex_t pool_mutex
= PTHREAD_MUTEX_INITIALIZER
;
113 static pthread_mutex_t wait_req_mutex
= PTHREAD_MUTEX_INITIALIZER
;
114 static int wait_count
= 0;
118 } user_count
[MAX_CONCURRENT_WAITS
];
121 * This returns an error message to libpicl
124 picld_return_error(picl_callnumber_t cnum
, picl_errno_t err
)
126 picl_reterror_t ret_error
;
128 ret_error
.cnum
= PICL_CNUM_ERROR
;
129 ret_error
.in_cnum
= cnum
;
130 ret_error
.errnum
= err
;
131 (void) rw_unlock(&init_lk
);
132 (void) door_return((char *)&ret_error
, sizeof (picl_reterror_t
), NULL
,
137 * picld_init is called when a picl_initialize request is received
140 picld_init(picl_service_t
*req
)
142 picl_retinit_t ret_init
;
145 clmajrev
= PICL_CLIENT_REV(req
->req_init
.clrev
);
147 if (clmajrev
< PICL_VERSION_1
)
148 picld_return_error(req
->req_init
.cnum
, PICL_NOTSUPPORTED
);
150 ret_init
.cnum
= req
->req_init
.cnum
;
151 ret_init
.rev
= PICLD_VERSION(PICLD_MAJOR_REV
, PICLD_MINOR_REV
);
153 (void) rw_unlock(&init_lk
);
154 (void) door_return((char *)&ret_init
, sizeof (picl_retinit_t
), NULL
, 0);
158 * picld_fini is called when a picl_shutdown request is received
161 picld_fini(picl_service_t
*in
)
165 ret
.cnum
= in
->req_fini
.cnum
;
167 (void) rw_unlock(&init_lk
);
168 (void) door_return((char *)&ret
, sizeof (picl_retfini_t
), NULL
, 0);
172 picld_ping(picl_service_t
*in
)
176 ret
.cnum
= in
->req_ping
.cnum
;
178 (void) rw_unlock(&init_lk
);
179 (void) door_return((char *)&ret
, sizeof (picl_retping_t
), NULL
, 0);
183 check_user(uid_t uid
)
190 return (PICL_SUCCESS
);
191 for (i
= 0; i
< MAX_CONCURRENT_WAITS
; i
++) {
192 if ((tmp_uid
= user_count
[i
].uid
) == uid
) {
193 if (user_count
[i
].count
== MAX_USER_WAITS
)
194 return (PICL_FAILURE
);
195 user_count
[i
].count
++;
196 return (PICL_SUCCESS
);
198 if ((free_idx
== -1) && (tmp_uid
== 0))
201 if (free_idx
!= -1) {
202 user_count
[free_idx
].uid
= uid
;
203 user_count
[free_idx
].count
= 1;
204 return (PICL_SUCCESS
);
206 return (PICL_FAILURE
);
216 for (i
= 0; i
< MAX_CONCURRENT_WAITS
; i
++) {
217 if (user_count
[i
].uid
== uid
) {
218 if (--user_count
[i
].count
== 0)
219 user_count
[i
].uid
= 0;
226 enter_picld_wait(uid_t uid
)
230 if (pthread_mutex_lock(&wait_req_mutex
) != 0)
231 return (PICL_FAILURE
);
232 if ((wait_count
< MAX_CONCURRENT_WAITS
) &&
233 (check_user(uid
) == PICL_SUCCESS
)) {
239 (void) pthread_mutex_unlock(&wait_req_mutex
);
244 exit_picld_wait(uid_t uid
)
246 (void) pthread_mutex_lock(&wait_req_mutex
);
249 (void) pthread_mutex_unlock(&wait_req_mutex
);
253 * picld_wait is called when a picl_wait request is received
256 picld_wait(picl_service_t
*in
)
263 ret
.cnum
= in
->req_wait
.cnum
;
264 if (door_ucred(&puc
) != 0)
265 ret
.retcode
= PICL_FAILURE
;
267 uid
= ucred_geteuid(puc
);
268 if (enter_picld_wait(uid
) == PICL_FAILURE
)
269 ret
.retcode
= PICL_FAILURE
;
271 err
= xptree_refresh_notify(in
->req_wait
.secs
);
273 exit_picld_wait(uid
);
277 (void) rw_unlock(&init_lk
);
278 (void) door_return((char *)&ret
, sizeof (picl_retwait_t
), NULL
, 0);
282 * This function returns the handle of the root node of the PICL tree
285 picld_getroot(picl_service_t
*in
)
290 ret
.cnum
= PICL_CNUM_GETROOT
;
291 err
= ptree_get_root(&ret
.rnode
);
292 if (err
!= PICL_SUCCESS
)
293 picld_return_error(in
->in
.cnum
, err
);
294 cvt_ptree2picl(&ret
.rnode
);
295 (void) rw_unlock(&init_lk
);
296 (void) door_return((char *)&ret
, sizeof (picl_retroot_t
), NULL
, 0);
300 * This function returns the value of the PICL property
303 picld_get_attrval(picl_service_t
*in
)
305 picl_retattrval_t
*ret
;
310 picl_prophdl_t ptreeh
;
311 ptree_propinfo_t pinfo
;
313 if (door_cred(&cred
) < 0)
314 picld_return_error(in
->in
.cnum
, PICL_FAILURE
);
316 err
= cvt_picl2ptree(in
->req_attrval
.attr
, &ptreeh
);
317 if (err
!= PICL_SUCCESS
)
318 picld_return_error(in
->in
.cnum
, err
);
320 err
= ptree_get_propinfo(ptreeh
, &pinfo
);
321 if (err
!= PICL_SUCCESS
)
322 picld_return_error(in
->in
.cnum
, err
);
324 if (!(pinfo
.piclinfo
.accessmode
& PICL_READ
))
325 picld_return_error(in
->in
.cnum
, PICL_NOTREADABLE
);
327 vbufsize
= pinfo
.piclinfo
.size
;
328 vbufsize
= MIN((size_t)in
->req_attrval
.bufsize
, vbufsize
);
330 len
= sizeof (picl_retattrval_t
) + vbufsize
;
333 picld_return_error(in
->in
.cnum
, PICL_FAILURE
);
334 ret
->cnum
= PICL_CNUM_GETATTRVAL
;
335 ret
->attr
= in
->req_attrval
.attr
;
336 ret
->nbytes
= (uint32_t)vbufsize
;
337 err
= xptree_get_propval_with_cred(ptreeh
, ret
->ret_buf
, vbufsize
,
339 if (err
!= PICL_SUCCESS
)
340 picld_return_error(in
->in
.cnum
, err
);
343 * adjust returned bytes for charstrings
345 if (pinfo
.piclinfo
.type
== PICL_PTYPE_CHARSTRING
)
346 ret
->nbytes
= (uint32_t)strlen(ret
->ret_buf
) + 1;
349 * convert handle values to picl handles
351 if ((pinfo
.piclinfo
.type
== PICL_PTYPE_TABLE
) ||
352 (pinfo
.piclinfo
.type
== PICL_PTYPE_REFERENCE
))
353 cvt_ptree2picl(&ret
->ret_nodeh
);
354 (void) rw_unlock(&init_lk
);
355 (void) door_return((char *)ret
, sizeof (picl_retattrval_t
) +
356 (size_t)ret
->nbytes
, NULL
, 0);
360 * This function returns the value of the PICL property specified by
364 picld_get_attrval_by_name(picl_service_t
*in
)
366 picl_retattrvalbyname_t
*ret
;
371 picl_nodehdl_t ptreeh
;
372 ptree_propinfo_t pinfo
;
374 if (door_cred(&cred
) < 0)
375 picld_return_error(in
->in
.cnum
, PICL_FAILURE
);
377 err
= cvt_picl2ptree(in
->req_attrvalbyname
.nodeh
, &ptreeh
);
378 if (err
!= PICL_SUCCESS
)
379 picld_return_error(in
->in
.cnum
, err
);
381 err
= xptree_get_propinfo_by_name(ptreeh
,
382 in
->req_attrvalbyname
.propname
, &pinfo
);
383 if (err
!= PICL_SUCCESS
)
384 picld_return_error(in
->in
.cnum
, err
);
386 if (!(pinfo
.piclinfo
.accessmode
& PICL_READ
))
387 picld_return_error(in
->in
.cnum
, PICL_NOTREADABLE
);
390 * allocate the minimum of piclinfo.size and input bufsize
392 vbufsize
= pinfo
.piclinfo
.size
;
393 vbufsize
= MIN((size_t)in
->req_attrvalbyname
.bufsize
, vbufsize
);
394 len
= sizeof (picl_retattrvalbyname_t
) + vbufsize
;
397 picld_return_error(in
->in
.cnum
, PICL_FAILURE
);
398 ret
->cnum
= PICL_CNUM_GETATTRVALBYNAME
;
399 ret
->nodeh
= in
->req_attrvalbyname
.nodeh
;
400 (void) strcpy(ret
->propname
, in
->req_attrvalbyname
.propname
);
401 ret
->nbytes
= (uint32_t)vbufsize
;
403 err
= xptree_get_propval_by_name_with_cred(ptreeh
,
404 in
->req_attrvalbyname
.propname
, ret
->ret_buf
, vbufsize
,
406 if (err
!= PICL_SUCCESS
)
407 picld_return_error(in
->in
.cnum
, err
);
409 * adjust returned value size for charstrings
411 if (pinfo
.piclinfo
.type
== PICL_PTYPE_CHARSTRING
)
412 ret
->nbytes
= (uint32_t)strlen(ret
->ret_buf
) + 1;
414 if ((pinfo
.piclinfo
.type
== PICL_PTYPE_TABLE
) ||
415 (pinfo
.piclinfo
.type
== PICL_PTYPE_REFERENCE
))
416 cvt_ptree2picl(&ret
->ret_nodeh
);
418 (void) rw_unlock(&init_lk
);
419 (void) door_return((char *)ret
, sizeof (picl_retattrvalbyname_t
) +
420 (size_t)ret
->nbytes
, NULL
, 0);
424 * This function sets a property value
427 picld_set_attrval(picl_service_t
*in
)
429 picl_retsetattrval_t ret
;
432 picl_prophdl_t ptreeh
;
433 ptree_propinfo_t pinfo
;
435 if (door_cred(&cred
) < 0)
436 picld_return_error(in
->in
.cnum
, PICL_FAILURE
);
438 err
= cvt_picl2ptree(in
->req_setattrval
.attr
, &ptreeh
);
439 if (err
!= PICL_SUCCESS
)
440 picld_return_error(in
->in
.cnum
, err
);
442 err
= ptree_get_propinfo(ptreeh
, &pinfo
);
443 if (err
!= PICL_SUCCESS
)
444 picld_return_error(in
->in
.cnum
, err
);
446 if (!(pinfo
.piclinfo
.accessmode
& PICL_WRITE
))
447 picld_return_error(in
->in
.cnum
, PICL_NOTWRITABLE
);
449 * For non-volatile prop, only super user can set its value.
451 if (!(pinfo
.piclinfo
.accessmode
& PICL_VOLATILE
) &&
452 (cred
.dc_euid
!= SUPER_USER
))
453 picld_return_error(in
->in
.cnum
, PICL_PERMDENIED
);
455 ret
.cnum
= PICL_CNUM_SETATTRVAL
;
456 ret
.attr
= in
->req_setattrval
.attr
;
458 err
= xptree_update_propval_with_cred(ptreeh
, in
->req_setattrval
.valbuf
,
459 (size_t)in
->req_setattrval
.bufsize
, cred
);
461 if (err
!= PICL_SUCCESS
)
462 picld_return_error(in
->in
.cnum
, err
);
464 (void) rw_unlock(&init_lk
);
465 (void) door_return((char *)&ret
, sizeof (picl_retsetattrval_t
), NULL
,
470 * This function sets the value of a property specified by its name.
473 picld_set_attrval_by_name(picl_service_t
*in
)
475 picl_retsetattrvalbyname_t ret
;
478 picl_prophdl_t ptreeh
;
479 ptree_propinfo_t pinfo
;
481 if (door_cred(&cred
) < 0)
482 picld_return_error(in
->in
.cnum
, PICL_FAILURE
);
484 err
= cvt_picl2ptree(in
->req_setattrvalbyname
.nodeh
, &ptreeh
);
485 if (err
!= PICL_SUCCESS
)
486 picld_return_error(in
->in
.cnum
, err
);
488 err
= xptree_get_propinfo_by_name(ptreeh
,
489 in
->req_setattrvalbyname
.propname
, &pinfo
);
490 if (err
!= PICL_SUCCESS
)
491 picld_return_error(in
->in
.cnum
, err
);
493 if (!(pinfo
.piclinfo
.accessmode
& PICL_WRITE
))
494 picld_return_error(in
->in
.cnum
, PICL_NOTWRITABLE
);
497 * For non-volatile prop, only super user can set its value.
499 if (!(pinfo
.piclinfo
.accessmode
& PICL_VOLATILE
) &&
500 (cred
.dc_euid
!= SUPER_USER
))
501 picld_return_error(in
->in
.cnum
, PICL_PERMDENIED
);
503 ret
.cnum
= PICL_CNUM_SETATTRVALBYNAME
;
504 ret
.nodeh
= in
->req_setattrvalbyname
.nodeh
;
505 (void) strcpy(ret
.propname
, in
->req_setattrvalbyname
.propname
);
507 err
= xptree_update_propval_by_name_with_cred(ptreeh
,
508 in
->req_setattrvalbyname
.propname
,
509 in
->req_setattrvalbyname
.valbuf
,
510 (size_t)in
->req_setattrvalbyname
.bufsize
,
513 if (err
!= PICL_SUCCESS
)
514 picld_return_error(in
->in
.cnum
, err
);
516 (void) rw_unlock(&init_lk
);
517 (void) door_return((char *)&ret
, sizeof (picl_retsetattrvalbyname_t
),
522 * This function returns the property information
525 picld_get_attrinfo(picl_service_t
*in
)
527 picl_retattrinfo_t ret
;
529 ptree_propinfo_t pinfo
;
530 picl_prophdl_t ptreeh
;
532 err
= cvt_picl2ptree(in
->req_attrinfo
.attr
, &ptreeh
);
533 if (err
!= PICL_SUCCESS
)
534 picld_return_error(in
->in
.cnum
, err
);
536 ret
.cnum
= PICL_CNUM_GETATTRINFO
;
537 ret
.attr
= in
->req_attrinfo
.attr
;
539 err
= ptree_get_propinfo(ptreeh
, &pinfo
);
540 if (err
!= PICL_SUCCESS
)
541 picld_return_error(in
->in
.cnum
, err
);
543 ret
.type
= pinfo
.piclinfo
.type
;
544 ret
.accessmode
= pinfo
.piclinfo
.accessmode
;
545 ret
.size
= (uint32_t)pinfo
.piclinfo
.size
;
546 (void) strcpy(ret
.name
, pinfo
.piclinfo
.name
);
547 (void) rw_unlock(&init_lk
);
548 (void) door_return((char *)&ret
, sizeof (picl_retattrinfo_t
), NULL
, 0);
552 * This function returns the node's first property handle
555 picld_get_first_attr(picl_service_t
*in
)
557 picl_retfirstattr_t ret
;
559 picl_prophdl_t ptreeh
;
561 err
= cvt_picl2ptree(in
->req_firstattr
.nodeh
, &ptreeh
);
562 if (err
!= PICL_SUCCESS
)
563 picld_return_error(in
->in
.cnum
, err
);
565 ret
.cnum
= PICL_CNUM_GETFIRSTATTR
;
566 ret
.nodeh
= in
->req_firstattr
.nodeh
;
568 err
= ptree_get_first_prop(ptreeh
, &ret
.attr
);
569 if (err
!= PICL_SUCCESS
)
570 picld_return_error(in
->in
.cnum
, err
);
571 cvt_ptree2picl(&ret
.attr
);
572 (void) rw_unlock(&init_lk
);
573 (void) door_return((char *)&ret
, sizeof (picl_retfirstattr_t
), NULL
, 0);
577 * This function returns the next property handle in list
580 picld_get_next_attr(picl_service_t
*in
)
582 picl_retnextattr_t ret
;
584 picl_prophdl_t ptreeh
;
586 err
= cvt_picl2ptree(in
->req_nextattr
.attr
, &ptreeh
);
587 if (err
!= PICL_SUCCESS
)
588 picld_return_error(in
->in
.cnum
, err
);
590 ret
.cnum
= PICL_CNUM_GETNEXTATTR
;
591 ret
.attr
= in
->req_nextattr
.attr
;
593 err
= ptree_get_next_prop(ptreeh
, &ret
.nextattr
);
594 if (err
!= PICL_SUCCESS
)
595 picld_return_error(in
->in
.cnum
, err
);
597 cvt_ptree2picl(&ret
.nextattr
);
599 (void) rw_unlock(&init_lk
);
600 (void) door_return((char *)&ret
, sizeof (picl_retnextattr_t
), NULL
, 0);
604 * This function returns the handle of a property specified by its name
607 picld_get_attr_by_name(picl_service_t
*in
)
609 picl_retattrbyname_t ret
;
611 picl_prophdl_t ptreeh
;
613 err
= cvt_picl2ptree(in
->req_attrbyname
.nodeh
, &ptreeh
);
614 if (err
!= PICL_SUCCESS
)
615 picld_return_error(in
->in
.cnum
, err
);
617 ret
.cnum
= PICL_CNUM_GETATTRBYNAME
;
618 ret
.nodeh
= in
->req_attrbyname
.nodeh
;
619 (void) strcpy(ret
.propname
, in
->req_attrbyname
.propname
);
621 err
= ptree_get_prop_by_name(ptreeh
, ret
.propname
, &ret
.attr
);
622 if (err
!= PICL_SUCCESS
)
623 picld_return_error(in
->in
.cnum
, err
);
625 cvt_ptree2picl(&ret
.attr
);
626 (void) rw_unlock(&init_lk
);
627 (void) door_return((char *)&ret
, sizeof (picl_retattrbyname_t
), NULL
,
632 * This function gets the next property on the same row in the table
635 picld_get_attr_by_row(picl_service_t
*in
)
637 picl_retattrbyrow_t ret
;
639 picl_prophdl_t ptreeh
;
641 err
= cvt_picl2ptree(in
->req_attrbyrow
.attr
, &ptreeh
);
642 if (err
!= PICL_SUCCESS
)
643 picld_return_error(in
->in
.cnum
, err
);
645 ret
.cnum
= PICL_CNUM_GETATTRBYROW
;
646 ret
.attr
= in
->req_attrbyrow
.attr
;
648 err
= ptree_get_next_by_row(ptreeh
, &ret
.rowattr
);
649 if (err
!= PICL_SUCCESS
)
650 picld_return_error(in
->in
.cnum
, err
);
651 cvt_ptree2picl(&ret
.rowattr
);
653 (void) rw_unlock(&init_lk
);
654 (void) door_return((char *)&ret
, sizeof (picl_retattrbyrow_t
), NULL
, 0);
658 * This function returns the handle of the next property in the same column
662 picld_get_attr_by_col(picl_service_t
*in
)
664 picl_retattrbycol_t ret
;
666 picl_prophdl_t ptreeh
;
668 err
= cvt_picl2ptree(in
->req_attrbycol
.attr
, &ptreeh
);
669 if (err
!= PICL_SUCCESS
)
670 picld_return_error(in
->in
.cnum
, err
);
672 ret
.cnum
= PICL_CNUM_GETATTRBYCOL
;
673 ret
.attr
= in
->req_attrbycol
.attr
;
675 err
= ptree_get_next_by_col(ptreeh
, &ret
.colattr
);
676 if (err
!= PICL_SUCCESS
)
677 picld_return_error(in
->in
.cnum
, err
);
679 cvt_ptree2picl(&ret
.colattr
);
681 (void) rw_unlock(&init_lk
);
682 (void) door_return((char *)&ret
, sizeof (picl_retattrbycol_t
), NULL
, 0);
686 * This function finds the node in the PICLTREE that matches the given
687 * criteria and returns its handle.
690 picld_find_node(picl_service_t
*in
)
692 picl_retfindnode_t ret
;
694 picl_nodehdl_t ptreeh
;
696 err
= cvt_picl2ptree(in
->req_findnode
.nodeh
, &ptreeh
);
697 if (err
!= PICL_SUCCESS
)
698 picld_return_error(in
->in
.cnum
, err
);
700 ret
.cnum
= PICL_CNUM_FINDNODE
;
702 err
= ptree_find_node(ptreeh
, in
->req_findnode
.propname
,
703 in
->req_findnode
.ptype
, in
->req_findnode
.valbuf
,
704 in
->req_findnode
.valsize
, &ret
.rnodeh
);
705 if (err
!= PICL_SUCCESS
)
706 picld_return_error(in
->in
.cnum
, err
);
708 cvt_ptree2picl(&ret
.rnodeh
);
710 (void) rw_unlock(&init_lk
);
711 (void) door_return((char *)&ret
, sizeof (ret
), NULL
, 0);
715 * This function finds the property/node that corresponds to the given path
716 * and returns its handle
719 picld_get_node_by_path(picl_service_t
*in
)
721 picl_retnodebypath_t ret
;
724 ret
.cnum
= PICL_CNUM_NODEBYPATH
;
725 err
= ptree_get_node_by_path(in
->req_nodebypath
.pathbuf
, &ret
.nodeh
);
726 if (err
!= PICL_SUCCESS
)
727 picld_return_error(in
->in
.cnum
, err
);
728 cvt_ptree2picl(&ret
.nodeh
);
729 (void) rw_unlock(&init_lk
);
730 (void) door_return((char *)&ret
, sizeof (ret
), NULL
, 0);
734 * This function returns finds the frutree parent node for a given node
735 * and returns its handle
738 picld_get_frutree_parent(picl_service_t
*in
)
740 picl_retfruparent_t ret
;
742 picl_nodehdl_t ptreeh
;
744 err
= cvt_picl2ptree(in
->req_fruparent
.devh
, &ptreeh
);
745 if (err
!= PICL_SUCCESS
)
746 picld_return_error(in
->in
.cnum
, err
);
748 ret
.cnum
= PICL_CNUM_FRUTREEPARENT
;
750 err
= ptree_get_frutree_parent(ptreeh
, &ret
.fruh
);
751 if (err
!= PICL_SUCCESS
)
752 picld_return_error(in
->in
.cnum
, err
);
753 cvt_ptree2picl(&ret
.fruh
);
755 (void) rw_unlock(&init_lk
);
756 (void) door_return((char *)&ret
, sizeof (ret
), NULL
, 0);
760 * This function is called when an unknown client request is received.
763 picld_unknown_service(picl_service_t
*in
)
765 picld_return_error(in
->in
.cnum
, PICL_UNKNOWNSERVICE
);
769 check_denial_of_service(int cnum
)
775 current
= gethrtime();
778 if (pthread_mutex_lock(&dos_mutex
) != 0)
779 picld_return_error(cnum
, PICL_FAILURE
);
782 window
= current
- orig_time
;
783 if (window
> MILLI_TO_NANO(sliding_interval_ms
)) {
785 service_requests
= 1;
788 if (service_requests
> dos_req_limit
)
791 if (pthread_mutex_unlock(&dos_mutex
) != 0)
792 picld_return_error(cnum
, PICL_FAILURE
);
795 (void) poll(NULL
, 0, dos_ms
);
800 picld_door_handler(void *cookie
, char *argp
, size_t asize
,
801 door_desc_t
*dp
, uint_t n_desc
)
806 req
= (picl_service_t
*)argp
;
809 (void) door_return((char *)req
, 0, NULL
, 0);
811 check_denial_of_service(req
->in
.cnum
);
813 (void) rw_rdlock(&init_lk
);
814 switch (req
->in
.cnum
) { /* client call number */
817 picld_init((picl_service_t
*)argp
);
821 picld_fini((picl_service_t
*)argp
);
823 case PICL_CNUM_GETROOT
:
825 picld_getroot((picl_service_t
*)argp
);
827 case PICL_CNUM_GETATTRVAL
:
829 picld_get_attrval((picl_service_t
*)argp
);
831 case PICL_CNUM_GETATTRVALBYNAME
:
833 picld_get_attrval_by_name((picl_service_t
*)argp
);
835 case PICL_CNUM_GETATTRINFO
:
837 picld_get_attrinfo((picl_service_t
*)argp
);
839 case PICL_CNUM_GETFIRSTATTR
:
841 picld_get_first_attr((picl_service_t
*)argp
);
843 case PICL_CNUM_GETNEXTATTR
:
845 picld_get_next_attr((picl_service_t
*)argp
);
847 case PICL_CNUM_GETATTRBYNAME
:
849 picld_get_attr_by_name((picl_service_t
*)argp
);
851 case PICL_CNUM_GETATTRBYROW
:
853 picld_get_attr_by_row((picl_service_t
*)argp
);
855 case PICL_CNUM_GETATTRBYCOL
:
857 picld_get_attr_by_col((picl_service_t
*)argp
);
859 case PICL_CNUM_SETATTRVAL
:
861 picld_set_attrval((picl_service_t
*)argp
);
863 case PICL_CNUM_SETATTRVALBYNAME
:
865 picld_set_attrval_by_name((picl_service_t
*)argp
);
869 picld_ping((picl_service_t
*)argp
);
873 picld_wait((picl_service_t
*)argp
);
875 case PICL_CNUM_FINDNODE
:
877 picld_find_node((picl_service_t
*)argp
);
879 case PICL_CNUM_NODEBYPATH
:
881 picld_get_node_by_path((picl_service_t
*)argp
);
883 case PICL_CNUM_FRUTREEPARENT
:
885 picld_get_frutree_parent((picl_service_t
*)argp
);
889 picld_unknown_service((picl_service_t
*)argp
);
897 hup_handler(int sig
, siginfo_t
*siginfo
, void *sigctx
)
903 * "ping" to see if a daemon is already running
909 picl_reqping_t req_ping
;
910 picl_retping_t ret_ping
;
914 doorh
= open(PICLD_DOOR
, O_RDONLY
);
918 if (door_info(doorh
, &dinfo
) < 0) {
923 if ((dinfo
.di_attributes
& DOOR_REVOKED
) ||
924 (dinfo
.di_data
!= (uintptr_t)PICLD_DOOR_COOKIE
)) {
929 if (dinfo
.di_target
!= getpid()) {
934 req_ping
.cnum
= PICL_CNUM_PING
;
936 darg
.data_ptr
= (char *)&req_ping
;
937 darg
.data_size
= sizeof (picl_reqping_t
);
938 darg
.desc_ptr
= NULL
;
940 darg
.rbuf
= (char *)&ret_ping
;
941 darg
.rsize
= sizeof (picl_retping_t
);
943 if (door_call(doorh
, &darg
) < 0) {
953 * picld_create_server_thread - binds the running thread to the private
954 * door pool, and sets the required cancellation state.
958 picld_create_server_thread(void *arg
)
961 * wait for door descriptor to be initialized
963 (void) pthread_mutex_lock(&door_mutex
);
964 while (door_id
== -1) {
965 (void) pthread_cond_wait(&door_cv
, &door_mutex
);
967 (void) pthread_mutex_unlock(&door_mutex
);
970 * Bind this thread to the door's private thread pool
972 if (door_bind(door_id
) < 0) {
977 * Disable thread cancellation mechanism
979 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, NULL
);
980 (void) door_return(NULL
, 0, NULL
, 0); /* wait for door invocation */
985 * picld_server_create_fn - creates threads for the private door pool
990 picld_server_create_fn(door_info_t
*dip
)
995 * For the non-private pool do nothing. It's used for events which are
996 * single threaded anyway. The single thread servicing that pool is
997 * created when the event plugin creates its door. Note that the event
998 * plugin runs before setup_door instantiates picld_server_create_fn as
999 * the new create_proc so the door library default create_proc is used.
1004 (void) pthread_mutex_lock(&pool_mutex
);
1005 if (pool_count
< MAX_POOL_SIZE
) {
1006 (void) pthread_attr_init(&attr
);
1007 (void) pthread_attr_setscope(&attr
, PTHREAD_SCOPE_SYSTEM
);
1008 (void) pthread_attr_setdetachstate(&attr
,
1009 PTHREAD_CREATE_DETACHED
);
1010 if (pthread_create(NULL
, &attr
, picld_create_server_thread
,
1012 perror("pthread_create");
1017 (void) pthread_mutex_unlock(&pool_mutex
);
1021 * Create the picld door
1028 (void) door_server_create(picld_server_create_fn
);
1029 (void) pthread_mutex_lock(&door_mutex
);
1033 door_id
= door_create(picld_door_handler
, PICLD_DOOR_COOKIE
,
1034 DOOR_REFUSE_DESC
| DOOR_NO_CANCEL
| DOOR_PRIVATE
);
1037 (void) pthread_mutex_unlock(&door_mutex
);
1040 (void) pthread_cond_signal(&door_cv
);
1041 (void) pthread_mutex_unlock(&door_mutex
);
1044 if (stat(PICLD_DOOR
, &stbuf
) < 0) {
1047 /* ensure that the door file is world-readable */
1048 old_mask
= umask(0);
1049 newfd
= creat(PICLD_DOOR
, 0444);
1050 /* restore the file mode creation mask */
1051 (void) umask(old_mask
);
1054 (void) close(newfd
);
1057 if (fattach(door_id
, PICLD_DOOR
) < 0) {
1058 if ((errno
!= EBUSY
) ||
1059 (fdetach(PICLD_DOOR
) < 0) ||
1060 (fattach(door_id
, PICLD_DOOR
) < 0))
1067 * Main function of picl daemon
1070 main(int argc
, char **argv
)
1072 struct sigaction act
;
1077 (void) setlocale(LC_ALL
, "");
1078 (void) textdomain(TEXT_DOMAIN
);
1080 if (getuid() != 0) {
1081 syslog(LOG_CRIT
, MUST_BE_ROOT
);
1085 (void) rwlock_init(&init_lk
, USYNC_THREAD
, NULL
);
1088 dos_req_limit
= DOS_PICL_REQUESTS_LIMIT
;
1089 sliding_interval_ms
= SLIDING_INTERVAL_MILLISECONDS
;
1090 dos_ms
= DOS_SLEEPTIME_MS
;
1096 while ((c
= getopt(argc
, argv
, "is:t:l:r:v:d:")) != EOF
) {
1099 dos_ms
= strtol(optarg
, (char **)NULL
, 0);
1105 sliding_interval_ms
= strtoll(optarg
, (char **)NULL
, 0);
1108 dos_req_limit
= strtol(optarg
, (char **)NULL
, 0);
1111 verbose_level
= strtol(optarg
, (char **)NULL
, 0);
1119 orig_time
= gethrtime();
1122 * is there a daemon already running?
1125 if (daemon_exists()) {
1126 syslog(LOG_CRIT
, DAEMON_RUNNING
);
1131 * Mask off/block SIGALRM signal so that the environmental plug-in
1132 * (piclenvd) can use it to simulate sleep() without being affected
1133 * by time being set back. No other PICL plug-in should use SIGALRM
1134 * or alarm() for now.
1136 (void) sigemptyset(&ublk
);
1137 (void) sigaddset(&ublk
, SIGALRM
);
1138 (void) sigprocmask(SIG_BLOCK
, &ublk
, NULL
);
1141 * Ignore SIGHUP until all the initialization is done.
1143 act
.sa_handler
= SIG_IGN
;
1144 (void) sigemptyset(&act
.sa_mask
);
1146 if (sigaction(SIGHUP
, &act
, NULL
) == -1)
1147 syslog(LOG_ERR
, SIGACT_FAILED
, strsignal(SIGHUP
),
1150 if (logflag
!= 0) { /* daemonize */
1161 if (chdir("/") == -1) {
1162 syslog(LOG_CRIT
, CD_ROOT_FAILED
);
1168 (void) open("/dev/null", O_RDWR
, 0);
1169 (void) dup2(STDIN_FILENO
, STDOUT_FILENO
);
1170 (void) dup2(STDIN_FILENO
, STDERR_FILENO
);
1171 openlog(PICLD
, LOG_PID
, LOG_DAEMON
);
1175 * Initialize the PICL Tree
1177 if (xptree_initialize(NULL
) != PICL_SUCCESS
) {
1178 syslog(LOG_CRIT
, INIT_FAILED
);
1183 syslog(LOG_CRIT
, DOOR_FAILED
);
1188 * setup signal handlers for post-init
1190 act
.sa_sigaction
= hup_handler
;
1191 (void) sigemptyset(&act
.sa_mask
);
1192 act
.sa_flags
= SA_SIGINFO
;
1193 if (sigaction(SIGHUP
, &act
, NULL
) == -1)
1194 syslog(LOG_ERR
, SIGACT_FAILED
, strsignal(SIGHUP
),
1204 * Block SIGHUP during reinitialization.
1205 * Also mask off/block SIGALRM signal so that the
1206 * environmental plug-in (piclenvd) can use it to
1207 * simulate sleep() without being affected by time
1208 * being set back. No ohter PICL plug-in should use
1209 * SIGALRM or alarm() for now.
1211 (void) sigemptyset(&ublk
);
1212 (void) sigaddset(&ublk
, SIGHUP
);
1213 (void) sigaddset(&ublk
, SIGALRM
);
1214 (void) sigprocmask(SIG_BLOCK
, &ublk
, NULL
);
1215 (void) sigdelset(&ublk
, SIGALRM
);
1217 (void) rw_wrlock(&init_lk
);
1219 (void) xptree_reinitialize();
1220 (void) rw_unlock(&init_lk
);
1221 (void) sigprocmask(SIG_UNBLOCK
, &ublk
, NULL
);