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