xref: /illumos-gate/usr/src/cmd/picl/picld/picld.c (revision 646e55b6807cdf761fecd1e4095d73116cdefdb5)
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 /*
24  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29 
30 /*
31  * PICL daemon
32  */
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <stdarg.h>
37 #include <string.h>
38 #include <libintl.h>
39 #include <locale.h>
40 #include <alloca.h>
41 #include <errno.h>
42 #include <assert.h>
43 #include <stropts.h>
44 #include <unistd.h>
45 #include <signal.h>
46 #include <pthread.h>
47 #include <synch.h>
48 #include <door.h>
49 #include <sys/door.h>
50 #include <fcntl.h>
51 #include <dlfcn.h>
52 #include <time.h>
53 #include <sys/utsname.h>
54 #include <sys/systeminfo.h>
55 #include <sys/stat.h>
56 #include <sys/wait.h>
57 #include <dirent.h>
58 #include <syslog.h>
59 #include <poll.h>
60 #include <limits.h>
61 #include <picl.h>
62 #include "picl2door.h"
63 #include <picltree.h>
64 #include "ptree_impl.h"
65 
66 /*
67  * Log text messages
68  */
69 #define	MUST_BE_ROOT	gettext("this program must be run as root\n")
70 #define	CD_ROOT_FAILED	gettext("chdir to root failed\n")
71 #define	INIT_FAILED	gettext("ptree initialization failed\n")
72 #define	DAEMON_RUNNING	gettext("PICL daemon already running\n")
73 #define	DOOR_FAILED	gettext("Failed creating picld door\n")
74 #define	SIGACT_FAILED	\
75 		gettext("Failed to install signal handler for %s: %s\n")
76 
77 /*
78  * Constants
79  */
80 #define	PICLD				"picld"
81 #define	DOS_PICL_REQUESTS_LIMIT		10000
82 #define	SLIDING_INTERVAL_MILLISECONDS	1000
83 #define	PICLD_MAJOR_REV			0x1
84 #define	PICLD_MINOR_REV			0x0
85 #define	DOS_SLEEPTIME_MS		1000
86 
87 /*
88  * Macros
89  */
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)
93 
94 extern	char	**environ;
95 
96 /*
97  * Module Variables
98  */
99 static	int		logflag = 1;
100 static	int		doreinit = 0;
101 static	int		door_id = -1;
102 static  int 		service_requests = 0;
103 static	hrtime_t	orig_time;
104 static	hrtime_t	sliding_interval_ms;
105 static	uint32_t	dos_req_limit;
106 static	uint32_t	dos_ms;
107 static	pthread_mutex_t	dos_mutex = PTHREAD_MUTEX_INITIALIZER;
108 static	rwlock_t	init_lk;
109 
110 /*
111  * This returns an error message to libpicl
112  */
113 static void
114 picld_return_error(picl_callnumber_t cnum, picl_errno_t err)
115 {
116 	picl_reterror_t	ret_error;
117 
118 	ret_error.cnum = PICL_CNUM_ERROR;
119 	ret_error.in_cnum = cnum;
120 	ret_error.errnum = err;
121 	(void) rw_unlock(&init_lk);
122 	(void) door_return((char *)&ret_error, sizeof (picl_reterror_t), NULL,
123 	    0);
124 }
125 
126 /*
127  * picld_init is called when a picl_initialize request is received
128  */
129 static void
130 picld_init(picl_service_t *req)
131 {
132 	picl_retinit_t	ret_init;
133 	int	clmajrev;
134 
135 	clmajrev = PICL_CLIENT_REV(req->req_init.clrev);
136 
137 	if (clmajrev < PICL_VERSION_1)
138 		picld_return_error(req->req_init.cnum, PICL_NOTSUPPORTED);
139 
140 	ret_init.cnum = req->req_init.cnum;
141 	ret_init.rev = PICLD_VERSION(PICLD_MAJOR_REV, PICLD_MINOR_REV);
142 
143 	(void) rw_unlock(&init_lk);
144 	(void) door_return((char *)&ret_init, sizeof (picl_retinit_t), NULL, 0);
145 }
146 
147 /*
148  * picld_fini is called when a picl_shutdown request is received
149  */
150 static void
151 picld_fini(picl_service_t *in)
152 {
153 	picl_retfini_t	ret;
154 
155 	ret.cnum = in->req_fini.cnum;
156 
157 	(void) rw_unlock(&init_lk);
158 	(void) door_return((char *)&ret, sizeof (picl_retfini_t), NULL, 0);
159 }
160 
161 static void
162 picld_ping(picl_service_t *in)
163 {
164 	picl_retping_t	ret;
165 
166 	ret.cnum = in->req_ping.cnum;
167 
168 	(void) rw_unlock(&init_lk);
169 	(void) door_return((char *)&ret, sizeof (picl_retping_t), NULL, 0);
170 }
171 
172 /*
173  * picld_wait is called when a picl_wait request is received
174  */
175 static void
176 picld_wait(picl_service_t *in)
177 {
178 	picl_retwait_t	ret;
179 	int		err;
180 
181 	ret.cnum = in->req_wait.cnum;
182 
183 	err = xptree_refresh_notify(in->req_wait.secs);
184 	ret.retcode = err;
185 
186 	(void) rw_unlock(&init_lk);
187 	(void) door_return((char *)&ret, sizeof (picl_retwait_t), NULL, 0);
188 }
189 
190 /*
191  * This function returns the handle of the root node of the PICL tree
192  */
193 static void
194 picld_getroot(picl_service_t *in)
195 {
196 	picl_retroot_t	ret;
197 	int		err;
198 
199 	ret.cnum = PICL_CNUM_GETROOT;
200 	err = ptree_get_root(&ret.rnode);
201 	if (err != PICL_SUCCESS)
202 		picld_return_error(in->in.cnum, err);
203 	cvt_ptree2picl(&ret.rnode);
204 	(void) rw_unlock(&init_lk);
205 	(void) door_return((char *)&ret, sizeof (picl_retroot_t), NULL, 0);
206 }
207 
208 /*
209  * This function returns the value of the PICL property
210  */
211 static void
212 picld_get_attrval(picl_service_t *in)
213 {
214 	picl_retattrval_t	*ret;
215 	int			err;
216 	size_t			vbufsize;
217 	size_t			len;
218 	door_cred_t		cred;
219 	picl_prophdl_t		ptreeh;
220 	ptree_propinfo_t	pinfo;
221 
222 	if (door_cred(&cred) < 0)
223 		picld_return_error(in->in.cnum, PICL_FAILURE);
224 
225 	err = cvt_picl2ptree(in->req_attrval.attr, &ptreeh);
226 	if (err != PICL_SUCCESS)
227 		picld_return_error(in->in.cnum, err);
228 
229 	err = ptree_get_propinfo(ptreeh, &pinfo);
230 	if (err != PICL_SUCCESS)
231 		picld_return_error(in->in.cnum, err);
232 
233 	if (!(pinfo.piclinfo.accessmode & PICL_READ))
234 		picld_return_error(in->in.cnum, PICL_NOTREADABLE);
235 
236 	vbufsize = pinfo.piclinfo.size;
237 	vbufsize = MIN((size_t)in->req_attrval.bufsize, vbufsize);
238 
239 	len = sizeof (picl_retattrval_t) + vbufsize;
240 	ret = alloca(len);
241 	if (ret == NULL)
242 		picld_return_error(in->in.cnum, PICL_FAILURE);
243 	ret->cnum = PICL_CNUM_GETATTRVAL;
244 	ret->attr = in->req_attrval.attr;
245 	ret->nbytes = (uint32_t)vbufsize;
246 	err = xptree_get_propval_with_cred(ptreeh, ret->ret_buf, vbufsize,
247 	    cred);
248 	if (err != PICL_SUCCESS)
249 		picld_return_error(in->in.cnum, err);
250 
251 	/*
252 	 * adjust returned bytes for charstrings
253 	 */
254 	if (pinfo.piclinfo.type == PICL_PTYPE_CHARSTRING)
255 		ret->nbytes = (uint32_t)strlen(ret->ret_buf) + 1;
256 
257 	/*
258 	 * convert handle values to picl handles
259 	 */
260 	if ((pinfo.piclinfo.type == PICL_PTYPE_TABLE) ||
261 	    (pinfo.piclinfo.type == PICL_PTYPE_REFERENCE))
262 		cvt_ptree2picl(&ret->ret_nodeh);
263 	(void) rw_unlock(&init_lk);
264 	(void) door_return((char *)ret, sizeof (picl_retattrval_t) +
265 	    (size_t)ret->nbytes, NULL, 0);
266 }
267 
268 /*
269  * This function returns the value of the PICL property specified by
270  * its name.
271  */
272 static void
273 picld_get_attrval_by_name(picl_service_t *in)
274 {
275 	picl_retattrvalbyname_t	*ret;
276 	int			err;
277 	size_t			vbufsize;
278 	size_t			len;
279 	door_cred_t		cred;
280 	picl_nodehdl_t		ptreeh;
281 	ptree_propinfo_t	pinfo;
282 
283 	if (door_cred(&cred) < 0)
284 		picld_return_error(in->in.cnum, PICL_FAILURE);
285 
286 	err = cvt_picl2ptree(in->req_attrvalbyname.nodeh, &ptreeh);
287 	if (err != PICL_SUCCESS)
288 		picld_return_error(in->in.cnum, err);
289 
290 	err = xptree_get_propinfo_by_name(ptreeh,
291 	    in->req_attrvalbyname.propname, &pinfo);
292 	if (err != PICL_SUCCESS)
293 		picld_return_error(in->in.cnum, err);
294 
295 	if (!(pinfo.piclinfo.accessmode & PICL_READ))
296 		picld_return_error(in->in.cnum, PICL_NOTREADABLE);
297 
298 	/*
299 	 * allocate the minimum of piclinfo.size and input bufsize
300 	 */
301 	vbufsize = pinfo.piclinfo.size;
302 	vbufsize = MIN((size_t)in->req_attrvalbyname.bufsize, vbufsize);
303 	len = sizeof (picl_retattrvalbyname_t) + vbufsize;
304 	ret = alloca(len);
305 	if (ret == NULL)
306 		picld_return_error(in->in.cnum, PICL_FAILURE);
307 	ret->cnum = PICL_CNUM_GETATTRVALBYNAME;
308 	ret->nodeh = in->req_attrvalbyname.nodeh;
309 	(void) strcpy(ret->propname, in->req_attrvalbyname.propname);
310 	ret->nbytes = (uint32_t)vbufsize;
311 
312 	err = xptree_get_propval_by_name_with_cred(ptreeh,
313 	    in->req_attrvalbyname.propname, ret->ret_buf, vbufsize,
314 	    cred);
315 	if (err != PICL_SUCCESS)
316 		picld_return_error(in->in.cnum, err);
317 	/*
318 	 * adjust returned value size for charstrings
319 	 */
320 	if (pinfo.piclinfo.type == PICL_PTYPE_CHARSTRING)
321 		ret->nbytes = (uint32_t)strlen(ret->ret_buf) + 1;
322 
323 	if ((pinfo.piclinfo.type == PICL_PTYPE_TABLE) ||
324 	    (pinfo.piclinfo.type == PICL_PTYPE_REFERENCE))
325 		cvt_ptree2picl(&ret->ret_nodeh);
326 
327 	(void) rw_unlock(&init_lk);
328 	(void) door_return((char *)ret, sizeof (picl_retattrvalbyname_t) +
329 	    (size_t)ret->nbytes, NULL, 0);
330 }
331 
332 /*
333  * This function sets a property value
334  */
335 static void
336 picld_set_attrval(picl_service_t *in)
337 {
338 	picl_retsetattrval_t	ret;
339 	int			err;
340 	door_cred_t		cred;
341 	picl_prophdl_t		ptreeh;
342 	ptree_propinfo_t	pinfo;
343 
344 	if (door_cred(&cred) < 0)
345 		picld_return_error(in->in.cnum, PICL_FAILURE);
346 
347 	err = cvt_picl2ptree(in->req_setattrval.attr, &ptreeh);
348 	if (err != PICL_SUCCESS)
349 		picld_return_error(in->in.cnum, err);
350 
351 	err = ptree_get_propinfo(ptreeh, &pinfo);
352 	if (err != PICL_SUCCESS)
353 		picld_return_error(in->in.cnum, err);
354 
355 	if (!(pinfo.piclinfo.accessmode & PICL_WRITE))
356 		picld_return_error(in->in.cnum, PICL_NOTWRITABLE);
357 	/*
358 	 * For non-volatile prop, only super user can set its value.
359 	 */
360 	if (!(pinfo.piclinfo.accessmode & PICL_VOLATILE) &&
361 	    (cred.dc_euid != SUPER_USER))
362 		picld_return_error(in->in.cnum, PICL_PERMDENIED);
363 
364 	ret.cnum = PICL_CNUM_SETATTRVAL;
365 	ret.attr = in->req_setattrval.attr;
366 
367 	err = xptree_update_propval_with_cred(ptreeh, in->req_setattrval.valbuf,
368 	    (size_t)in->req_setattrval.bufsize, cred);
369 
370 	if (err != PICL_SUCCESS)
371 		picld_return_error(in->in.cnum, err);
372 
373 	(void) rw_unlock(&init_lk);
374 	(void) door_return((char *)&ret, sizeof (picl_retsetattrval_t), NULL,
375 	    0);
376 }
377 
378 /*
379  * This function sets the value of a property specified by its name.
380  */
381 static void
382 picld_set_attrval_by_name(picl_service_t *in)
383 {
384 	picl_retsetattrvalbyname_t	ret;
385 	int				err;
386 	door_cred_t			cred;
387 	picl_prophdl_t			ptreeh;
388 	ptree_propinfo_t		pinfo;
389 
390 	if (door_cred(&cred) < 0)
391 		picld_return_error(in->in.cnum, PICL_FAILURE);
392 
393 	err = cvt_picl2ptree(in->req_setattrvalbyname.nodeh, &ptreeh);
394 	if (err != PICL_SUCCESS)
395 		picld_return_error(in->in.cnum, err);
396 
397 	err = xptree_get_propinfo_by_name(ptreeh,
398 	    in->req_setattrvalbyname.propname, &pinfo);
399 	if (err != PICL_SUCCESS)
400 		picld_return_error(in->in.cnum, err);
401 
402 	if (!(pinfo.piclinfo.accessmode & PICL_WRITE))
403 		picld_return_error(in->in.cnum, PICL_NOTWRITABLE);
404 
405 	/*
406 	 * For non-volatile prop, only super user can set its value.
407 	 */
408 	if (!(pinfo.piclinfo.accessmode & PICL_VOLATILE) &&
409 	    (cred.dc_euid != SUPER_USER))
410 		picld_return_error(in->in.cnum, PICL_PERMDENIED);
411 
412 	ret.cnum = PICL_CNUM_SETATTRVALBYNAME;
413 	ret.nodeh = in->req_setattrvalbyname.nodeh;
414 	(void) strcpy(ret.propname, in->req_setattrvalbyname.propname);
415 
416 	err = xptree_update_propval_by_name_with_cred(ptreeh,
417 		in->req_setattrvalbyname.propname,
418 		in->req_setattrvalbyname.valbuf,
419 		(size_t)in->req_setattrvalbyname.bufsize,
420 		cred);
421 
422 	if (err != PICL_SUCCESS)
423 		picld_return_error(in->in.cnum, err);
424 
425 	(void) rw_unlock(&init_lk);
426 	(void) door_return((char *)&ret, sizeof (picl_retsetattrvalbyname_t),
427 	    NULL, 0);
428 }
429 
430 /*
431  * This function returns the property information
432  */
433 static void
434 picld_get_attrinfo(picl_service_t *in)
435 {
436 	picl_retattrinfo_t	ret;
437 	int			err;
438 	ptree_propinfo_t	pinfo;
439 	picl_prophdl_t		ptreeh;
440 
441 	err = cvt_picl2ptree(in->req_attrinfo.attr, &ptreeh);
442 	if (err != PICL_SUCCESS)
443 		picld_return_error(in->in.cnum, err);
444 
445 	ret.cnum = PICL_CNUM_GETATTRINFO;
446 	ret.attr = in->req_attrinfo.attr;
447 
448 	err = ptree_get_propinfo(ptreeh, &pinfo);
449 	if (err != PICL_SUCCESS)
450 		picld_return_error(in->in.cnum, err);
451 
452 	ret.type = pinfo.piclinfo.type;
453 	ret.accessmode = pinfo.piclinfo.accessmode;
454 	ret.size = (uint32_t)pinfo.piclinfo.size;
455 	(void) strcpy(ret.name, pinfo.piclinfo.name);
456 	(void) rw_unlock(&init_lk);
457 	(void) door_return((char *)&ret, sizeof (picl_retattrinfo_t), NULL, 0);
458 }
459 
460 /*
461  * This function returns the node's first property handle
462  */
463 static void
464 picld_get_first_attr(picl_service_t *in)
465 {
466 	picl_retfirstattr_t	ret;
467 	int			err;
468 	picl_prophdl_t		ptreeh;
469 
470 	err = cvt_picl2ptree(in->req_firstattr.nodeh, &ptreeh);
471 	if (err != PICL_SUCCESS)
472 		picld_return_error(in->in.cnum, err);
473 
474 	ret.cnum = PICL_CNUM_GETFIRSTATTR;
475 	ret.nodeh = in->req_firstattr.nodeh;
476 
477 	err = ptree_get_first_prop(ptreeh, &ret.attr);
478 	if (err != PICL_SUCCESS)
479 		picld_return_error(in->in.cnum, err);
480 	cvt_ptree2picl(&ret.attr);
481 	(void) rw_unlock(&init_lk);
482 	(void) door_return((char *)&ret, sizeof (picl_retfirstattr_t), NULL, 0);
483 }
484 
485 /*
486  * This function returns the next property handle in list
487  */
488 static void
489 picld_get_next_attr(picl_service_t *in)
490 {
491 	picl_retnextattr_t	ret;
492 	int			err;
493 	picl_prophdl_t		ptreeh;
494 
495 	err = cvt_picl2ptree(in->req_nextattr.attr, &ptreeh);
496 	if (err != PICL_SUCCESS)
497 		picld_return_error(in->in.cnum, err);
498 
499 	ret.cnum = PICL_CNUM_GETNEXTATTR;
500 	ret.attr = in->req_nextattr.attr;
501 
502 	err = ptree_get_next_prop(ptreeh, &ret.nextattr);
503 	if (err != PICL_SUCCESS)
504 		picld_return_error(in->in.cnum, err);
505 
506 	cvt_ptree2picl(&ret.nextattr);
507 
508 	(void) rw_unlock(&init_lk);
509 	(void) door_return((char *)&ret, sizeof (picl_retnextattr_t), NULL, 0);
510 }
511 
512 /*
513  * This function returns the handle of a property specified by its name
514  */
515 static void
516 picld_get_attr_by_name(picl_service_t *in)
517 {
518 	picl_retattrbyname_t	ret;
519 	int			err;
520 	picl_prophdl_t		ptreeh;
521 
522 	err = cvt_picl2ptree(in->req_attrbyname.nodeh, &ptreeh);
523 	if (err != PICL_SUCCESS)
524 		picld_return_error(in->in.cnum, err);
525 
526 	ret.cnum = PICL_CNUM_GETATTRBYNAME;
527 	ret.nodeh = in->req_attrbyname.nodeh;
528 	(void) strcpy(ret.propname, in->req_attrbyname.propname);
529 
530 	err = ptree_get_prop_by_name(ptreeh, ret.propname, &ret.attr);
531 	if (err != PICL_SUCCESS)
532 		picld_return_error(in->in.cnum, err);
533 
534 	cvt_ptree2picl(&ret.attr);
535 	(void) rw_unlock(&init_lk);
536 	(void) door_return((char *)&ret, sizeof (picl_retattrbyname_t), NULL,
537 	    0);
538 }
539 
540 /*
541  * This function gets the next property on the same row in the table
542  */
543 static void
544 picld_get_attr_by_row(picl_service_t *in)
545 {
546 	picl_retattrbyrow_t	ret;
547 	int			err;
548 	picl_prophdl_t		ptreeh;
549 
550 	err = cvt_picl2ptree(in->req_attrbyrow.attr, &ptreeh);
551 	if (err != PICL_SUCCESS)
552 		picld_return_error(in->in.cnum, err);
553 
554 	ret.cnum = PICL_CNUM_GETATTRBYROW;
555 	ret.attr = in->req_attrbyrow.attr;
556 
557 	err = ptree_get_next_by_row(ptreeh, &ret.rowattr);
558 	if (err != PICL_SUCCESS)
559 		picld_return_error(in->in.cnum, err);
560 	cvt_ptree2picl(&ret.rowattr);
561 
562 	(void) rw_unlock(&init_lk);
563 	(void) door_return((char *)&ret, sizeof (picl_retattrbyrow_t), NULL, 0);
564 }
565 
566 /*
567  * This function returns the handle of the next property in the same column
568  * of the table.
569  */
570 static void
571 picld_get_attr_by_col(picl_service_t *in)
572 {
573 	picl_retattrbycol_t	ret;
574 	int			err;
575 	picl_prophdl_t		ptreeh;
576 
577 	err = cvt_picl2ptree(in->req_attrbycol.attr, &ptreeh);
578 	if (err != PICL_SUCCESS)
579 		picld_return_error(in->in.cnum, err);
580 
581 	ret.cnum = PICL_CNUM_GETATTRBYCOL;
582 	ret.attr = in->req_attrbycol.attr;
583 
584 	err = ptree_get_next_by_col(ptreeh, &ret.colattr);
585 	if (err != PICL_SUCCESS)
586 		picld_return_error(in->in.cnum, err);
587 
588 	cvt_ptree2picl(&ret.colattr);
589 
590 	(void) rw_unlock(&init_lk);
591 	(void) door_return((char *)&ret, sizeof (picl_retattrbycol_t), NULL, 0);
592 }
593 
594 /*
595  * This function finds the node in the PICLTREE that matches the given
596  * criteria and returns its handle.
597  */
598 static void
599 picld_find_node(picl_service_t *in)
600 {
601 	picl_retfindnode_t	ret;
602 	int			err;
603 	picl_nodehdl_t		ptreeh;
604 
605 	err = cvt_picl2ptree(in->req_findnode.nodeh, &ptreeh);
606 	if (err != PICL_SUCCESS)
607 		picld_return_error(in->in.cnum, err);
608 
609 	ret.cnum = PICL_CNUM_FINDNODE;
610 
611 	err = ptree_find_node(ptreeh, in->req_findnode.propname,
612 	    in->req_findnode.ptype, in->req_findnode.valbuf,
613 	    in->req_findnode.valsize, &ret.rnodeh);
614 	if (err != PICL_SUCCESS)
615 		picld_return_error(in->in.cnum, err);
616 
617 	cvt_ptree2picl(&ret.rnodeh);
618 
619 	(void) rw_unlock(&init_lk);
620 	(void) door_return((char *)&ret, sizeof (ret), NULL, 0);
621 }
622 
623 /*
624  * This function finds the property/node that corresponds to the given path
625  * and returns its handle
626  */
627 static void
628 picld_get_node_by_path(picl_service_t *in)
629 {
630 	picl_retnodebypath_t	ret;
631 	int			err;
632 
633 	ret.cnum = PICL_CNUM_NODEBYPATH;
634 	err = ptree_get_node_by_path(in->req_nodebypath.pathbuf, &ret.nodeh);
635 	if (err != PICL_SUCCESS)
636 		picld_return_error(in->in.cnum, err);
637 	cvt_ptree2picl(&ret.nodeh);
638 	(void) rw_unlock(&init_lk);
639 	(void) door_return((char *)&ret, sizeof (ret), NULL, 0);
640 }
641 
642 /*
643  * This function returns finds the frutree parent node for a given node
644  * and returns its handle
645  */
646 static void
647 picld_get_frutree_parent(picl_service_t *in)
648 {
649 	picl_retfruparent_t	ret;
650 	int			err;
651 	picl_nodehdl_t		ptreeh;
652 
653 	err = cvt_picl2ptree(in->req_fruparent.devh, &ptreeh);
654 	if (err != PICL_SUCCESS)
655 		picld_return_error(in->in.cnum, err);
656 
657 	ret.cnum = PICL_CNUM_FRUTREEPARENT;
658 
659 	err = ptree_get_frutree_parent(ptreeh, &ret.fruh);
660 	if (err != PICL_SUCCESS)
661 		picld_return_error(in->in.cnum, err);
662 	cvt_ptree2picl(&ret.fruh);
663 
664 	(void) rw_unlock(&init_lk);
665 	(void) door_return((char *)&ret, sizeof (ret), NULL, 0);
666 }
667 
668 /*
669  * This function is called when an unknown client request is received.
670  */
671 static void
672 picld_unknown_service(picl_service_t *in)
673 {
674 	picld_return_error(in->in.cnum, PICL_UNKNOWNSERVICE);
675 }
676 
677 static void
678 check_denial_of_service(int cnum)
679 {
680 	hrtime_t	window;
681 	hrtime_t	current;
682 	int		dos_flag;
683 
684 	current = gethrtime();
685 	dos_flag = 0;
686 
687 	if (pthread_mutex_lock(&dos_mutex) != 0)
688 		picld_return_error(cnum, PICL_FAILURE);
689 
690 	++service_requests;
691 	window = current - orig_time;
692 	if (window > MILLI_TO_NANO(sliding_interval_ms)) {
693 		orig_time = current;
694 		service_requests = 1;
695 	}
696 
697 	if (service_requests > dos_req_limit)
698 		dos_flag = 1;
699 
700 	if (pthread_mutex_unlock(&dos_mutex) != 0)
701 		picld_return_error(cnum, PICL_FAILURE);
702 
703 	if (dos_flag)
704 		(void) poll(NULL, 0, dos_ms);
705 }
706 
707 
708 /* ARGSUSED */
709 static void
710 picld_door_handler(void *cookie, char *argp, size_t asize,
711     door_desc_t *dp, uint_t n_desc)
712 {
713 	picl_service_t  *req;
714 
715 	/*LINTED*/
716 	req = (picl_service_t *)argp;
717 
718 	if (req == NULL)
719 		(void) door_return((char *)req, 0, NULL, 0);
720 
721 	check_denial_of_service(req->in.cnum);
722 
723 	(void) rw_rdlock(&init_lk);
724 	switch (req->in.cnum) {	/* client call number */
725 	case PICL_CNUM_INIT:
726 		/*LINTED*/
727 		picld_init((picl_service_t *)argp);
728 		break;
729 	case PICL_CNUM_FINI:
730 		/*LINTED*/
731 		picld_fini((picl_service_t *)argp);
732 		break;
733 	case PICL_CNUM_GETROOT:
734 		/*LINTED*/
735 		picld_getroot((picl_service_t *)argp);
736 		break;
737 	case PICL_CNUM_GETATTRVAL:
738 		/*LINTED*/
739 		picld_get_attrval((picl_service_t *)argp);
740 		break;
741 	case PICL_CNUM_GETATTRVALBYNAME:
742 		/*LINTED*/
743 		picld_get_attrval_by_name((picl_service_t *)argp);
744 		break;
745 	case PICL_CNUM_GETATTRINFO:
746 		/*LINTED*/
747 		picld_get_attrinfo((picl_service_t *)argp);
748 		break;
749 	case PICL_CNUM_GETFIRSTATTR:
750 		/*LINTED*/
751 		picld_get_first_attr((picl_service_t *)argp);
752 		break;
753 	case PICL_CNUM_GETNEXTATTR:
754 		/*LINTED*/
755 		picld_get_next_attr((picl_service_t *)argp);
756 		break;
757 	case PICL_CNUM_GETATTRBYNAME:
758 		/*LINTED*/
759 		picld_get_attr_by_name((picl_service_t *)argp);
760 		break;
761 	case PICL_CNUM_GETATTRBYROW:
762 		/*LINTED*/
763 		picld_get_attr_by_row((picl_service_t *)argp);
764 		break;
765 	case PICL_CNUM_GETATTRBYCOL:
766 		/*LINTED*/
767 		picld_get_attr_by_col((picl_service_t *)argp);
768 		break;
769 	case PICL_CNUM_SETATTRVAL:
770 		/*LINTED*/
771 		picld_set_attrval((picl_service_t *)argp);
772 		break;
773 	case PICL_CNUM_SETATTRVALBYNAME:
774 		/*LINTED*/
775 		picld_set_attrval_by_name((picl_service_t *)argp);
776 		break;
777 	case PICL_CNUM_PING:
778 		/*LINTED*/
779 		picld_ping((picl_service_t *)argp);
780 		break;
781 	case PICL_CNUM_WAIT:
782 		/*LINTED*/
783 		picld_wait((picl_service_t *)argp);
784 		break;
785 	case PICL_CNUM_FINDNODE:
786 		/*LINTED*/
787 		picld_find_node((picl_service_t *)argp);
788 		break;
789 	case PICL_CNUM_NODEBYPATH:
790 		/*LINTED*/
791 		picld_get_node_by_path((picl_service_t *)argp);
792 		break;
793 	case PICL_CNUM_FRUTREEPARENT:
794 		/*LINTED*/
795 		picld_get_frutree_parent((picl_service_t *)argp);
796 		break;
797 	default:
798 		/*LINTED*/
799 		picld_unknown_service((picl_service_t *)argp);
800 		break;
801 	};
802 	/*NOTREACHED*/
803 }
804 
805 /* ARGSUSED */
806 static void
807 hup_handler(int sig, siginfo_t *siginfo, void *sigctx)
808 {
809 	doreinit = 1;
810 }
811 
812 /*
813  * "ping" to see if a daemon is already running
814  */
815 static int
816 daemon_exists(void)
817 {
818 	door_arg_t	darg;
819 	picl_reqping_t	req_ping;
820 	picl_retping_t	ret_ping;
821 	int		doorh;
822 	door_info_t	dinfo;
823 
824 	doorh = open(PICLD_DOOR, O_RDONLY);
825 	if (doorh < 0)
826 		return (0);
827 
828 	if (door_info(doorh, &dinfo) < 0) {
829 		(void) close(doorh);
830 		return (0);
831 	}
832 
833 	if ((dinfo.di_attributes & DOOR_REVOKED) ||
834 	    (dinfo.di_data != (uintptr_t)PICLD_DOOR_COOKIE)) {
835 		(void) close(doorh);
836 		return (0);
837 	}
838 
839 	if (dinfo.di_target != getpid()) {
840 		(void) close(doorh);
841 		return (1);
842 	}
843 
844 	req_ping.cnum = PICL_CNUM_PING;
845 
846 	darg.data_ptr = (char *)&req_ping;
847 	darg.data_size = sizeof (picl_reqping_t);
848 	darg.desc_ptr = NULL;
849 	darg.desc_num = 0;
850 	darg.rbuf = (char *)&ret_ping;
851 	darg.rsize = sizeof (picl_retping_t);
852 
853 	if (door_call(doorh, &darg) < 0) {
854 		(void) close(doorh);
855 		return (0);
856 	}
857 
858 	(void) close(doorh);
859 	return (1);
860 }
861 
862 /*
863  * Create the picld door
864  */
865 static int
866 setup_door(void)
867 {
868 	struct stat	stbuf;
869 
870 	/*
871 	 * Create the door
872 	 */
873 	door_id = door_create(picld_door_handler, PICLD_DOOR_COOKIE,
874 	    DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
875 
876 	if (door_id < 0) {
877 		return (-1);
878 	}
879 
880 	if (stat(PICLD_DOOR, &stbuf) < 0) {
881 		int newfd;
882 		if ((newfd = creat(PICLD_DOOR, 0444)) < 0)
883 			return (-1);
884 		(void) close(newfd);
885 	}
886 
887 	if (fattach(door_id, PICLD_DOOR) < 0) {
888 		if ((errno != EBUSY) ||
889 		    (fdetach(PICLD_DOOR) < 0) ||
890 		    (fattach(door_id, PICLD_DOOR) < 0))
891 			return (-1);
892 	}
893 
894 	return (0);
895 }
896 
897 /*
898  * Main function of picl daemon
899  */
900 int
901 main(int argc, char **argv)
902 {
903 	struct	sigaction	act;
904 	int			c;
905 	sigset_t		ublk;
906 
907 
908 	(void) setlocale(LC_ALL, "");
909 	(void) textdomain(TEXT_DOMAIN);
910 
911 	if (getuid() != 0) {
912 		syslog(LOG_CRIT, MUST_BE_ROOT);
913 		return (0);
914 	}
915 
916 	(void) rwlock_init(&init_lk, USYNC_THREAD, NULL);
917 	doreinit = 0;
918 	logflag = 1;
919 	dos_req_limit = DOS_PICL_REQUESTS_LIMIT;
920 	sliding_interval_ms = SLIDING_INTERVAL_MILLISECONDS;
921 	dos_ms = DOS_SLEEPTIME_MS;
922 	verbose_level = 0;
923 
924 	/*
925 	 * parse arguments
926 	 */
927 	while ((c = getopt(argc, argv, "is:t:l:r:v:d:")) != EOF) {
928 		switch (c) {
929 		case 'd':
930 			dos_ms = strtol(optarg, (char **)NULL, 0);
931 			break;
932 		case 'i':
933 			logflag = 0;
934 			break;
935 		case 's':
936 			sliding_interval_ms = strtoll(optarg, (char **)NULL, 0);
937 			break;
938 		case 't':
939 			dos_req_limit = strtol(optarg, (char **)NULL, 0);
940 			break;
941 		case 'v':
942 			verbose_level = strtol(optarg, (char **)NULL, 0);
943 			logflag = 0;
944 			break;
945 		default:
946 			break;
947 		}
948 	}
949 
950 	orig_time = gethrtime();
951 
952 	/*
953 	 * is there a daemon already running?
954 	 */
955 
956 	if (daemon_exists()) {
957 		syslog(LOG_CRIT, DAEMON_RUNNING);
958 		exit(1);
959 	}
960 
961 	/*
962 	 * Mask off/block SIGALRM signal so that the environmental plug-in
963 	 * (piclenvd) can use it to simulate sleep() without being affected
964 	 * by time being set back. No other PICL plug-in should use SIGALRM
965 	 * or alarm() for now.
966 	 */
967 	(void) sigemptyset(&ublk);
968 	(void) sigaddset(&ublk, SIGALRM);
969 	(void) sigprocmask(SIG_BLOCK, &ublk, NULL);
970 
971 	/*
972 	 * Ignore SIGHUP until all the initialization is done.
973 	 */
974 	act.sa_handler = SIG_IGN;
975 	(void) sigemptyset(&act.sa_mask);
976 	act.sa_flags = 0;
977 	if (sigaction(SIGHUP, &act, NULL) == -1)
978 		syslog(LOG_ERR, SIGACT_FAILED, strsignal(SIGHUP),
979 		    strerror(errno));
980 
981 	if (logflag != 0) {	/* daemonize */
982 		pid_t pid;
983 
984 		pid = fork();
985 		if (pid < 0)
986 			exit(1);
987 		if (pid > 0)
988 			/* parent */
989 			exit(0);
990 
991 		/* child */
992 		if (chdir("/") == -1) {
993 			syslog(LOG_CRIT, CD_ROOT_FAILED);
994 			exit(1);
995 		}
996 
997 		(void) setsid();
998 		(void) close(STDIN_FILENO);
999 		(void) close(STDOUT_FILENO);
1000 		(void) close(STDERR_FILENO);
1001 		(void) open("/dev/null", O_RDWR, 0);
1002 		(void) dup2(STDIN_FILENO, STDOUT_FILENO);
1003 		(void) dup2(STDIN_FILENO, STDERR_FILENO);
1004 		openlog(PICLD, LOG_PID, LOG_DAEMON);
1005 	}
1006 
1007 	/*
1008 	 * Initialize the PICL Tree
1009 	 */
1010 	if (xptree_initialize(NULL) != PICL_SUCCESS) {
1011 		syslog(LOG_CRIT, INIT_FAILED);
1012 		exit(1);
1013 	}
1014 
1015 	if (setup_door()) {
1016 		syslog(LOG_CRIT, DOOR_FAILED);
1017 		exit(1);
1018 	}
1019 
1020 	/*
1021 	 * setup signal handlers for post-init
1022 	 */
1023 	act.sa_sigaction = hup_handler;
1024 	(void) sigemptyset(&act.sa_mask);
1025 	act.sa_flags = SA_SIGINFO;
1026 	if (sigaction(SIGHUP, &act, NULL) == -1)
1027 		syslog(LOG_ERR, SIGACT_FAILED, strsignal(SIGHUP),
1028 		    strerror(errno));
1029 
1030 	/*
1031 	 * wait for requests
1032 	 */
1033 	for (;;) {
1034 		(void) pause();
1035 		if (doreinit) {
1036 			/*
1037 			 * Block SIGHUP during reinitialization.
1038 			 * Also mask off/block SIGALRM signal so that the
1039 			 * environmental plug-in (piclenvd) can use it to
1040 			 * simulate sleep() without being affected by time
1041 			 * being set back. No ohter PICL plug-in should use
1042 			 * SIGALRM or alarm() for now.
1043 			 */
1044 			(void) sigemptyset(&ublk);
1045 			(void) sigaddset(&ublk, SIGHUP);
1046 			(void) sigaddset(&ublk, SIGALRM);
1047 			(void) sigprocmask(SIG_BLOCK, &ublk, NULL);
1048 			(void) sigdelset(&ublk, SIGALRM);
1049 			doreinit = 0;
1050 			(void) rw_wrlock(&init_lk);
1051 			xptree_destroy();
1052 			(void) xptree_reinitialize();
1053 			(void) rw_unlock(&init_lk);
1054 			(void) sigprocmask(SIG_UNBLOCK, &ublk, NULL);
1055 		}
1056 	}
1057 }
1058