xref: /illumos-gate/usr/src/cmd/picl/plugins/sun4u/psvc/psvcplugin/psvcplugin.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
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  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * PICL plug-in to create environment tree nodes.
28  * This plugin should only be installed in the platform directories
29  * of supported systems, such as /usr/platform/picl/plugins/SUNW,<>.
30  */
31 
32 #include <picl.h>
33 #include <picltree.h>
34 #include <stdio.h>
35 #include <time.h>
36 #include <dlfcn.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <stdlib.h>
40 #include <limits.h>
41 #include  <ctype.h>
42 #include <pthread.h>
43 #include <libintl.h>
44 #include <errno.h>
45 #include <semaphore.h>
46 #include <sched.h>
47 #include <syslog.h>
48 #include <string.h>
49 #include <signal.h>
50 #include <sys/types.h>
51 #include <sys/systeminfo.h>
52 #include <psvc_objects.h>
53 #include <psvc_objects_class.h>
54 
55 #define	BUFSZ	512
56 
57 typedef struct {
58 	char	name[32];
59 } EName_t;
60 
61 typedef struct {
62 	void *hdl;
63 	int32_t (*funcp)(void *, char *);
64 	int32_t	num_objects;
65 	EName_t *obj_list;
66 	char    routine[64];
67 } ETask_t;
68 
69 typedef struct interval_info {
70 	volatile int32_t   interval;
71 	int32_t	  num_tasks;
72 	ETask_t   *task_list;
73 	pthread_t thread;
74 	int32_t   has_thread;
75 	struct interval_info *next;
76 } EInterval_t;
77 
78 static EInterval_t *first_interval;
79 
80 static psvc_opaque_t hdlp;
81 
82 sem_t timer_sem;
83 pthread_mutex_t timer_mutex;
84 pthread_cond_t timer_cond;
85 pthread_t timer_thread_id;
86 
87 extern int ptree_get_node_by_path(const char *, picl_nodehdl_t *);
88 
89 /* Timer states */
90 #define	NOT_READY	0
91 #define	READY		1
92 #define	HAVE_REQUEST	2
93 #define	ACTIVE		3
94 #define	TIMER_SHUTDOWN	4
95 
96 int timer_state = NOT_READY;
97 
98 int app_timeout;
99 
100 /* Lock State Loop State Definitions */
101 #define	STATE_CHANGED		1
102 #define	STATE_NOT_CHANGED	0
103 
104 #ifdef DEBUG
105 static int32_t debug_flag = 1;
106 #else
107 static int32_t debug_flag = 0;
108 #endif
109 
110 static char library[PATH_MAX];
111 
112 #define	PSVC_PLUGIN_VERSION	PICLD_PLUGIN_VERSION_1
113 
114 #pragma init(psvc_plugin_register)	/* place in .init section */
115 
116 typedef struct  {
117 	char	parent_path[256];
118 	char    child_name[32];
119 	picl_nodehdl_t	child_node;
120 } psvc_name_t;
121 psvc_name_t *psvc_paths;
122 
123 #define	MUTEX_LOCK_FAILED_MSG	gettext("platsvcd: pthread_mutex_lock %s\n")
124 #define	CV_WAIT_FAILED_MSG	gettext("platsvcd: pthread_cond_wait %s\n")
125 #define	CV_TWAIT_FAILED_MSG gettext("platsvcd: pthread_cond_timed_wait %s\n")
126 #define	SEM_WAIT_FAILED_MSG	gettext("platsvcd: sem_wait failed %s\n")
127 #define	PSVC_APP_DEATH_MSG	gettext("PSVC application death detected\n")
128 #define	POLICY_FAILED_MSG	gettext("ERROR running %s on %s (%d)")
129 #define	ID_NOT_FOUND_MSG	gettext("%s: Can't determine id of %s\n")
130 #define	CLASS_NOT_FOUND_MSG	gettext("%s: Can't determine class of %s\n")
131 #define	SUBCLASS_NOT_FOUND_MSG	gettext("%s: Can't determine subclass of %s\n")
132 #define	NODE_NOT_FOUND_MSG	gettext("%s: Can't determine node of %s\n")
133 #define	SIZE_NOT_FOUND_MSG	gettext("%s: Couldn't determine size of %s\n")
134 #define	PTREE_CREATE_TABLE_FAILED_MSG		\
135 	gettext("%s: ptree_create_table failed, %s\n")
136 #define	PTREE_CREATE_PROP_FAILED_MSG		\
137 	gettext("%s: ptree_create_prop failed, %s\n")
138 #define	PTREE_CREATE_NODE_FAILED_MSG		\
139 	gettext("%s: ptree_create_node failed, %s\n")
140 #define	PTREE_ADD_ROW_FAILED_MSG gettext("%s: ptree_add_row_to_table: %s\n")
141 #define	PTREE_ADD_NODE_FAILED_MSG gettext("%s: ptree_add_node: %s\n")
142 #define	PTREE_ADD_PROP_FAILED_MSG gettext("%s: ptree_add_prop: %s\n")
143 #define	PTREE_GET_ROOT_FAILED_MSG gettext("%s: ptree_get_root: %s\n")
144 #define	CREATE_PROP_FAILED_MSG	gettext("%s: Error creating property %s\n")
145 #define	INVALID_FILE_FORMAT_MSG		gettext("%s: Invalid file format\n")
146 #define	INVALID_FILE_FORMAT1_MSG	gettext("%s: Invalid file format %s\n")
147 #define	PSVC_INIT_ERR_MSG	gettext("%s: Error in psvc_init(): %s\n")
148 #define	SYSINFO_FAILED_MSG	gettext("%s: Can't determine platform type\n")
149 #define	FILE_OPEN_FAILED_MSG	gettext("%s: Can't open file %s\n")
150 #define	MALLOC_FAILED_MSG	gettext("%s: malloc failed, %s\n")
151 #define	UNKNOWN_CLASS_MSG	gettext("%s: Unknown class\n")
152 #define	NODE_PROP_FAILED_MSG	gettext("%s: node_property: %s\n")
153 
154 #define	LOCK_STRING_MAX 32
155 
156 picl_nodehdl_t system_node;
157 static picl_nodehdl_t lock_node;
158 static char env_lock_state[LOCK_STRING_MAX] = PSVC_LOCK_ENABLED;
159 static pthread_mutex_t env_lock_mutex;
160 
161 static char *class_name[] = {
162 "temperature-sensor",
163 "fan",
164 "led",
165 "picl",
166 "digital-sensor",
167 "digital-control",
168 "gpio",
169 "fan-tachometer",
170 "switch",
171 "keyswitch",
172 "gpio",
173 "i2c"
174 };
175 #define	NUM_CLASSES (sizeof (class_name) / sizeof (char *))
176 
177 struct proj_prop {	/* projected property */
178 	picl_prophdl_t	handle;
179 	picl_nodehdl_t  dst_node;
180 	char		name[32];
181 };
182 
183 struct propinfo {
184 	char		*name;
185 	uint32_t	type;
186 	uint32_t	size;
187 	uint32_t	access;
188 };
189 
190 struct propinfo common[] = {
191 	{"State", PICL_PTYPE_CHARSTRING, 32,
192 	PICL_READ | PICL_WRITE | PICL_VOLATILE},
193 	{"FaultInformation", PICL_PTYPE_CHARSTRING, 32,
194 	PICL_READ | PICL_VOLATILE}
195 };
196 #define	COMMON_COUNT (sizeof (common) / sizeof (struct propinfo))
197 
198 struct propinfo led_properties[] = {
199 	{"Color", PICL_PTYPE_CHARSTRING, 32, PICL_READ | PICL_VOLATILE},
200 	{"IsLocator", PICL_PTYPE_CHARSTRING, 32, PICL_READ | PICL_VOLATILE},
201 	{"LocatorName", PICL_PTYPE_CHARSTRING, 32, PICL_READ | PICL_VOLATILE}
202 };
203 /*
204  * We define the amount of LED properties to 1 because not all LED's have
205  * the two remainding properties.  This number is augmented in psvc_plugin_init
206  * when it sees an LED of subclass 2.
207  */
208 #define	LED_COUNT 1
209 
210 struct propinfo temperature_sensor_properties[] = {
211 	{"Temperature", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE},
212 	{"LowWarningThreshold", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE},
213 	{"LowShutdownThreshold", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE},
214 	{"HighWarningThreshold", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE},
215 	{"HighShutdownThreshold", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE}
216 };
217 #define	TEMP_SENSOR_COUNT \
218 	(sizeof (temperature_sensor_properties) / sizeof (struct propinfo))
219 
220 struct propinfo digi_sensor_properties[] = {
221 	{"AtoDSensorValue", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE},
222 	{"LowWarningThreshold", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE},
223 	{"LowShutdownThreshold", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE},
224 	{"HighWarningThreshold", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE},
225 	{"HighShutdownThreshold", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE}
226 };
227 #define	DIGI_SENSOR_COUNT \
228 	(sizeof (digi_sensor_properties) / sizeof (struct propinfo))
229 
230 struct propinfo boolgpio_properties[] = {
231 	{"Gpio-value", PICL_PTYPE_UNSIGNED_INT, sizeof (boolean_t),
232 	PICL_READ | PICL_WRITE | PICL_VOLATILE},
233 	{"#Bits", PICL_PTYPE_UNSIGNED_INT, 4, PICL_READ |PICL_VOLATILE}
234 };
235 #define	BOOLGPIO_COUNT (sizeof (boolgpio_properties) / sizeof (struct propinfo))
236 
237 struct propinfo gpio8_properties[] = {
238 	{"Gpio-value", PICL_PTYPE_UNSIGNED_INT, 1,
239 	PICL_READ | PICL_WRITE | PICL_VOLATILE},
240 	{"#Bits", PICL_PTYPE_UNSIGNED_INT, 4, PICL_READ |PICL_VOLATILE}
241 };
242 #define	GPIO8_COUNT (sizeof (gpio8_properties) / sizeof (struct propinfo))
243 
244 struct propinfo digictrl_properties[] = {
245 	{"DtoAControlValue", PICL_PTYPE_INT, 4,
246 	PICL_READ | PICL_WRITE | PICL_VOLATILE},
247 };
248 #define	DIGICTRL_COUNT (sizeof (digictrl_properties) / sizeof (struct propinfo))
249 
250 struct classinfo {
251 	struct propinfo	*props;
252 	int32_t		count;
253 } class_properties[] =
254 {
255 	{temperature_sensor_properties, TEMP_SENSOR_COUNT}, /* temp sensor */
256 	{0, 0},				/* fan, only has projected properties */
257 	{led_properties, LED_COUNT},
258 	{0, 0},						  /* system class */
259 	{digi_sensor_properties, DIGI_SENSOR_COUNT}, /* digital sensor */
260 	{digictrl_properties, DIGICTRL_COUNT},
261 	{boolgpio_properties, BOOLGPIO_COUNT},
262 	{digi_sensor_properties, DIGI_SENSOR_COUNT}, /* fan tach */
263 	{0, 0},
264 	{0, 0},
265 	{gpio8_properties, GPIO8_COUNT},
266 	{0, 0},
267 };
268 
269 struct prop_trans {
270 	char *picl_class;
271 	char *picl_prop;
272 	int32_t psvc_prop;
273 } picl_prop_trans[] =
274 {
275 	{"digital-sensor", "AtoDSensorValue", PSVC_SENSOR_VALUE_ATTR},
276 	{"digital-sensor", "LowWarningThreshold", PSVC_LO_WARN_ATTR},
277 	{"digital-sensor", "LowShutdownThreshold", PSVC_LO_SHUT_ATTR},
278 	{"digital-sensor", "HighWarningThreshold", PSVC_HI_WARN_ATTR},
279 	{"digital-sensor", "HighShutdownThreshold", PSVC_HI_SHUT_ATTR},
280 	{"digital-control", "DtoAControlValue", PSVC_CONTROL_VALUE_ATTR},
281 	{"fan-tachometer", "AtoDSensorValue", PSVC_SENSOR_VALUE_ATTR},
282 	{"fan-tachometer", "LowWarningThreshold", PSVC_LO_WARN_ATTR},
283 	{"fan-tachometer", "LowShutdownThreshold", PSVC_LO_SHUT_ATTR},
284 	{"fan-tachometer", "HighWarningThreshold", PSVC_HI_WARN_ATTR},
285 	{"fan-tachometer", "HighShutdownThreshold", PSVC_HI_SHUT_ATTR},
286 	{"temperature-sensor", "Temperature", PSVC_SENSOR_VALUE_ATTR},
287 	{"temperature-sensor", "LowWarningThreshold", PSVC_LO_WARN_ATTR},
288 	{"temperature-sensor", "LowShutdownThreshold", PSVC_LO_SHUT_ATTR},
289 	{"temperature-sensor", "HighWarningThreshold", PSVC_HI_WARN_ATTR},
290 	{"temperature-sensor", "HighShutdownThreshold", PSVC_HI_SHUT_ATTR},
291 	{"led", "State", PSVC_LED_STATE_ATTR},
292 	{"led", "Color", PSVC_LED_COLOR_ATTR},
293 	{"switch", "State", PSVC_SWITCH_STATE_ATTR},
294 	{"keyswitch", "State", PSVC_SWITCH_STATE_ATTR},
295 	{"i2c", "State", PSVC_PROBE_RESULT_ATTR}
296 };
297 
298 #define	PICL_PROP_TRANS_COUNT \
299 	(sizeof (picl_prop_trans) / sizeof (struct prop_trans))
300 
301 
302 typedef struct {
303 	char		name[32];
304 	picl_nodehdl_t	node;
305 } picl_psvc_t;
306 
307 struct assoc_pair {
308 	char	antecedent[32];
309 	char	dependent[32];
310 };
311 
312 struct handle {
313 	uint32_t    obj_count;
314 	picl_psvc_t *objects;
315 	FILE	*fp;
316 } psvc_hdl;
317 
318 struct proj_prop *prop_list;
319 uint32_t proj_prop_count;
320 
321 int psvc_picl_nodes;
322 
323 void psvc_plugin_init(void);
324 void psvc_plugin_fini(void);
325 
326 picld_plugin_reg_t psvc_reg = {
327 	PSVC_PLUGIN_VERSION,
328 	PICLD_PLUGIN_CRITICAL,
329 	"PSVC",
330 	psvc_plugin_init,
331 	psvc_plugin_fini
332 };
333 
334 /*
335  * psvcplugin_add_children was written so that devices which are hotplugable
336  * will be able to add in all thier children and children's children. The
337  * routine takes in the path of a parent and then searches the psvc_paths
338  * array to find all of it's children.  It in turns adds the child and then
339  * recursively check to see if it had children and add them too.
340  */
341 void
342 psvcplugin_add_children(char *parent_path)
343 {
344 	int i;
345 	picl_nodehdl_t parent_node;
346 	char next_path[256];
347 
348 	for (i = 0; i < psvc_picl_nodes; ++i) {
349 		if (strcmp(parent_path, psvc_paths[i].parent_path) == 0) {
350 			ptree_get_node_by_path(parent_path, &parent_node);
351 			ptree_add_node(parent_node, psvc_paths[i].child_node);
352 			(void) snprintf(next_path, sizeof (next_path), "%s/%s",
353 			    parent_path, psvc_paths[i].child_name);
354 			psvcplugin_add_children(next_path);
355 		}
356 	}
357 }
358 
359 void
360 psvcplugin_lookup(char *name, char *parent, picl_nodehdl_t *node)
361 {
362 	int i;
363 
364 	for (i = 0; i < psvc_picl_nodes; ++i) {
365 		if (strcmp(name, psvc_paths[i].child_name) == 0) {
366 			(void) strcpy(parent, psvc_paths[i].parent_path);
367 			*node = psvc_paths[i].child_node;
368 		}
369 	}
370 }
371 
372 void
373 timer_thread(void)
374 {
375 	struct timespec timeout;
376 	int status;
377 
378 
379 	status = pthread_mutex_lock(&timer_mutex);
380 	if (status != 0) {
381 		syslog(LOG_ERR, MUTEX_LOCK_FAILED_MSG, strerror(status));
382 	}
383 
384 	for (;;) {
385 		/* wait for thread to tell us to start timer */
386 		timer_state = READY;
387 		do {
388 			status = pthread_cond_wait(&timer_cond, &timer_mutex);
389 		} while (timer_state == READY && status == 0);
390 
391 		if (timer_state == TIMER_SHUTDOWN) {
392 			pthread_exit(NULL);
393 			/* not reached */
394 		}
395 
396 		if (status != 0) {
397 			syslog(LOG_ERR, CV_WAIT_FAILED_MSG, strerror(status));
398 		}
399 
400 		/*
401 		 * Will get signalled after semaphore acquired,
402 		 * or when timeout occurs.
403 		 */
404 		(void) clock_gettime(CLOCK_REALTIME, &timeout);
405 		timeout.tv_sec += app_timeout;
406 
407 		if (timer_state == HAVE_REQUEST) {
408 			timer_state = ACTIVE;
409 			do {
410 				status = pthread_cond_timedwait(&timer_cond,
411 				    &timer_mutex, &timeout);
412 			} while (timer_state == ACTIVE && status == 0);
413 		}
414 
415 		if (status != 0) {
416 			if (status == ETIMEDOUT) {
417 				syslog(LOG_ERR, PSVC_APP_DEATH_MSG);
418 				(void) pthread_mutex_lock(&env_lock_mutex);
419 				(void) strlcpy(env_lock_state,
420 				    PSVC_LOCK_ENABLED, LOCK_STRING_MAX);
421 				(void) pthread_mutex_unlock(&env_lock_mutex);
422 			} else {
423 				syslog(LOG_ERR, CV_TWAIT_FAILED_MSG,
424 				    strerror(status));
425 			}
426 		}
427 	}
428 }
429 
430 static int
431 lock_state_loop(char *set_lock_state)
432 {
433 	(void) pthread_mutex_lock(&env_lock_mutex);
434 	if (strcmp(env_lock_state, PSVC_LOCK_ENABLED) == 0) {
435 		(void) strlcpy(env_lock_state, set_lock_state, LOCK_STRING_MAX);
436 		(void) pthread_mutex_unlock(&env_lock_mutex);
437 		return (STATE_NOT_CHANGED);
438 	}
439 	(void) pthread_mutex_unlock(&env_lock_mutex);
440 	return (STATE_CHANGED);
441 }
442 
443 static int timed_lock_wait(char *set_lock_state)
444 {
445 	int32_t status;
446 
447 	/* Only want one timer active at a time */
448 	do {
449 		status = sem_wait(&timer_sem);
450 	} while (status == -1 && errno == EINTR);
451 	if (status == -1)
452 		return (status);
453 
454 	while (timer_state != READY)
455 		(void) sched_yield();
456 	(void) pthread_mutex_lock(&timer_mutex);
457 	timer_state = HAVE_REQUEST;
458 	(void) pthread_cond_signal(&timer_cond);	/* start timer */
459 	(void) pthread_mutex_unlock(&timer_mutex);
460 
461 	/*
462 	 * We now spin checking the state env_lock_state for it to change to
463 	 * enabled.
464 	 */
465 	while (lock_state_loop(set_lock_state))
466 		(void) sleep(1);
467 
468 	(void) pthread_mutex_lock(&timer_mutex);
469 	if (timer_state == ACTIVE) {
470 		timer_state = NOT_READY;
471 		(void) pthread_cond_signal(&timer_cond);	/* stop timer */
472 	}
473 	if (timer_state == HAVE_REQUEST) {		/* cancel request */
474 		timer_state = NOT_READY;
475 	}
476 	(void) pthread_mutex_unlock(&timer_mutex);
477 	(void) sem_post(&timer_sem);
478 	return (0);
479 }
480 
481 static void lock_and_run(ETask_t *tp, int32_t obj_num)
482 {
483 	int32_t status;
484 
485 	/* Grab mutex to stop the env_lock from being changed. */
486 	(void) pthread_mutex_lock(&env_lock_mutex);
487 	/*
488 	 * Check to see if the lock is anything but Enabled. If so, we then
489 	 * goto our timer routine to wait for it to become enabled.
490 	 * If not then set it to RUNNING and run policy.
491 	 */
492 	if (strcmp(env_lock_state, PSVC_LOCK_ENABLED) != 0) {
493 		/* drop mutex and goto timer */
494 		(void) pthread_mutex_unlock(&env_lock_mutex);
495 		status = timed_lock_wait(PSVC_LOCK_RUNNING);
496 		if (status == -1) {
497 			syslog(LOG_ERR, SEM_WAIT_FAILED_MSG);
498 		}
499 	} else {
500 		(void) strlcpy(env_lock_state, PSVC_LOCK_RUNNING,
501 		    LOCK_STRING_MAX);
502 		(void) pthread_mutex_unlock(&env_lock_mutex);
503 	}
504 	status = (*tp->funcp)(hdlp, (tp->obj_list + obj_num)->name);
505 	if (status == PSVC_FAILURE && errno != ENODEV) {
506 		char dev_name[32];
507 
508 		psvc_get_attr(hdlp, (tp->obj_list + obj_num)->name,
509 		    PSVC_LABEL_ATTR, dev_name);
510 		syslog(LOG_ERR, POLICY_FAILED_MSG, tp->routine, dev_name,
511 		    (tp->obj_list + obj_num)->name);
512 		syslog(LOG_ERR, "%s", strerror(errno));
513 	}
514 
515 	/* The policy is done so set the lock back to ENABLED. */
516 	(void) pthread_mutex_lock(&env_lock_mutex);
517 	(void) strlcpy(env_lock_state, PSVC_LOCK_ENABLED, LOCK_STRING_MAX);
518 	(void) pthread_mutex_unlock(&env_lock_mutex);
519 }
520 
521 static void run_policies(EInterval_t *ip)
522 {
523 	ETask_t *tp;
524 	int32_t i, j;
525 
526 	do {
527 		if (ip->interval) {
528 			int remaining = ip->interval;
529 			do {
530 				/* check to see if we've been told to exit */
531 				if (ip->has_thread && (ip->interval == 0))
532 					break;
533 				remaining = sleep(remaining);
534 			} while (remaining > 0);
535 		}
536 		for (i = 0; i < ip->num_tasks; ++i) {
537 			tp = &ip->task_list[i];
538 			for (j = 0; j < tp->num_objects; ++j) {
539 				/* check to see if we've been told to exit */
540 				if (ip->has_thread && (ip->interval == 0))
541 					break;
542 				lock_and_run(tp, j);
543 			}
544 			if (ip->has_thread && (ip->interval == 0))
545 				break;
546 		}
547 	} while (ip->interval);
548 }
549 
550 static void thread_setup(EInterval_t *ip)
551 {
552 	int32_t status;
553 
554 	status = pthread_create(&ip->thread, NULL, (void *(*)())run_policies,
555 	    ip);
556 	if (status != 0) {
557 		if (debug_flag)
558 			syslog(LOG_ERR, "%s", strerror(errno));
559 		exit(-1);
560 	}
561 	ip->has_thread = 1;
562 }
563 
564 static int32_t load_policy(const char *library, ETask_t *tp)
565 {
566 	tp->hdl = dlopen(library, RTLD_NOW | RTLD_GLOBAL);
567 	if (tp->hdl == NULL) {
568 		if (debug_flag) {
569 			char *errstr = dlerror();
570 			syslog(LOG_ERR, "%s", errstr);
571 		}
572 		exit(1);
573 	}
574 	tp->funcp = (int32_t (*)(void *, char *))dlsym(tp->hdl, tp->routine);
575 	if (tp->funcp == NULL) {
576 		if (debug_flag) {
577 			char *errstr = dlerror();
578 			syslog(LOG_ERR, "%s", errstr);
579 		}
580 		exit(1);
581 	}
582 	return (0);
583 }
584 
585 static int32_t get_timeout(FILE *fp, int *timeout)
586 {
587 	char buf[BUFSZ];
588 	char name[32];
589 	char *cp;
590 
591 	/* skip blank lines */
592 	do {
593 		cp = fgets(buf, BUFSZ, fp);
594 		if (cp == NULL)
595 			return (1);
596 		while (isspace(*cp))
597 			++cp;
598 		(void) sscanf(buf, "%31s %d", name, timeout);
599 	} while (*cp == 0 || *cp == '\n' || strcmp(name, "TIMEOUT") != 0);
600 
601 	if (strcmp(name, "TIMEOUT") != 0) {
602 		errno = EINVAL;
603 		return (-1);
604 	}
605 	return (0);
606 
607 }
608 
609 static int32_t load_interval(FILE *fp, EInterval_t **ipp)
610 {
611 	char buf[BUFSZ];
612 	int32_t found;
613 	EInterval_t *ip;
614 	ETask_t *tp;
615 	int32_t tasks;
616 	int32_t status, i, j;
617 	int32_t interval;
618 	char name[32];
619 	char *cp;
620 
621 	/* skip blank lines */
622 	do {
623 		cp = fgets(buf, BUFSZ, fp);
624 		if (cp == NULL)
625 			return (1);
626 		while (isspace(*cp))
627 			++cp;
628 	} while (*cp == 0 || *cp == '\n');
629 	found = sscanf(buf, "%31s %d %d", name, &interval, &tasks);
630 	if (found != 3) {
631 		errno = EINVAL;
632 		return (-1);
633 	}
634 
635 	if (strcmp(name, "INTERVAL") != 0) {
636 		errno = EINVAL;
637 		return (-1);
638 	}
639 
640 	ip = (EInterval_t *)malloc(sizeof (EInterval_t));
641 	if (ip == NULL)
642 		return (-1);
643 	ip->num_tasks = tasks;
644 	ip->interval = interval;
645 	ip->next = NULL;
646 	ip->has_thread = 0;
647 
648 	/* allocate and load table */
649 	ip->task_list = (ETask_t *)malloc(ip->num_tasks * sizeof (ETask_t));
650 	if (ip->task_list == NULL)
651 		return (-1);
652 	for (i = 0; i < ip->num_tasks; ++i) {
653 		tp = &ip->task_list[i];
654 
655 		(void) fgets(buf, BUFSZ, fp);
656 		found = sscanf(buf, "%31s %1023s %63s",
657 		    name, library, tp->routine);
658 		if (found != 3) {
659 			errno = EINVAL;
660 			return (-1);
661 		}
662 
663 		status = load_policy(library, tp);
664 		if (status == -1)
665 			return (-1);
666 		found = fscanf(fp, "%d", &tp->num_objects);
667 		if (found != 1) {
668 			if (debug_flag)
669 				syslog(LOG_ERR, "No list of objects for task");
670 			errno = EINVAL;
671 			return (-1);
672 		}
673 		tp->obj_list =
674 		    (EName_t *)malloc(tp->num_objects * sizeof (EName_t));
675 		if (tp->obj_list == NULL)
676 			return (-1);
677 
678 		for (j = 0; j < tp->num_objects; ++j) {
679 			found = fscanf(fp, "%31s", (char *)(tp->obj_list + j));
680 			if (found != 1) {
681 				if (debug_flag)
682 					syslog(LOG_ERR,
683 					"Wrong number of objects for task");
684 				errno = EINVAL;
685 				return (-1);
686 			}
687 		}
688 		(void) fgets(buf, BUFSZ, fp);  /* reads newline on data line */
689 		(void) fgets(buf, BUFSZ, fp);
690 		if (strncmp(buf, "TASK_END", 8) != 0) {
691 			if (debug_flag)
692 				syslog(LOG_ERR, "Expected TASK_END, task %s",
693 				    tp->routine);
694 			errno = EINVAL;
695 			return (-1);
696 		}
697 	}
698 
699 	(void) fgets(buf, BUFSZ, fp);
700 	if (strncmp(buf, "INTERVAL_END", 12) != 0) {
701 		if (debug_flag)
702 			syslog(LOG_ERR, "Expected INTERVAL_END");
703 		errno = EINVAL;
704 		return (-1);
705 	}
706 
707 	*ipp = ip;
708 	return (0);
709 }
710 
711 void
712 fini_daemon(void)
713 {
714 	EInterval_t *ip;
715 
716 	/* shut down the threads running the policies */
717 	for (ip = first_interval; ip != NULL; ip = ip->next) {
718 		if (ip->has_thread) {
719 			/*
720 			 * there is a thread for this interval; tell it to stop
721 			 * by clearing the interval
722 			 */
723 			ip->interval = 0;
724 		}
725 	}
726 	for (ip = first_interval; ip != NULL; ip = ip->next) {
727 		if (ip->has_thread) {
728 			(void) pthread_join(ip->thread, NULL);
729 		}
730 	}
731 	/* shut down the timer thread */
732 	while (timer_state != READY)
733 		(void) sched_yield();
734 	(void) pthread_mutex_lock(&timer_mutex);
735 	timer_state = TIMER_SHUTDOWN;
736 	(void) pthread_cond_signal(&timer_cond);
737 	(void) pthread_mutex_unlock(&timer_mutex);
738 	(void) pthread_join(timer_thread_id, NULL);
739 	(void) pthread_mutex_destroy(&env_lock_mutex);
740 	(void) pthread_mutex_destroy(&timer_mutex);
741 	(void) pthread_cond_destroy(&timer_cond);
742 	(void) sem_destroy(&timer_sem);
743 }
744 
745 void
746 init_daemon(void)
747 {
748 	int32_t intervals = 0;
749 	int32_t threads = 0;
750 	int32_t status;
751 	FILE *fp;
752 	char filename[PATH_MAX];
753 	char platform[64];
754 	EInterval_t *ip, *prev;
755 
756 	if (sysinfo(SI_PLATFORM, platform, sizeof (platform)) == -1) {
757 		if (debug_flag)
758 			syslog(LOG_ERR, "%s", strerror(errno));
759 		return;
760 	}
761 
762 	(void) snprintf(filename, sizeof (filename),
763 	    "/usr/platform/%s/lib/platsvcd.conf", platform);
764 	if ((fp = fopen(filename, "r")) == NULL) {
765 		if (debug_flag)
766 			syslog(LOG_ERR, "%s", strerror(errno));
767 		return;
768 	}
769 
770 	status = get_timeout(fp, &app_timeout);
771 	if (status != 0) {
772 		if (debug_flag)
773 			syslog(LOG_ERR, "%s", strerror(errno));
774 		return;
775 	}
776 
777 	status = sem_init(&timer_sem, 0, 1);
778 	if (status == -1) {
779 		if (debug_flag)
780 			syslog(LOG_ERR, "%s", strerror(errno));
781 		return;
782 	}
783 
784 	(void) strlcpy(env_lock_state, PSVC_LOCK_ENABLED, LOCK_STRING_MAX);
785 	(void) pthread_mutex_init(&env_lock_mutex, NULL);
786 	(void) pthread_mutex_init(&timer_mutex, NULL);
787 	(void) pthread_cond_init(&timer_cond, NULL);
788 
789 	timer_state = NOT_READY;
790 	status = pthread_create(&timer_thread_id, NULL,
791 	    (void *(*)())timer_thread, 0);
792 	if (status != 0) {
793 		if (debug_flag)
794 			syslog(LOG_ERR, "%s", strerror(errno));
795 		return;
796 	}
797 
798 	/* get timer thread running */
799 	while (timer_state != READY)
800 		(void) sched_yield();
801 
802 	for (;;) {
803 		status = load_interval(fp, &ip);
804 		if (status != 0)
805 			break;
806 
807 #ifdef	lint
808 		prev = NULL;
809 #endif
810 		if (first_interval == 0)
811 			first_interval = ip;
812 		else
813 			prev->next = ip;
814 		prev = ip;
815 
816 		++intervals;
817 		if (ip->interval == 0) {
818 			run_policies(ip);
819 		} else {
820 			thread_setup(ip);
821 			++threads;
822 		}
823 	}
824 	if (intervals == 0) {
825 		if (debug_flag)
826 			syslog(LOG_ERR, "ERROR: No policies started");
827 		return;
828 	}
829 
830 	if (status == -1) {
831 		if (debug_flag)
832 			syslog(LOG_ERR, "%s", strerror(errno));
833 		return;
834 	}
835 }
836 
837 
838 static int32_t count_records(FILE *fp, char *end, uint32_t *countp)
839 {
840 	long first_record;
841 	char *ret;
842 	char buf[BUFSZ];
843 	uint32_t count = 0;
844 
845 	first_record = ftell(fp);
846 
847 	while ((ret = fgets(buf, BUFSZ, fp)) != NULL) {
848 		if (strncmp(end, buf, strlen(end)) == 0)
849 			break;
850 		++count;
851 	}
852 
853 	if (ret == NULL) {
854 		errno = EINVAL;
855 		return (-1);
856 	}
857 
858 	(void) fseek(fp, first_record, SEEK_SET);
859 	*countp = count;
860 	return (0);
861 }
862 
863 /*
864  * Find start of a section within the config file,
865  * Returns number of records in the section.
866  * FILE *fd is set to first data record within section.
867  */
868 static int32_t
869 find_file_section(FILE *fd, char *start)
870 {
871 	char *ret;
872 	char buf[BUFSZ];
873 	char name[32];
874 	int found;
875 
876 	(void) fseek(fd, 0, SEEK_SET);
877 	while ((ret = fgets(buf, BUFSZ, fd)) != NULL) {
878 		if (strncmp(start, buf, strlen(start)) == 0)
879 			break;
880 	}
881 
882 	if (ret == NULL) {
883 		errno = EINVAL;
884 		return (-1);
885 	}
886 
887 	found = sscanf(buf, "%31s", name);
888 	if (found != 1) {
889 		errno = EINVAL;
890 		return (-1);
891 	} else {
892 		return (0);
893 	}
894 
895 }
896 
897 static int32_t name_compare_qsort(picl_psvc_t *s1, picl_psvc_t *s2)
898 {
899 	return (strcmp(s1->name, s2->name));
900 }
901 
902 static int32_t name_compare_bsearch(char *s1, picl_psvc_t *s2)
903 {
904 	return (strcmp(s1, s2->name));
905 }
906 
907 /*
908  * Create a property and add it to the specified node.
909  * PICL will take a segmentation violation if a volatile property
910  * has a non-zero size.
911  */
912 static int32_t node_property(picl_nodehdl_t node,
913 	int (*read)(ptree_rarg_t *, void *),
914 	int (*write)(ptree_warg_t *, const void *), picl_prop_type_t type,
915 	unsigned int size, unsigned int accessmode, char *name, void *value)
916 {
917 	ptree_propinfo_t propinfo;
918 	picl_prophdl_t prophdl;
919 	int err;
920 
921 	propinfo.version = PSVC_PLUGIN_VERSION;
922 	if (accessmode & PICL_VOLATILE) {
923 		propinfo.read = read;
924 		propinfo.write = write;
925 	} else {
926 		propinfo.read = NULL;
927 		propinfo.write = NULL;
928 	}
929 	propinfo.piclinfo.type = type;
930 	propinfo.piclinfo.accessmode = accessmode;
931 	propinfo.piclinfo.size = size;
932 	(void) strcpy(propinfo.piclinfo.name, name);
933 
934 	err = ptree_create_prop(&propinfo, value, &prophdl);
935 	if (err != 0) {
936 		return (err);
937 	}
938 
939 	err = ptree_add_prop(node, prophdl);
940 	if (err != 0)
941 		return (err);
942 
943 	return (0);
944 }
945 
946 static void init_err(const char *fmt, char *arg1, char *arg2)
947 {
948 	char msg[256];
949 
950 	(void) snprintf(msg, sizeof (msg), fmt, arg1, arg2);
951 	syslog(LOG_ERR, "%s", msg);
952 }
953 
954 static int
955 projected_lookup(picl_prophdl_t proph, struct proj_prop **dstp)
956 {
957 	int i;
958 
959 	for (i = 0; i < proj_prop_count; ++i) {
960 		if (prop_list[i].handle == proph) {
961 			*dstp = &prop_list[i];
962 			return (PICL_SUCCESS);
963 		}
964 	}
965 
966 	return (PICL_INVALIDHANDLE);
967 }
968 
969 int
970 projected_read(ptree_rarg_t *rarg, void *buf)
971 {
972 	ptree_propinfo_t propinfo;
973 	struct proj_prop *dstinfo;
974 	int err;
975 
976 	err = projected_lookup(rarg->proph, &dstinfo);
977 	if (err != 0) {
978 		return (PICL_FAILURE);
979 	}
980 
981 
982 	err = ptree_get_propinfo(rarg->proph, &propinfo);
983 	if (err != 0)
984 		return (err);
985 	err = ptree_get_propval_by_name(dstinfo->dst_node,
986 	    dstinfo->name, buf, propinfo.piclinfo.size);
987 	if (err != 0)
988 		return (err);
989 	return (PICL_SUCCESS);
990 }
991 
992 int
993 projected_write(ptree_warg_t *warg, const void *buf)
994 {
995 	ptree_propinfo_t propinfo;
996 	struct proj_prop *dstinfo;
997 	int err;
998 
999 	err = projected_lookup(warg->proph, &dstinfo);
1000 	if (err != 0) {
1001 		return (PICL_FAILURE);
1002 	}
1003 
1004 	err = ptree_get_propinfo(warg->proph, &propinfo);
1005 	if (err != 0)
1006 		return (err);
1007 	err = ptree_update_propval_by_name(dstinfo->dst_node,
1008 	    dstinfo->name, buf, propinfo.piclinfo.size);
1009 	if (err != 0)
1010 		return (err);
1011 	return (PICL_SUCCESS);
1012 }
1013 
1014 int
1015 psvc_read_volatile(ptree_rarg_t *rarg, void *buf)
1016 {
1017 	ptree_propinfo_t propinfo;
1018 	char name[32], class[32];
1019 	int err, i;
1020 	int32_t attr_num = -1;
1021 	int32_t use_attr_num = 0;
1022 
1023 	err = ptree_get_propval_by_name(rarg->nodeh, "name", name,
1024 	    sizeof (name));
1025 	if (err != 0) {
1026 		return (err);
1027 	}
1028 
1029 	err = ptree_get_propval_by_name(rarg->nodeh, "_class", class,
1030 	    sizeof (class));
1031 	if (err != 0) {
1032 		return (err);
1033 	}
1034 
1035 	err = ptree_get_propinfo(rarg->proph, &propinfo);
1036 	if (err != 0) {
1037 		return (err);
1038 	}
1039 
1040 	for (i = 0; i < PICL_PROP_TRANS_COUNT; i++) {
1041 		if ((strcmp(class, picl_prop_trans[i].picl_class) == 0) &&
1042 		    (strcmp(propinfo.piclinfo.name,
1043 		    picl_prop_trans[i].picl_prop) == 0)) {
1044 			attr_num = i;
1045 			break;
1046 		}
1047 	}
1048 
1049 	if (attr_num == -1)
1050 		for (i = 0; i < ATTR_STR_TAB_SIZE; i++) {
1051 			if (strcmp(propinfo.piclinfo.name,
1052 			    attr_str_tab[i]) == 0) {
1053 				attr_num = i;
1054 				use_attr_num = 1;
1055 				break;
1056 			}
1057 		}
1058 
1059 	if (use_attr_num)
1060 		err = psvc_get_attr(hdlp, name, attr_num, buf);
1061 	else
1062 		err = psvc_get_attr(hdlp, name,
1063 		    picl_prop_trans[attr_num].psvc_prop,
1064 		    buf);
1065 
1066 	if (err != 0) {
1067 		return (PICL_FAILURE);
1068 	}
1069 	return (PICL_SUCCESS);
1070 }
1071 
1072 int
1073 psvc_write_volatile(ptree_warg_t *warg, const void *buf)
1074 {
1075 	ptree_propinfo_t propinfo;
1076 	char name[32], class[32];
1077 	int err, i;
1078 	int32_t attr_num = -1;
1079 	int32_t use_attr_num = 0;
1080 
1081 	if (warg->cred.dc_euid != 0)
1082 		return (PICL_PERMDENIED);
1083 
1084 	err = ptree_get_propval_by_name(warg->nodeh, "name", name,
1085 	    sizeof (name));
1086 	if (err != 0) {
1087 		return (err);
1088 	}
1089 
1090 	err = ptree_get_propval_by_name(warg->nodeh, "_class", class,
1091 	    sizeof (class));
1092 	if (err != 0) {
1093 		return (err);
1094 	}
1095 
1096 	err = ptree_get_propinfo(warg->proph, &propinfo);
1097 	if (err != 0) {
1098 		return (err);
1099 	}
1100 
1101 	for (i = 0; i < PICL_PROP_TRANS_COUNT; i++) {
1102 		if ((strcmp(class, picl_prop_trans[i].picl_class) == 0) &&
1103 		    (strcmp(propinfo.piclinfo.name,
1104 		    picl_prop_trans[i].picl_prop) == 0)) {
1105 			attr_num = i;
1106 			break;
1107 		}
1108 	}
1109 
1110 	if (attr_num == -1)
1111 		for (i = 0; i < ATTR_STR_TAB_SIZE; i++) {
1112 			if (strcmp(propinfo.piclinfo.name,
1113 			    attr_str_tab[i]) == 0) {
1114 			attr_num = i;
1115 			use_attr_num = 1;
1116 			break;
1117 			}
1118 		}
1119 
1120 	if (use_attr_num)
1121 		err = psvc_set_attr(hdlp, name, attr_num, (void *)buf);
1122 	else
1123 		err = psvc_set_attr(hdlp, name,
1124 		    picl_prop_trans[attr_num].psvc_prop,
1125 		    (void *)buf);
1126 
1127 	if (err != 0) {
1128 		return (PICL_FAILURE);
1129 	}
1130 
1131 	return (PICL_SUCCESS);
1132 }
1133 
1134 void create_reference_properties(struct assoc_pair *assoc_tbl, int32_t count,
1135 	char *assoc_name)
1136 {
1137 	picl_psvc_t *aobjp, *dobjp;
1138 	picl_prophdl_t tbl_hdl;
1139 	picl_nodehdl_t *dep_list;
1140 	ptree_propinfo_t propinfo;
1141 	char *funcname = "create_reference_properties";
1142 	char name[PICL_PROPNAMELEN_MAX];
1143 	int32_t i, j, offset;
1144 	int32_t dependents;
1145 	int32_t err;
1146 	char class[PICL_CLASSNAMELEN_MAX];
1147 
1148 	for (i = 0; i < count; ++i) {
1149 		/* antecedent */
1150 		aobjp = (picl_psvc_t *)bsearch(assoc_tbl[i].antecedent,
1151 		    psvc_hdl.objects, psvc_hdl.obj_count,
1152 		    sizeof (picl_psvc_t),
1153 		    (int (*)(const void *, const void *))
1154 		    name_compare_bsearch);
1155 		if (aobjp == NULL) {
1156 			init_err(ID_NOT_FOUND_MSG,
1157 			    funcname, assoc_tbl[i].antecedent);
1158 			return;
1159 		}
1160 
1161 		/* skip if table already created */
1162 		if (ptree_get_propval_by_name(aobjp->node, assoc_name,
1163 		    &tbl_hdl, sizeof (tbl_hdl)) == 0) {
1164 			continue;
1165 		}
1166 
1167 		/* create a new table */
1168 		err = ptree_create_table(&tbl_hdl);
1169 		if (err != 0) {
1170 			init_err(PTREE_CREATE_TABLE_FAILED_MSG,
1171 			    funcname, picl_strerror(err));
1172 			return;
1173 		}
1174 
1175 		err = node_property(aobjp->node, NULL, NULL,
1176 		    PICL_PTYPE_TABLE, sizeof (tbl_hdl), PICL_READ,
1177 		    assoc_name, &tbl_hdl);
1178 		if (err != 0) {
1179 			init_err(CREATE_PROP_FAILED_MSG, funcname,
1180 			    picl_strerror(err));
1181 			return;
1182 		}
1183 
1184 		/* determine number of elements in the table */
1185 		dependents = 0;
1186 		for (j = i; j < count; ++j) {
1187 			if (strcmp(aobjp->name, assoc_tbl[j].antecedent) == 0)
1188 				++dependents;
1189 		}
1190 
1191 		dep_list = (picl_nodehdl_t *)malloc(sizeof (picl_nodehdl_t) *
1192 		    dependents);
1193 		if (dep_list == NULL) {
1194 			init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1195 			return;
1196 		}
1197 		/* build row of reference properties */
1198 		offset = 0;
1199 		for (j = i; j < count; ++j) {
1200 			if (strcmp(aobjp->name, assoc_tbl[j].antecedent) != 0)
1201 				continue;
1202 
1203 			dobjp = (picl_psvc_t *)bsearch(assoc_tbl[j].dependent,
1204 			    psvc_hdl.objects,
1205 			    psvc_hdl.obj_count, sizeof (picl_psvc_t),
1206 			    (int (*)(const void *, const void *))
1207 			    name_compare_bsearch);
1208 			if (dobjp == NULL) {
1209 				init_err(ID_NOT_FOUND_MSG,
1210 				    funcname, assoc_tbl[j].dependent);
1211 				return;
1212 			}
1213 
1214 			/*
1215 			 * Reference property name must be
1216 			 * _classname_propertyname
1217 			 */
1218 			err = ptree_get_propval_by_name(dobjp->node,
1219 			    "_class", class, sizeof (class));
1220 			if (err != 0) {
1221 				init_err(CLASS_NOT_FOUND_MSG, funcname,
1222 				    assoc_tbl[j].dependent);
1223 				return;
1224 			}
1225 			(void) snprintf(name, sizeof (name), "_%s_subclass",
1226 			    class);
1227 
1228 			propinfo.version = PSVC_PLUGIN_VERSION;
1229 			propinfo.read = NULL;
1230 			propinfo.write = NULL;
1231 			propinfo.piclinfo.type = PICL_PTYPE_REFERENCE;
1232 			propinfo.piclinfo.accessmode = PICL_READ;
1233 			propinfo.piclinfo.size = sizeof (picl_nodehdl_t);
1234 			(void) strcpy(propinfo.piclinfo.name, name);
1235 
1236 			err = ptree_create_prop(&propinfo, &dobjp->node,
1237 			    dep_list + offset);
1238 			if (err != 0) {
1239 				init_err(PTREE_CREATE_PROP_FAILED_MSG,
1240 				    name, picl_strerror(err));
1241 				return;
1242 			}
1243 
1244 			++offset;
1245 		}
1246 
1247 		/* add row to table */
1248 		err = ptree_add_row_to_table(tbl_hdl, dependents, dep_list);
1249 		if (err != 0) {
1250 			init_err(PTREE_ADD_ROW_FAILED_MSG, funcname,
1251 			    picl_strerror(err));
1252 			return;
1253 		}
1254 
1255 	}
1256 
1257 
1258 }
1259 
1260 /* Load projected properties */
1261 static void
1262 load_projected_properties(FILE *fp)
1263 {
1264 	int32_t found;
1265 	ptree_propinfo_t propinfo;
1266 	ptree_propinfo_t dstinfo;
1267 	picl_prophdl_t src_prophdl, dst_prophdl;
1268 	picl_nodehdl_t src_node, dst_node;
1269 	int err, i;
1270 	picl_psvc_t *srcobjp, *dstobjp;
1271 	char src[32], dst[256];
1272 	char src_prop[32], dst_prop[32];
1273 	char buf[BUFSZ];
1274 	char *funcname = "load_projected_properties";
1275 
1276 	if (find_file_section(fp, "PROJECTED_PROPERTIES") != 0)
1277 		return;
1278 
1279 	if (count_records(fp, "PROJECTED_PROPERTIES_END", &proj_prop_count) !=
1280 	    0) {
1281 		init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1282 		return;
1283 	}
1284 
1285 	prop_list = (struct proj_prop *)malloc(sizeof (struct proj_prop)
1286 	    * proj_prop_count);
1287 	if (prop_list == NULL) {
1288 		init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1289 		return;
1290 	}
1291 
1292 	for (i = 0; i < proj_prop_count; ++i) {
1293 		buf[0] = '\0';
1294 		(void) fgets(buf, BUFSZ, fp);
1295 		found = sscanf(buf, "%31s %31s %255s %31s", src, src_prop, dst,
1296 		    dst_prop);
1297 		if (found != 4) {
1298 			init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1299 			return;
1300 		}
1301 
1302 		/* find src node */
1303 		if (src[0] == '/') {
1304 			/* picl node name, outside psvc subtree */
1305 			err = ptree_get_node_by_path(src, &src_node);
1306 			if (err != 0) {
1307 				init_err(NODE_NOT_FOUND_MSG, funcname, src);
1308 				return;
1309 			}
1310 		} else {
1311 			srcobjp = (picl_psvc_t *)bsearch(src, psvc_hdl.objects,
1312 			    psvc_hdl.obj_count, sizeof (picl_psvc_t),
1313 			    (int (*)(const void *, const void *))
1314 			    name_compare_bsearch);
1315 			if (srcobjp == NULL) {
1316 				init_err(ID_NOT_FOUND_MSG, funcname, src);
1317 				return;
1318 			}
1319 			src_node = srcobjp->node;
1320 		}
1321 
1322 		/* find dest node */
1323 		if (dst[0] == '/') {
1324 			/* picl node name, outside psvc subtree */
1325 			err = ptree_get_node_by_path(dst, &dst_node);
1326 			if (err != 0) {
1327 				init_err(NODE_NOT_FOUND_MSG, funcname, dst);
1328 				return;
1329 			}
1330 			prop_list[i].dst_node = dst_node;
1331 		} else {
1332 			dstobjp = (picl_psvc_t *)bsearch(dst, psvc_hdl.objects,
1333 			    psvc_hdl.obj_count, sizeof (picl_psvc_t),
1334 			    (int (*)(const void *, const void *))
1335 			    name_compare_bsearch);
1336 			if (dstobjp == NULL) {
1337 				init_err(ID_NOT_FOUND_MSG, funcname, dst);
1338 				return;
1339 			}
1340 			dst_node = dstobjp->node;
1341 			prop_list[i].dst_node = dst_node;
1342 		}
1343 
1344 		/* determine destination property size */
1345 		err = ptree_get_first_prop(dst_node, &dst_prophdl);
1346 		while (err == 0) {
1347 			err = ptree_get_propinfo(dst_prophdl, &dstinfo);
1348 			if (err != 0)
1349 				break;
1350 			if (strcmp(dst_prop, dstinfo.piclinfo.name) == 0)
1351 				break;
1352 			err = ptree_get_next_prop(dst_prophdl, &dst_prophdl);
1353 		}
1354 		if (err != 0) {
1355 			init_err(SIZE_NOT_FOUND_MSG, funcname, dst_prop);
1356 			return;
1357 		}
1358 
1359 		propinfo.version = PSVC_PLUGIN_VERSION;
1360 		propinfo.read = projected_read;
1361 		propinfo.write = projected_write;
1362 		propinfo.piclinfo.type = dstinfo.piclinfo.type;
1363 		propinfo.piclinfo.accessmode =
1364 		    PICL_READ | PICL_WRITE | PICL_VOLATILE;
1365 		propinfo.piclinfo.size = dstinfo.piclinfo.size;
1366 		(void) strcpy(propinfo.piclinfo.name, src_prop);
1367 
1368 		err = ptree_create_prop(&propinfo, 0, &src_prophdl);
1369 		if (err != 0) {
1370 			init_err(PTREE_CREATE_PROP_FAILED_MSG, funcname,
1371 			    picl_strerror(err));
1372 			return;
1373 		}
1374 
1375 		err = ptree_add_prop(src_node, src_prophdl);
1376 		if (err != 0) {
1377 			init_err(PTREE_ADD_PROP_FAILED_MSG, funcname,
1378 			    picl_strerror(err));
1379 			return;
1380 		}
1381 
1382 		prop_list[i].handle = src_prophdl;
1383 		(void) strcpy(prop_list[i].name, dst_prop);
1384 
1385 	}
1386 }
1387 
1388 /* Load the association table */
1389 static void load_associations(FILE *fp)
1390 {
1391 	char *funcname = "load_associations";
1392 	uint32_t count;
1393 	int found;
1394 	int j;
1395 	char assoc_name[32];
1396 	struct assoc_pair *assoc_tbl;
1397 	char name1[32];
1398 	char buf[BUFSZ];
1399 
1400 	/*
1401 	 * ignore count in the file, correct count is highest
1402 	 * association id + 1, now figured when loading ASSOC_STR
1403 	 * section.
1404 	 */
1405 	if (find_file_section(fp, "ASSOCIATIONS") != 0)
1406 		return;
1407 
1408 	buf[0] = '\0';
1409 	(void) fgets(buf, BUFSZ, fp);
1410 	while (strncmp("ASSOCIATIONS_END", buf, 16) != 0) {
1411 		found = sscanf(buf, "%31s %31s", name1, assoc_name);
1412 		if (found != 2) {
1413 			init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1414 			return;
1415 		}
1416 
1417 		if (count_records(fp, "ASSOCIATION_END", &count) != 0) {
1418 			init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1419 			return;
1420 		}
1421 
1422 		assoc_tbl = (struct assoc_pair *)malloc(
1423 		    sizeof (struct assoc_pair) * count);
1424 		if (assoc_tbl == NULL) {
1425 			init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1426 			return;
1427 		}
1428 
1429 		for (j = 0; j < count; ++j) {
1430 			buf[0] = '\0';
1431 			(void) fgets(buf, BUFSZ, fp);
1432 			found = sscanf(buf, "%31s %31s",
1433 			    assoc_tbl[j].antecedent, assoc_tbl[j].dependent);
1434 			if (found != 2) {
1435 				init_err(INVALID_FILE_FORMAT_MSG, funcname,
1436 				    0);
1437 				return;
1438 			}
1439 
1440 		}
1441 		buf[0] = '\0';
1442 		(void) fgets(buf, BUFSZ, fp);
1443 		if (strncmp(buf, "ASSOCIATION_END", 15) != 0) {
1444 			init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1445 			return;
1446 		}
1447 
1448 		/* Create separate list of dependents for each antecedent */
1449 		if (strcmp(assoc_name, "PSVC_TABLE") != 0) {
1450 			create_reference_properties(assoc_tbl, count,
1451 			    assoc_name);
1452 		}
1453 
1454 		free(assoc_tbl);
1455 		buf[0] = '\0';
1456 		(void) fgets(buf, BUFSZ, fp);
1457 	}
1458 
1459 }
1460 
1461 /* Enviornmental Lock Object's Read and Write routine */
1462 /* ARGSUSED */
1463 static int
1464 env_lock_read(ptree_rarg_t *rarg, void *buf)
1465 {
1466 	(void) strlcpy((char *)buf, env_lock_state, LOCK_STRING_MAX);
1467 	return (PSVC_SUCCESS);
1468 }
1469 
1470 /* ARGSUSED */
1471 static int
1472 env_lock_write(ptree_warg_t *warg, const void *buf)
1473 {
1474 	int32_t status = PSVC_SUCCESS;
1475 	char *var = (char *)buf;
1476 
1477 	/*
1478 	 * Check to make sure that the value is either Disabled or Enabled
1479 	 * as these are the only 2 states that this object can be set to.
1480 	 */
1481 	if ((strcmp(var, PSVC_LOCK_DISABLED) != 0) &&
1482 	    (strcmp(var, PSVC_LOCK_ENABLED) != 0)) {
1483 		errno = EINVAL;
1484 		return (PSVC_FAILURE);
1485 	}
1486 
1487 	(void) pthread_mutex_lock(&env_lock_mutex);
1488 
1489 	/*
1490 	 * If the state is already Enabled we can set the state to Disabled
1491 	 * to stop the policies.
1492 	 */
1493 	if (strcmp(env_lock_state, PSVC_LOCK_ENABLED) == 0) {
1494 		(void) pthread_mutex_unlock(&env_lock_mutex);
1495 		status = timed_lock_wait(PSVC_LOCK_DISABLED);
1496 		if (status == -1) {
1497 			syslog(LOG_ERR, SEM_WAIT_FAILED_MSG);
1498 		}
1499 		return (status);
1500 	}
1501 
1502 	/*
1503 	 * If the state is Running we must go into timed_lock_wait to aquire
1504 	 * the env_lock.
1505 	 */
1506 	if (strcmp(env_lock_state, PSVC_LOCK_RUNNING) == 0) {
1507 		(void) pthread_mutex_unlock(&env_lock_mutex);
1508 		status = timed_lock_wait(PSVC_LOCK_DISABLED);
1509 		if (status == -1) {
1510 			syslog(LOG_ERR, SEM_WAIT_FAILED_MSG);
1511 		}
1512 		return (status);
1513 	}
1514 
1515 	/*
1516 	 * If the state is already Disabled we need to first check to see if
1517 	 * we are resetting it to Disabled or changing it to Enabled. If we
1518 	 * are resetting it to Disabled then we need to stop the timer and
1519 	 * restart it. If we are changing it to Enabled we just set it to
1520 	 * enabled.
1521 	 */
1522 	if (strcmp(env_lock_state, PSVC_LOCK_DISABLED) == 0) {
1523 		if (strcmp(var, PSVC_LOCK_DISABLED) == 0) {
1524 			(void) pthread_mutex_lock(&timer_mutex);
1525 			if (timer_state == ACTIVE) {
1526 				timer_state = NOT_READY;
1527 				/* stop timer */
1528 				(void) pthread_cond_signal(&timer_cond);
1529 				(void) pthread_mutex_unlock(&timer_mutex);
1530 				/* wait for timer to reset */
1531 				while (timer_state != READY)
1532 					(void) sched_yield();
1533 				(void) pthread_mutex_lock(&timer_mutex);
1534 				timer_state = HAVE_REQUEST;
1535 				/* restart timer */
1536 				(void) pthread_cond_signal(&timer_cond);
1537 			}
1538 			(void) pthread_mutex_unlock(&timer_mutex);
1539 		} else {
1540 			(void) strlcpy(env_lock_state, var, LOCK_STRING_MAX);
1541 		}
1542 	}
1543 	(void) pthread_mutex_unlock(&env_lock_mutex);
1544 	return (PSVC_SUCCESS);
1545 }
1546 
1547 static int
1548 init_env_lock_node(picl_nodehdl_t root_node)
1549 {
1550 	int err;
1551 	ptree_propinfo_t propinfo;
1552 	char *funcname = "init_env_lock_node";
1553 
1554 	/* Here we are creating a Enviornmental Lock Node */
1555 	err = ptree_create_node("/plugins/environmental", "picl", &lock_node);
1556 	if (err != PICL_SUCCESS) {
1557 		init_err(PTREE_CREATE_NODE_FAILED_MSG, funcname,
1558 		    picl_strerror(err));
1559 		return (err);
1560 	}
1561 
1562 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION_1,
1563 	    PICL_PTYPE_CHARSTRING, PICL_READ | PICL_WRITE | PICL_VOLATILE,
1564 	    32, "State", env_lock_read, env_lock_write);
1565 	if (err != PICL_SUCCESS) {
1566 		init_err(NODE_PROP_FAILED_MSG, funcname, picl_strerror(err));
1567 		return (err);
1568 	}
1569 
1570 	err = ptree_create_and_add_prop(lock_node, &propinfo,
1571 	    NULL, NULL);
1572 	if (err != PICL_SUCCESS) {
1573 		init_err(PTREE_ADD_PROP_FAILED_MSG, funcname,
1574 		    picl_strerror(err));
1575 		return (err);
1576 	}
1577 
1578 	err = ptree_add_node(root_node, lock_node);
1579 	if (err != PICL_SUCCESS) {
1580 		init_err(PTREE_ADD_NODE_FAILED_MSG, funcname,
1581 		    picl_strerror(err));
1582 		return (err);
1583 	}
1584 
1585 	return (PSVC_SUCCESS);
1586 }
1587 
1588 void
1589 psvc_plugin_init(void)
1590 {
1591 	struct classinfo *cp;
1592 	picl_nodehdl_t root_node;
1593 	picl_nodehdl_t parent_node;
1594 	char *funcname = "psvc_plugin_init";
1595 	char platform[32];
1596 	char filename[256];
1597 	char buf[BUFSZ];
1598 	int32_t i, j;
1599 	int err, found;
1600 
1601 	psvc_paths = NULL;
1602 	psvc_hdl.obj_count = 0;
1603 	psvc_hdl.objects = NULL;
1604 	psvc_hdl.fp = NULL;
1605 	first_interval = NULL;
1606 
1607 	/*
1608 	 * So the volatile read/write routines can retrieve data from
1609 	 * psvc or picl
1610 	 */
1611 	err = psvc_init(&hdlp);
1612 	if (err != 0) {
1613 		init_err(PSVC_INIT_ERR_MSG, funcname, strerror(errno));
1614 	}
1615 
1616 	if (sysinfo(SI_PLATFORM, platform, sizeof (platform)) == -1) {
1617 		init_err(SYSINFO_FAILED_MSG, funcname, 0);
1618 		return;
1619 	}
1620 
1621 	(void) snprintf(filename, sizeof (filename),
1622 	    "/usr/platform/%s/lib/psvcobj.conf", platform);
1623 	if ((psvc_hdl.fp = fopen(filename, "r")) == NULL) {
1624 		init_err(FILE_OPEN_FAILED_MSG, funcname, filename);
1625 		return;
1626 	}
1627 
1628 	/* Create all PICL nodes */
1629 	if (find_file_section(psvc_hdl.fp, "OBJECT_INFO") == -1) {
1630 		init_err(INVALID_FILE_FORMAT1_MSG, funcname, filename);
1631 		return;
1632 	}
1633 	if (count_records(psvc_hdl.fp, "OBJECT_INFO_END", &psvc_hdl.obj_count)
1634 	    == -1) {
1635 		init_err(INVALID_FILE_FORMAT1_MSG, funcname, filename);
1636 		return;
1637 	}
1638 	if ((psvc_hdl.objects = (picl_psvc_t *)malloc(sizeof (picl_psvc_t) *
1639 	    psvc_hdl.obj_count)) == NULL) {
1640 		init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1641 		return;
1642 	}
1643 	(void) memset(psvc_hdl.objects, 0,
1644 	    sizeof (picl_psvc_t) * psvc_hdl.obj_count);
1645 
1646 	err = ptree_get_root(&root_node);
1647 	if (err != 0) {
1648 		init_err(PTREE_GET_ROOT_FAILED_MSG, funcname,
1649 		    picl_strerror(err));
1650 		return;
1651 	}
1652 
1653 	/* Following array is  accessed directly by the psvc policies. */
1654 	psvc_paths = (psvc_name_t *)malloc(sizeof (psvc_name_t) *
1655 	    psvc_hdl.obj_count);
1656 	psvc_picl_nodes = psvc_hdl.obj_count;
1657 	if (psvc_paths == NULL) {
1658 		init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1659 		return;
1660 	}
1661 	for (i = 0; i < psvc_hdl.obj_count; ++i) {
1662 		char *start;
1663 		int32_t class;
1664 		int32_t subclass;
1665 		int32_t	cp_count;
1666 		picl_psvc_t *objp = &psvc_hdl.objects[i];
1667 		buf[0] = '\0';
1668 		(void) fgets(buf, BUFSZ, psvc_hdl.fp);
1669 		if (strncmp(buf, "OBJECT_INFO_END", 15) == 0)
1670 			break;
1671 
1672 		start = strrchr(buf, '/');
1673 		if (start == NULL) {
1674 			init_err(INVALID_FILE_FORMAT1_MSG, funcname,
1675 			    filename);
1676 			return;
1677 		}
1678 		found = sscanf(start + 1, "%31s",  objp->name);
1679 		if (found != 1) {
1680 			init_err(INVALID_FILE_FORMAT1_MSG, funcname,
1681 			    filename);
1682 			return;
1683 		}
1684 
1685 		/* get class */
1686 		err = psvc_get_attr(hdlp, objp->name, PSVC_CLASS_ATTR, &class);
1687 		if (err != PSVC_SUCCESS) {
1688 			init_err(CLASS_NOT_FOUND_MSG, funcname, objp->name);
1689 			return;
1690 		}
1691 		if (class > NUM_CLASSES) {
1692 			init_err(UNKNOWN_CLASS_MSG, funcname, 0);
1693 			return;
1694 		}
1695 
1696 		err = psvc_get_attr(hdlp, objp->name, PSVC_SUBCLASS_ATTR,
1697 		    &subclass);
1698 		if (err != PSVC_SUCCESS) {
1699 			init_err(SUBCLASS_NOT_FOUND_MSG, funcname, objp->name);
1700 			return;
1701 		}
1702 
1703 		err = ptree_create_node(objp->name, class_name[class],
1704 		    &objp->node);
1705 		if (err != 0) {
1706 			init_err(PTREE_CREATE_NODE_FAILED_MSG, funcname,
1707 			    picl_strerror(err));
1708 			return;
1709 		}
1710 		if (strcmp(objp->name, PSVC_CHASSIS) == 0)
1711 			system_node = objp->node;
1712 
1713 		for (j = 0; j < COMMON_COUNT; ++j) {
1714 
1715 			err = node_property(objp->node,
1716 			    common[j].access & PICL_READ ?
1717 			    psvc_read_volatile : 0,
1718 			    common[j].access & PICL_WRITE ?
1719 			    psvc_write_volatile : 0,
1720 			    common[j].type, common[j].size,
1721 			    common[j].access, common[j].name, 0);
1722 			if (err != PSVC_SUCCESS) {
1723 				init_err(NODE_PROP_FAILED_MSG, funcname,
1724 				    picl_strerror(err));
1725 				return;
1726 			}
1727 		}
1728 		cp = &class_properties[class];
1729 		/* Locator LED Support */
1730 		if (class == 2 && subclass == 2) {
1731 			cp_count = 3;
1732 		} else {
1733 			cp_count = cp->count;
1734 		}
1735 
1736 		for (j = 0; j < cp_count; ++j) {
1737 			err = node_property(objp->node, psvc_read_volatile,
1738 			    psvc_write_volatile, cp->props[j].type,
1739 			    cp->props[j].size,
1740 			    cp->props[j].access, cp->props[j].name, 0);
1741 			if (err != PSVC_SUCCESS) {
1742 				init_err(NODE_PROP_FAILED_MSG, funcname,
1743 				    picl_strerror(err));
1744 				return;
1745 			}
1746 		}
1747 
1748 		/* Link the nodes into the PICL tree */
1749 		*start = 0;
1750 		if (start == buf) {	/* no parent */
1751 			parent_node = root_node;
1752 		} else {
1753 			err = ptree_get_node_by_path(buf, &parent_node);
1754 			if (err != PICL_SUCCESS) {
1755 				init_err(NODE_NOT_FOUND_MSG, funcname, buf);
1756 				return;
1757 			}
1758 		}
1759 
1760 		err = ptree_add_node(parent_node, objp->node);
1761 		if (err != PICL_SUCCESS) {
1762 			init_err(PTREE_ADD_NODE_FAILED_MSG, funcname,
1763 			    picl_strerror(err));
1764 			return;
1765 		}
1766 		(void) strcpy(psvc_paths[i].parent_path, buf);
1767 		(void) strcpy(psvc_paths[i].child_name, objp->name);
1768 		psvc_paths[i].child_node = objp->node;
1769 	}
1770 
1771 	qsort(psvc_hdl.objects, psvc_hdl.obj_count, sizeof (picl_psvc_t),
1772 	    (int (*)(const void *, const void *))name_compare_qsort);
1773 
1774 	load_associations(psvc_hdl.fp);
1775 	load_projected_properties(psvc_hdl.fp);
1776 
1777 	if (init_env_lock_node(root_node) != PSVC_SUCCESS)
1778 		return;
1779 
1780 	init_daemon();
1781 }
1782 
1783 void
1784 psvc_plugin_fini(void)
1785 {
1786 	int32_t i;
1787 	EInterval_t *ip, *next;
1788 
1789 	fini_daemon();
1790 	for (ip = first_interval; ip != 0; ip = next) {
1791 		for (i = 0; i < ip->num_tasks; ++i) {
1792 			(void) dlclose(ip->task_list[i].hdl);
1793 			free(ip->task_list[i].obj_list);
1794 		}
1795 		free(ip->task_list);
1796 		next = ip->next;
1797 		free(ip);
1798 	}
1799 	free(prop_list);
1800 	free(psvc_paths);
1801 	free(psvc_hdl.objects);
1802 	if (psvc_hdl.fp != NULL)
1803 		(void) fclose(psvc_hdl.fp);
1804 	psvc_fini(hdlp);
1805 }
1806 
1807 void
1808 psvc_plugin_register(void)
1809 {
1810 	picld_plugin_register(&psvc_reg);
1811 }
1812