8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / picl / picld / picld.c
blobae67fd75811676594434fb319557d3e5faa25d53
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * PICL daemon
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stdarg.h>
34 #include <string.h>
35 #include <libintl.h>
36 #include <locale.h>
37 #include <alloca.h>
38 #include <errno.h>
39 #include <assert.h>
40 #include <stropts.h>
41 #include <unistd.h>
42 #include <signal.h>
43 #include <pthread.h>
44 #include <synch.h>
45 #include <door.h>
46 #include <sys/door.h>
47 #include <fcntl.h>
48 #include <dlfcn.h>
49 #include <time.h>
50 #include <sys/utsname.h>
51 #include <sys/systeminfo.h>
52 #include <sys/stat.h>
53 #include <sys/wait.h>
54 #include <dirent.h>
55 #include <syslog.h>
56 #include <poll.h>
57 #include <limits.h>
58 #include <picl.h>
59 #include "picl2door.h"
60 #include <picltree.h>
61 #include "ptree_impl.h"
64 * Log text messages
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")
75 * Constants
77 #define PICLD "picld"
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
88 * Macros
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;
97 * Module Variables
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;
115 static struct {
116 uid_t uid;
117 int count;
118 } user_count[MAX_CONCURRENT_WAITS];
121 * This returns an error message to libpicl
123 static void
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
139 static void
140 picld_init(picl_service_t *req)
142 picl_retinit_t ret_init;
143 int clmajrev;
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
160 static void
161 picld_fini(picl_service_t *in)
163 picl_retfini_t ret;
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);
171 static void
172 picld_ping(picl_service_t *in)
174 picl_retping_t ret;
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);
182 static int
183 check_user(uid_t uid)
185 int i;
186 uid_t tmp_uid;
187 int free_idx = -1;
189 if (uid == 0)
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))
199 free_idx = i;
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);
209 static void
210 done_user(uid_t uid)
212 int i;
214 if (uid == 0)
215 return;
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;
220 return;
225 static int
226 enter_picld_wait(uid_t uid)
228 int rv;
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)) {
234 rv = PICL_SUCCESS;
235 wait_count++;
236 } else {
237 rv = PICL_FAILURE;
239 (void) pthread_mutex_unlock(&wait_req_mutex);
240 return (rv);
243 static void
244 exit_picld_wait(uid_t uid)
246 (void) pthread_mutex_lock(&wait_req_mutex);
247 done_user(uid);
248 wait_count--;
249 (void) pthread_mutex_unlock(&wait_req_mutex);
253 * picld_wait is called when a picl_wait request is received
255 static void
256 picld_wait(picl_service_t *in)
258 picl_retwait_t ret;
259 int err;
260 ucred_t *puc = NULL;
261 uid_t uid;
263 ret.cnum = in->req_wait.cnum;
264 if (door_ucred(&puc) != 0)
265 ret.retcode = PICL_FAILURE;
266 else {
267 uid = ucred_geteuid(puc);
268 if (enter_picld_wait(uid) == PICL_FAILURE)
269 ret.retcode = PICL_FAILURE;
270 else {
271 err = xptree_refresh_notify(in->req_wait.secs);
272 ret.retcode = err;
273 exit_picld_wait(uid);
275 ucred_free(puc);
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
284 static void
285 picld_getroot(picl_service_t *in)
287 picl_retroot_t ret;
288 int err;
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
302 static void
303 picld_get_attrval(picl_service_t *in)
305 picl_retattrval_t *ret;
306 int err;
307 size_t vbufsize;
308 size_t len;
309 door_cred_t cred;
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;
331 ret = alloca(len);
332 if (ret == NULL)
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,
338 cred);
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
361 * its name.
363 static void
364 picld_get_attrval_by_name(picl_service_t *in)
366 picl_retattrvalbyname_t *ret;
367 int err;
368 size_t vbufsize;
369 size_t len;
370 door_cred_t cred;
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;
395 ret = alloca(len);
396 if (ret == NULL)
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,
405 cred);
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
426 static void
427 picld_set_attrval(picl_service_t *in)
429 picl_retsetattrval_t ret;
430 int err;
431 door_cred_t cred;
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.
472 static void
473 picld_set_attrval_by_name(picl_service_t *in)
475 picl_retsetattrvalbyname_t ret;
476 int err;
477 door_cred_t cred;
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,
511 cred);
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),
518 NULL, 0);
522 * This function returns the property information
524 static void
525 picld_get_attrinfo(picl_service_t *in)
527 picl_retattrinfo_t ret;
528 int err;
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
554 static void
555 picld_get_first_attr(picl_service_t *in)
557 picl_retfirstattr_t ret;
558 int err;
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
579 static void
580 picld_get_next_attr(picl_service_t *in)
582 picl_retnextattr_t ret;
583 int err;
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
606 static void
607 picld_get_attr_by_name(picl_service_t *in)
609 picl_retattrbyname_t ret;
610 int err;
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
634 static void
635 picld_get_attr_by_row(picl_service_t *in)
637 picl_retattrbyrow_t ret;
638 int err;
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
659 * of the table.
661 static void
662 picld_get_attr_by_col(picl_service_t *in)
664 picl_retattrbycol_t ret;
665 int err;
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.
689 static void
690 picld_find_node(picl_service_t *in)
692 picl_retfindnode_t ret;
693 int err;
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
718 static void
719 picld_get_node_by_path(picl_service_t *in)
721 picl_retnodebypath_t ret;
722 int err;
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
737 static void
738 picld_get_frutree_parent(picl_service_t *in)
740 picl_retfruparent_t ret;
741 int err;
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.
762 static void
763 picld_unknown_service(picl_service_t *in)
765 picld_return_error(in->in.cnum, PICL_UNKNOWNSERVICE);
768 static void
769 check_denial_of_service(int cnum)
771 hrtime_t window;
772 hrtime_t current;
773 int dos_flag;
775 current = gethrtime();
776 dos_flag = 0;
778 if (pthread_mutex_lock(&dos_mutex) != 0)
779 picld_return_error(cnum, PICL_FAILURE);
781 ++service_requests;
782 window = current - orig_time;
783 if (window > MILLI_TO_NANO(sliding_interval_ms)) {
784 orig_time = current;
785 service_requests = 1;
788 if (service_requests > dos_req_limit)
789 dos_flag = 1;
791 if (pthread_mutex_unlock(&dos_mutex) != 0)
792 picld_return_error(cnum, PICL_FAILURE);
794 if (dos_flag)
795 (void) poll(NULL, 0, dos_ms);
798 /* ARGSUSED */
799 static void
800 picld_door_handler(void *cookie, char *argp, size_t asize,
801 door_desc_t *dp, uint_t n_desc)
803 picl_service_t *req;
805 /*LINTED*/
806 req = (picl_service_t *)argp;
808 if (req == NULL)
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 */
815 case PICL_CNUM_INIT:
816 /*LINTED*/
817 picld_init((picl_service_t *)argp);
818 break;
819 case PICL_CNUM_FINI:
820 /*LINTED*/
821 picld_fini((picl_service_t *)argp);
822 break;
823 case PICL_CNUM_GETROOT:
824 /*LINTED*/
825 picld_getroot((picl_service_t *)argp);
826 break;
827 case PICL_CNUM_GETATTRVAL:
828 /*LINTED*/
829 picld_get_attrval((picl_service_t *)argp);
830 break;
831 case PICL_CNUM_GETATTRVALBYNAME:
832 /*LINTED*/
833 picld_get_attrval_by_name((picl_service_t *)argp);
834 break;
835 case PICL_CNUM_GETATTRINFO:
836 /*LINTED*/
837 picld_get_attrinfo((picl_service_t *)argp);
838 break;
839 case PICL_CNUM_GETFIRSTATTR:
840 /*LINTED*/
841 picld_get_first_attr((picl_service_t *)argp);
842 break;
843 case PICL_CNUM_GETNEXTATTR:
844 /*LINTED*/
845 picld_get_next_attr((picl_service_t *)argp);
846 break;
847 case PICL_CNUM_GETATTRBYNAME:
848 /*LINTED*/
849 picld_get_attr_by_name((picl_service_t *)argp);
850 break;
851 case PICL_CNUM_GETATTRBYROW:
852 /*LINTED*/
853 picld_get_attr_by_row((picl_service_t *)argp);
854 break;
855 case PICL_CNUM_GETATTRBYCOL:
856 /*LINTED*/
857 picld_get_attr_by_col((picl_service_t *)argp);
858 break;
859 case PICL_CNUM_SETATTRVAL:
860 /*LINTED*/
861 picld_set_attrval((picl_service_t *)argp);
862 break;
863 case PICL_CNUM_SETATTRVALBYNAME:
864 /*LINTED*/
865 picld_set_attrval_by_name((picl_service_t *)argp);
866 break;
867 case PICL_CNUM_PING:
868 /*LINTED*/
869 picld_ping((picl_service_t *)argp);
870 break;
871 case PICL_CNUM_WAIT:
872 /*LINTED*/
873 picld_wait((picl_service_t *)argp);
874 break;
875 case PICL_CNUM_FINDNODE:
876 /*LINTED*/
877 picld_find_node((picl_service_t *)argp);
878 break;
879 case PICL_CNUM_NODEBYPATH:
880 /*LINTED*/
881 picld_get_node_by_path((picl_service_t *)argp);
882 break;
883 case PICL_CNUM_FRUTREEPARENT:
884 /*LINTED*/
885 picld_get_frutree_parent((picl_service_t *)argp);
886 break;
887 default:
888 /*LINTED*/
889 picld_unknown_service((picl_service_t *)argp);
890 break;
892 /*NOTREACHED*/
895 /* ARGSUSED */
896 static void
897 hup_handler(int sig, siginfo_t *siginfo, void *sigctx)
899 doreinit = 1;
903 * "ping" to see if a daemon is already running
905 static int
906 daemon_exists(void)
908 door_arg_t darg;
909 picl_reqping_t req_ping;
910 picl_retping_t ret_ping;
911 int doorh;
912 door_info_t dinfo;
914 doorh = open(PICLD_DOOR, O_RDONLY);
915 if (doorh < 0)
916 return (0);
918 if (door_info(doorh, &dinfo) < 0) {
919 (void) close(doorh);
920 return (0);
923 if ((dinfo.di_attributes & DOOR_REVOKED) ||
924 (dinfo.di_data != (uintptr_t)PICLD_DOOR_COOKIE)) {
925 (void) close(doorh);
926 return (0);
929 if (dinfo.di_target != getpid()) {
930 (void) close(doorh);
931 return (1);
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;
939 darg.desc_num = 0;
940 darg.rbuf = (char *)&ret_ping;
941 darg.rsize = sizeof (picl_retping_t);
943 if (door_call(doorh, &darg) < 0) {
944 (void) close(doorh);
945 return (0);
948 (void) close(doorh);
949 return (1);
953 * picld_create_server_thread - binds the running thread to the private
954 * door pool, and sets the required cancellation state.
956 /* ARGSUSED */
957 static void *
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) {
973 perror("door_bind");
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 */
981 return (NULL);
985 * picld_server_create_fn - creates threads for the private door pool
988 /* ARGSUSED */
989 static void
990 picld_server_create_fn(door_info_t *dip)
992 pthread_attr_t attr;
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.
1001 if (dip == NULL)
1002 return;
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,
1011 NULL)) {
1012 perror("pthread_create");
1013 } else {
1014 pool_count++;
1017 (void) pthread_mutex_unlock(&pool_mutex);
1021 * Create the picld door
1023 static int
1024 setup_door(void)
1026 struct stat stbuf;
1028 (void) door_server_create(picld_server_create_fn);
1029 (void) pthread_mutex_lock(&door_mutex);
1031 * Create the door
1033 door_id = door_create(picld_door_handler, PICLD_DOOR_COOKIE,
1034 DOOR_REFUSE_DESC | DOOR_NO_CANCEL | DOOR_PRIVATE);
1036 if (door_id < 0) {
1037 (void) pthread_mutex_unlock(&door_mutex);
1038 return (-1);
1039 } else {
1040 (void) pthread_cond_signal(&door_cv);
1041 (void) pthread_mutex_unlock(&door_mutex);
1044 if (stat(PICLD_DOOR, &stbuf) < 0) {
1045 int newfd;
1046 mode_t old_mask;
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);
1052 if (newfd < 0)
1053 return (-1);
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))
1061 return (-1);
1063 return (0);
1067 * Main function of picl daemon
1070 main(int argc, char **argv)
1072 struct sigaction act;
1073 int c;
1074 sigset_t ublk;
1077 (void) setlocale(LC_ALL, "");
1078 (void) textdomain(TEXT_DOMAIN);
1080 if (getuid() != 0) {
1081 syslog(LOG_CRIT, MUST_BE_ROOT);
1082 return (0);
1085 (void) rwlock_init(&init_lk, USYNC_THREAD, NULL);
1086 doreinit = 0;
1087 logflag = 1;
1088 dos_req_limit = DOS_PICL_REQUESTS_LIMIT;
1089 sliding_interval_ms = SLIDING_INTERVAL_MILLISECONDS;
1090 dos_ms = DOS_SLEEPTIME_MS;
1091 verbose_level = 0;
1094 * parse arguments
1096 while ((c = getopt(argc, argv, "is:t:l:r:v:d:")) != EOF) {
1097 switch (c) {
1098 case 'd':
1099 dos_ms = strtol(optarg, (char **)NULL, 0);
1100 break;
1101 case 'i':
1102 logflag = 0;
1103 break;
1104 case 's':
1105 sliding_interval_ms = strtoll(optarg, (char **)NULL, 0);
1106 break;
1107 case 't':
1108 dos_req_limit = strtol(optarg, (char **)NULL, 0);
1109 break;
1110 case 'v':
1111 verbose_level = strtol(optarg, (char **)NULL, 0);
1112 logflag = 0;
1113 break;
1114 default:
1115 break;
1119 orig_time = gethrtime();
1122 * is there a daemon already running?
1125 if (daemon_exists()) {
1126 syslog(LOG_CRIT, DAEMON_RUNNING);
1127 exit(1);
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);
1145 act.sa_flags = 0;
1146 if (sigaction(SIGHUP, &act, NULL) == -1)
1147 syslog(LOG_ERR, SIGACT_FAILED, strsignal(SIGHUP),
1148 strerror(errno));
1150 if (logflag != 0) { /* daemonize */
1151 pid_t pid;
1153 pid = fork();
1154 if (pid < 0)
1155 exit(1);
1156 if (pid > 0)
1157 /* parent */
1158 exit(0);
1160 /* child */
1161 if (chdir("/") == -1) {
1162 syslog(LOG_CRIT, CD_ROOT_FAILED);
1163 exit(1);
1166 (void) setsid();
1167 closefrom(0);
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);
1179 exit(1);
1182 if (setup_door()) {
1183 syslog(LOG_CRIT, DOOR_FAILED);
1184 exit(1);
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),
1195 strerror(errno));
1198 * wait for requests
1200 for (;;) {
1201 (void) pause();
1202 if (doreinit) {
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);
1216 doreinit = 0;
1217 (void) rw_wrlock(&init_lk);
1218 xptree_destroy();
1219 (void) xptree_reinitialize();
1220 (void) rw_unlock(&init_lk);
1221 (void) sigprocmask(SIG_UNBLOCK, &ublk, NULL);