xref: /illumos-gate/usr/src/cmd/picl/plugins/sun4u/psvc/psvcplugin/psvcplugin.c (revision d48be21240dfd051b689384ce2b23479d757f2d8)
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 *
522 run_policies(void *ptr)
523 {
524 	EInterval_t *ip = ptr;
525 	ETask_t *tp;
526 	int32_t i, j;
527 
528 	do {
529 		if (ip->interval) {
530 			int remaining = ip->interval;
531 			do {
532 				/* check to see if we've been told to exit */
533 				if (ip->has_thread && (ip->interval == 0))
534 					break;
535 				remaining = sleep(remaining);
536 			} while (remaining > 0);
537 		}
538 		for (i = 0; i < ip->num_tasks; ++i) {
539 			tp = &ip->task_list[i];
540 			for (j = 0; j < tp->num_objects; ++j) {
541 				/* check to see if we've been told to exit */
542 				if (ip->has_thread && (ip->interval == 0))
543 					break;
544 				lock_and_run(tp, j);
545 			}
546 			if (ip->has_thread && (ip->interval == 0))
547 				break;
548 		}
549 	} while (ip->interval);
550 
551 	return (NULL);
552 }
553 
554 static void thread_setup(EInterval_t *ip)
555 {
556 	int32_t status;
557 
558 	status = pthread_create(&ip->thread, NULL, run_policies, ip);
559 	if (status != 0) {
560 		if (debug_flag)
561 			syslog(LOG_ERR, "%s", strerror(errno));
562 		exit(-1);
563 	}
564 	ip->has_thread = 1;
565 }
566 
567 static int32_t load_policy(const char *library, ETask_t *tp)
568 {
569 	tp->hdl = dlopen(library, RTLD_NOW | RTLD_GLOBAL);
570 	if (tp->hdl == NULL) {
571 		if (debug_flag) {
572 			char *errstr = dlerror();
573 			syslog(LOG_ERR, "%s", errstr);
574 		}
575 		exit(1);
576 	}
577 	tp->funcp = (int32_t (*)(void *, char *))dlsym(tp->hdl, tp->routine);
578 	if (tp->funcp == NULL) {
579 		if (debug_flag) {
580 			char *errstr = dlerror();
581 			syslog(LOG_ERR, "%s", errstr);
582 		}
583 		exit(1);
584 	}
585 	return (0);
586 }
587 
588 static int32_t get_timeout(FILE *fp, int *timeout)
589 {
590 	char buf[BUFSZ];
591 	char name[32];
592 	char *cp;
593 
594 	/* skip blank lines */
595 	do {
596 		cp = fgets(buf, BUFSZ, fp);
597 		if (cp == NULL)
598 			return (1);
599 		while (isspace(*cp))
600 			++cp;
601 		(void) sscanf(buf, "%31s %d", name, timeout);
602 	} while (*cp == 0 || *cp == '\n' || strcmp(name, "TIMEOUT") != 0);
603 
604 	if (strcmp(name, "TIMEOUT") != 0) {
605 		errno = EINVAL;
606 		return (-1);
607 	}
608 	return (0);
609 
610 }
611 
612 static int32_t load_interval(FILE *fp, EInterval_t **ipp)
613 {
614 	char buf[BUFSZ];
615 	int32_t found;
616 	EInterval_t *ip;
617 	ETask_t *tp;
618 	int32_t tasks;
619 	int32_t status, i, j;
620 	int32_t interval;
621 	char name[32];
622 	char *cp;
623 
624 	/* skip blank lines */
625 	do {
626 		cp = fgets(buf, BUFSZ, fp);
627 		if (cp == NULL)
628 			return (1);
629 		while (isspace(*cp))
630 			++cp;
631 	} while (*cp == 0 || *cp == '\n');
632 	found = sscanf(buf, "%31s %d %d", name, &interval, &tasks);
633 	if (found != 3) {
634 		errno = EINVAL;
635 		return (-1);
636 	}
637 
638 	if (strcmp(name, "INTERVAL") != 0) {
639 		errno = EINVAL;
640 		return (-1);
641 	}
642 
643 	ip = (EInterval_t *)malloc(sizeof (EInterval_t));
644 	if (ip == NULL)
645 		return (-1);
646 	ip->num_tasks = tasks;
647 	ip->interval = interval;
648 	ip->next = NULL;
649 	ip->has_thread = 0;
650 
651 	/* allocate and load table */
652 	ip->task_list = (ETask_t *)malloc(ip->num_tasks * sizeof (ETask_t));
653 	if (ip->task_list == NULL)
654 		return (-1);
655 	for (i = 0; i < ip->num_tasks; ++i) {
656 		tp = &ip->task_list[i];
657 
658 		(void) fgets(buf, BUFSZ, fp);
659 		found = sscanf(buf, "%31s %1023s %63s",
660 		    name, library, tp->routine);
661 		if (found != 3) {
662 			errno = EINVAL;
663 			return (-1);
664 		}
665 
666 		status = load_policy(library, tp);
667 		if (status == -1)
668 			return (-1);
669 		found = fscanf(fp, "%d", &tp->num_objects);
670 		if (found != 1) {
671 			if (debug_flag)
672 				syslog(LOG_ERR, "No list of objects for task");
673 			errno = EINVAL;
674 			return (-1);
675 		}
676 		tp->obj_list =
677 		    (EName_t *)malloc(tp->num_objects * sizeof (EName_t));
678 		if (tp->obj_list == NULL)
679 			return (-1);
680 
681 		for (j = 0; j < tp->num_objects; ++j) {
682 			found = fscanf(fp, "%31s", (char *)(tp->obj_list + j));
683 			if (found != 1) {
684 				if (debug_flag)
685 					syslog(LOG_ERR,
686 					"Wrong number of objects for task");
687 				errno = EINVAL;
688 				return (-1);
689 			}
690 		}
691 		(void) fgets(buf, BUFSZ, fp);  /* reads newline on data line */
692 		(void) fgets(buf, BUFSZ, fp);
693 		if (strncmp(buf, "TASK_END", 8) != 0) {
694 			if (debug_flag)
695 				syslog(LOG_ERR, "Expected TASK_END, task %s",
696 				    tp->routine);
697 			errno = EINVAL;
698 			return (-1);
699 		}
700 	}
701 
702 	(void) fgets(buf, BUFSZ, fp);
703 	if (strncmp(buf, "INTERVAL_END", 12) != 0) {
704 		if (debug_flag)
705 			syslog(LOG_ERR, "Expected INTERVAL_END");
706 		errno = EINVAL;
707 		return (-1);
708 	}
709 
710 	*ipp = ip;
711 	return (0);
712 }
713 
714 void
715 fini_daemon(void)
716 {
717 	EInterval_t *ip;
718 
719 	/* shut down the threads running the policies */
720 	for (ip = first_interval; ip != NULL; ip = ip->next) {
721 		if (ip->has_thread) {
722 			/*
723 			 * there is a thread for this interval; tell it to stop
724 			 * by clearing the interval
725 			 */
726 			ip->interval = 0;
727 		}
728 	}
729 	for (ip = first_interval; ip != NULL; ip = ip->next) {
730 		if (ip->has_thread) {
731 			(void) pthread_join(ip->thread, NULL);
732 		}
733 	}
734 	/* shut down the timer thread */
735 	while (timer_state != READY)
736 		(void) sched_yield();
737 	(void) pthread_mutex_lock(&timer_mutex);
738 	timer_state = TIMER_SHUTDOWN;
739 	(void) pthread_cond_signal(&timer_cond);
740 	(void) pthread_mutex_unlock(&timer_mutex);
741 	(void) pthread_join(timer_thread_id, NULL);
742 	(void) pthread_mutex_destroy(&env_lock_mutex);
743 	(void) pthread_mutex_destroy(&timer_mutex);
744 	(void) pthread_cond_destroy(&timer_cond);
745 	(void) sem_destroy(&timer_sem);
746 }
747 
748 void
749 init_daemon(void)
750 {
751 	int32_t intervals = 0;
752 	int32_t threads = 0;
753 	int32_t status;
754 	FILE *fp;
755 	char filename[PATH_MAX];
756 	char platform[64];
757 	EInterval_t *ip, *prev;
758 
759 	if (sysinfo(SI_PLATFORM, platform, sizeof (platform)) == -1) {
760 		if (debug_flag)
761 			syslog(LOG_ERR, "%s", strerror(errno));
762 		return;
763 	}
764 
765 	(void) snprintf(filename, sizeof (filename),
766 	    "/usr/platform/%s/lib/platsvcd.conf", platform);
767 	if ((fp = fopen(filename, "r")) == NULL) {
768 		if (debug_flag)
769 			syslog(LOG_ERR, "%s", strerror(errno));
770 		return;
771 	}
772 
773 	status = get_timeout(fp, &app_timeout);
774 	if (status != 0) {
775 		if (debug_flag)
776 			syslog(LOG_ERR, "%s", strerror(errno));
777 		return;
778 	}
779 
780 	status = sem_init(&timer_sem, 0, 1);
781 	if (status == -1) {
782 		if (debug_flag)
783 			syslog(LOG_ERR, "%s", strerror(errno));
784 		return;
785 	}
786 
787 	(void) strlcpy(env_lock_state, PSVC_LOCK_ENABLED, LOCK_STRING_MAX);
788 	(void) pthread_mutex_init(&env_lock_mutex, NULL);
789 	(void) pthread_mutex_init(&timer_mutex, NULL);
790 	(void) pthread_cond_init(&timer_cond, NULL);
791 
792 	timer_state = NOT_READY;
793 	status = pthread_create(&timer_thread_id, NULL,
794 	    (void *(*)())timer_thread, 0);
795 	if (status != 0) {
796 		if (debug_flag)
797 			syslog(LOG_ERR, "%s", strerror(errno));
798 		return;
799 	}
800 
801 	/* get timer thread running */
802 	while (timer_state != READY)
803 		(void) sched_yield();
804 
805 	for (;;) {
806 		status = load_interval(fp, &ip);
807 		if (status != 0)
808 			break;
809 
810 #ifdef	lint
811 		prev = NULL;
812 #endif
813 		if (first_interval == 0)
814 			first_interval = ip;
815 		else
816 			prev->next = ip;
817 		prev = ip;
818 
819 		++intervals;
820 		if (ip->interval == 0) {
821 			run_policies(ip);
822 		} else {
823 			thread_setup(ip);
824 			++threads;
825 		}
826 	}
827 	if (intervals == 0) {
828 		if (debug_flag)
829 			syslog(LOG_ERR, "ERROR: No policies started");
830 		return;
831 	}
832 
833 	if (status == -1) {
834 		if (debug_flag)
835 			syslog(LOG_ERR, "%s", strerror(errno));
836 		return;
837 	}
838 }
839 
840 
841 static int32_t count_records(FILE *fp, char *end, uint32_t *countp)
842 {
843 	long first_record;
844 	char *ret;
845 	char buf[BUFSZ];
846 	uint32_t count = 0;
847 
848 	first_record = ftell(fp);
849 
850 	while ((ret = fgets(buf, BUFSZ, fp)) != NULL) {
851 		if (strncmp(end, buf, strlen(end)) == 0)
852 			break;
853 		++count;
854 	}
855 
856 	if (ret == NULL) {
857 		errno = EINVAL;
858 		return (-1);
859 	}
860 
861 	(void) fseek(fp, first_record, SEEK_SET);
862 	*countp = count;
863 	return (0);
864 }
865 
866 /*
867  * Find start of a section within the config file,
868  * Returns number of records in the section.
869  * FILE *fd is set to first data record within section.
870  */
871 static int32_t
872 find_file_section(FILE *fd, char *start)
873 {
874 	char *ret;
875 	char buf[BUFSZ];
876 	char name[32];
877 	int found;
878 
879 	(void) fseek(fd, 0, SEEK_SET);
880 	while ((ret = fgets(buf, BUFSZ, fd)) != NULL) {
881 		if (strncmp(start, buf, strlen(start)) == 0)
882 			break;
883 	}
884 
885 	if (ret == NULL) {
886 		errno = EINVAL;
887 		return (-1);
888 	}
889 
890 	found = sscanf(buf, "%31s", name);
891 	if (found != 1) {
892 		errno = EINVAL;
893 		return (-1);
894 	} else {
895 		return (0);
896 	}
897 
898 }
899 
900 static int32_t name_compare_qsort(picl_psvc_t *s1, picl_psvc_t *s2)
901 {
902 	return (strcmp(s1->name, s2->name));
903 }
904 
905 static int32_t name_compare_bsearch(char *s1, picl_psvc_t *s2)
906 {
907 	return (strcmp(s1, s2->name));
908 }
909 
910 /*
911  * Create a property and add it to the specified node.
912  * PICL will take a segmentation violation if a volatile property
913  * has a non-zero size.
914  */
915 static int32_t node_property(picl_nodehdl_t node,
916 	int (*read)(ptree_rarg_t *, void *),
917 	int (*write)(ptree_warg_t *, const void *), picl_prop_type_t type,
918 	unsigned int size, unsigned int accessmode, char *name, void *value)
919 {
920 	ptree_propinfo_t propinfo;
921 	picl_prophdl_t prophdl;
922 	int err;
923 
924 	propinfo.version = PSVC_PLUGIN_VERSION;
925 	if (accessmode & PICL_VOLATILE) {
926 		propinfo.read = read;
927 		propinfo.write = write;
928 	} else {
929 		propinfo.read = NULL;
930 		propinfo.write = NULL;
931 	}
932 	propinfo.piclinfo.type = type;
933 	propinfo.piclinfo.accessmode = accessmode;
934 	propinfo.piclinfo.size = size;
935 	(void) strcpy(propinfo.piclinfo.name, name);
936 
937 	err = ptree_create_prop(&propinfo, value, &prophdl);
938 	if (err != 0) {
939 		return (err);
940 	}
941 
942 	err = ptree_add_prop(node, prophdl);
943 	if (err != 0)
944 		return (err);
945 
946 	return (0);
947 }
948 
949 static void init_err(const char *fmt, char *arg1, char *arg2)
950 {
951 	char msg[256];
952 
953 	(void) snprintf(msg, sizeof (msg), fmt, arg1, arg2);
954 	syslog(LOG_ERR, "%s", msg);
955 }
956 
957 static int
958 projected_lookup(picl_prophdl_t proph, struct proj_prop **dstp)
959 {
960 	int i;
961 
962 	for (i = 0; i < proj_prop_count; ++i) {
963 		if (prop_list[i].handle == proph) {
964 			*dstp = &prop_list[i];
965 			return (PICL_SUCCESS);
966 		}
967 	}
968 
969 	return (PICL_INVALIDHANDLE);
970 }
971 
972 int
973 projected_read(ptree_rarg_t *rarg, void *buf)
974 {
975 	ptree_propinfo_t propinfo;
976 	struct proj_prop *dstinfo;
977 	int err;
978 
979 	err = projected_lookup(rarg->proph, &dstinfo);
980 	if (err != 0) {
981 		return (PICL_FAILURE);
982 	}
983 
984 
985 	err = ptree_get_propinfo(rarg->proph, &propinfo);
986 	if (err != 0)
987 		return (err);
988 	err = ptree_get_propval_by_name(dstinfo->dst_node,
989 	    dstinfo->name, buf, propinfo.piclinfo.size);
990 	if (err != 0)
991 		return (err);
992 	return (PICL_SUCCESS);
993 }
994 
995 int
996 projected_write(ptree_warg_t *warg, const void *buf)
997 {
998 	ptree_propinfo_t propinfo;
999 	struct proj_prop *dstinfo;
1000 	int err;
1001 
1002 	err = projected_lookup(warg->proph, &dstinfo);
1003 	if (err != 0) {
1004 		return (PICL_FAILURE);
1005 	}
1006 
1007 	err = ptree_get_propinfo(warg->proph, &propinfo);
1008 	if (err != 0)
1009 		return (err);
1010 	err = ptree_update_propval_by_name(dstinfo->dst_node,
1011 	    dstinfo->name, buf, propinfo.piclinfo.size);
1012 	if (err != 0)
1013 		return (err);
1014 	return (PICL_SUCCESS);
1015 }
1016 
1017 int
1018 psvc_read_volatile(ptree_rarg_t *rarg, void *buf)
1019 {
1020 	ptree_propinfo_t propinfo;
1021 	char name[32], class[32];
1022 	int err, i;
1023 	int32_t attr_num = -1;
1024 	int32_t use_attr_num = 0;
1025 
1026 	err = ptree_get_propval_by_name(rarg->nodeh, "name", name,
1027 	    sizeof (name));
1028 	if (err != 0) {
1029 		return (err);
1030 	}
1031 
1032 	err = ptree_get_propval_by_name(rarg->nodeh, "_class", class,
1033 	    sizeof (class));
1034 	if (err != 0) {
1035 		return (err);
1036 	}
1037 
1038 	err = ptree_get_propinfo(rarg->proph, &propinfo);
1039 	if (err != 0) {
1040 		return (err);
1041 	}
1042 
1043 	for (i = 0; i < PICL_PROP_TRANS_COUNT; i++) {
1044 		if ((strcmp(class, picl_prop_trans[i].picl_class) == 0) &&
1045 		    (strcmp(propinfo.piclinfo.name,
1046 		    picl_prop_trans[i].picl_prop) == 0)) {
1047 			attr_num = i;
1048 			break;
1049 		}
1050 	}
1051 
1052 	if (attr_num == -1)
1053 		for (i = 0; i < ATTR_STR_TAB_SIZE; i++) {
1054 			if (strcmp(propinfo.piclinfo.name,
1055 			    attr_str_tab[i]) == 0) {
1056 				attr_num = i;
1057 				use_attr_num = 1;
1058 				break;
1059 			}
1060 		}
1061 
1062 	if (use_attr_num)
1063 		err = psvc_get_attr(hdlp, name, attr_num, buf);
1064 	else
1065 		err = psvc_get_attr(hdlp, name,
1066 		    picl_prop_trans[attr_num].psvc_prop,
1067 		    buf);
1068 
1069 	if (err != 0) {
1070 		return (PICL_FAILURE);
1071 	}
1072 	return (PICL_SUCCESS);
1073 }
1074 
1075 int
1076 psvc_write_volatile(ptree_warg_t *warg, const void *buf)
1077 {
1078 	ptree_propinfo_t propinfo;
1079 	char name[32], class[32];
1080 	int err, i;
1081 	int32_t attr_num = -1;
1082 	int32_t use_attr_num = 0;
1083 
1084 	if (warg->cred.dc_euid != 0)
1085 		return (PICL_PERMDENIED);
1086 
1087 	err = ptree_get_propval_by_name(warg->nodeh, "name", name,
1088 	    sizeof (name));
1089 	if (err != 0) {
1090 		return (err);
1091 	}
1092 
1093 	err = ptree_get_propval_by_name(warg->nodeh, "_class", class,
1094 	    sizeof (class));
1095 	if (err != 0) {
1096 		return (err);
1097 	}
1098 
1099 	err = ptree_get_propinfo(warg->proph, &propinfo);
1100 	if (err != 0) {
1101 		return (err);
1102 	}
1103 
1104 	for (i = 0; i < PICL_PROP_TRANS_COUNT; i++) {
1105 		if ((strcmp(class, picl_prop_trans[i].picl_class) == 0) &&
1106 		    (strcmp(propinfo.piclinfo.name,
1107 		    picl_prop_trans[i].picl_prop) == 0)) {
1108 			attr_num = i;
1109 			break;
1110 		}
1111 	}
1112 
1113 	if (attr_num == -1)
1114 		for (i = 0; i < ATTR_STR_TAB_SIZE; i++) {
1115 			if (strcmp(propinfo.piclinfo.name,
1116 			    attr_str_tab[i]) == 0) {
1117 			attr_num = i;
1118 			use_attr_num = 1;
1119 			break;
1120 			}
1121 		}
1122 
1123 	if (use_attr_num)
1124 		err = psvc_set_attr(hdlp, name, attr_num, (void *)buf);
1125 	else
1126 		err = psvc_set_attr(hdlp, name,
1127 		    picl_prop_trans[attr_num].psvc_prop,
1128 		    (void *)buf);
1129 
1130 	if (err != 0) {
1131 		return (PICL_FAILURE);
1132 	}
1133 
1134 	return (PICL_SUCCESS);
1135 }
1136 
1137 void create_reference_properties(struct assoc_pair *assoc_tbl, int32_t count,
1138 	char *assoc_name)
1139 {
1140 	picl_psvc_t *aobjp, *dobjp;
1141 	picl_prophdl_t tbl_hdl;
1142 	picl_nodehdl_t *dep_list;
1143 	ptree_propinfo_t propinfo;
1144 	char *funcname = "create_reference_properties";
1145 	char name[PICL_PROPNAMELEN_MAX];
1146 	int32_t i, j, offset;
1147 	int32_t dependents;
1148 	int32_t err;
1149 	char class[PICL_CLASSNAMELEN_MAX];
1150 
1151 	for (i = 0; i < count; ++i) {
1152 		/* antecedent */
1153 		aobjp = (picl_psvc_t *)bsearch(assoc_tbl[i].antecedent,
1154 		    psvc_hdl.objects, psvc_hdl.obj_count,
1155 		    sizeof (picl_psvc_t),
1156 		    (int (*)(const void *, const void *))
1157 		    name_compare_bsearch);
1158 		if (aobjp == NULL) {
1159 			init_err(ID_NOT_FOUND_MSG,
1160 			    funcname, assoc_tbl[i].antecedent);
1161 			return;
1162 		}
1163 
1164 		/* skip if table already created */
1165 		if (ptree_get_propval_by_name(aobjp->node, assoc_name,
1166 		    &tbl_hdl, sizeof (tbl_hdl)) == 0) {
1167 			continue;
1168 		}
1169 
1170 		/* create a new table */
1171 		err = ptree_create_table(&tbl_hdl);
1172 		if (err != 0) {
1173 			init_err(PTREE_CREATE_TABLE_FAILED_MSG,
1174 			    funcname, picl_strerror(err));
1175 			return;
1176 		}
1177 
1178 		err = node_property(aobjp->node, NULL, NULL,
1179 		    PICL_PTYPE_TABLE, sizeof (tbl_hdl), PICL_READ,
1180 		    assoc_name, &tbl_hdl);
1181 		if (err != 0) {
1182 			init_err(CREATE_PROP_FAILED_MSG, funcname,
1183 			    picl_strerror(err));
1184 			return;
1185 		}
1186 
1187 		/* determine number of elements in the table */
1188 		dependents = 0;
1189 		for (j = i; j < count; ++j) {
1190 			if (strcmp(aobjp->name, assoc_tbl[j].antecedent) == 0)
1191 				++dependents;
1192 		}
1193 
1194 		dep_list = (picl_nodehdl_t *)malloc(sizeof (picl_nodehdl_t) *
1195 		    dependents);
1196 		if (dep_list == NULL) {
1197 			init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1198 			return;
1199 		}
1200 		/* build row of reference properties */
1201 		offset = 0;
1202 		for (j = i; j < count; ++j) {
1203 			if (strcmp(aobjp->name, assoc_tbl[j].antecedent) != 0)
1204 				continue;
1205 
1206 			dobjp = (picl_psvc_t *)bsearch(assoc_tbl[j].dependent,
1207 			    psvc_hdl.objects,
1208 			    psvc_hdl.obj_count, sizeof (picl_psvc_t),
1209 			    (int (*)(const void *, const void *))
1210 			    name_compare_bsearch);
1211 			if (dobjp == NULL) {
1212 				init_err(ID_NOT_FOUND_MSG,
1213 				    funcname, assoc_tbl[j].dependent);
1214 				return;
1215 			}
1216 
1217 			/*
1218 			 * Reference property name must be
1219 			 * _classname_propertyname
1220 			 */
1221 			err = ptree_get_propval_by_name(dobjp->node,
1222 			    "_class", class, sizeof (class));
1223 			if (err != 0) {
1224 				init_err(CLASS_NOT_FOUND_MSG, funcname,
1225 				    assoc_tbl[j].dependent);
1226 				return;
1227 			}
1228 			(void) snprintf(name, sizeof (name), "_%s_subclass",
1229 			    class);
1230 
1231 			propinfo.version = PSVC_PLUGIN_VERSION;
1232 			propinfo.read = NULL;
1233 			propinfo.write = NULL;
1234 			propinfo.piclinfo.type = PICL_PTYPE_REFERENCE;
1235 			propinfo.piclinfo.accessmode = PICL_READ;
1236 			propinfo.piclinfo.size = sizeof (picl_nodehdl_t);
1237 			(void) strcpy(propinfo.piclinfo.name, name);
1238 
1239 			err = ptree_create_prop(&propinfo, &dobjp->node,
1240 			    dep_list + offset);
1241 			if (err != 0) {
1242 				init_err(PTREE_CREATE_PROP_FAILED_MSG,
1243 				    name, picl_strerror(err));
1244 				return;
1245 			}
1246 
1247 			++offset;
1248 		}
1249 
1250 		/* add row to table */
1251 		err = ptree_add_row_to_table(tbl_hdl, dependents, dep_list);
1252 		if (err != 0) {
1253 			init_err(PTREE_ADD_ROW_FAILED_MSG, funcname,
1254 			    picl_strerror(err));
1255 			return;
1256 		}
1257 
1258 	}
1259 
1260 
1261 }
1262 
1263 /* Load projected properties */
1264 static void
1265 load_projected_properties(FILE *fp)
1266 {
1267 	int32_t found;
1268 	ptree_propinfo_t propinfo;
1269 	ptree_propinfo_t dstinfo;
1270 	picl_prophdl_t src_prophdl, dst_prophdl;
1271 	picl_nodehdl_t src_node, dst_node;
1272 	int err, i;
1273 	picl_psvc_t *srcobjp, *dstobjp;
1274 	char src[32], dst[256];
1275 	char src_prop[32], dst_prop[32];
1276 	char buf[BUFSZ];
1277 	char *funcname = "load_projected_properties";
1278 
1279 	if (find_file_section(fp, "PROJECTED_PROPERTIES") != 0)
1280 		return;
1281 
1282 	if (count_records(fp, "PROJECTED_PROPERTIES_END", &proj_prop_count) !=
1283 	    0) {
1284 		init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1285 		return;
1286 	}
1287 
1288 	prop_list = (struct proj_prop *)malloc(sizeof (struct proj_prop)
1289 	    * proj_prop_count);
1290 	if (prop_list == NULL) {
1291 		init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1292 		return;
1293 	}
1294 
1295 	for (i = 0; i < proj_prop_count; ++i) {
1296 		buf[0] = '\0';
1297 		(void) fgets(buf, BUFSZ, fp);
1298 		found = sscanf(buf, "%31s %31s %255s %31s", src, src_prop, dst,
1299 		    dst_prop);
1300 		if (found != 4) {
1301 			init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1302 			return;
1303 		}
1304 
1305 		/* find src node */
1306 		if (src[0] == '/') {
1307 			/* picl node name, outside psvc subtree */
1308 			err = ptree_get_node_by_path(src, &src_node);
1309 			if (err != 0) {
1310 				init_err(NODE_NOT_FOUND_MSG, funcname, src);
1311 				return;
1312 			}
1313 		} else {
1314 			srcobjp = (picl_psvc_t *)bsearch(src, psvc_hdl.objects,
1315 			    psvc_hdl.obj_count, sizeof (picl_psvc_t),
1316 			    (int (*)(const void *, const void *))
1317 			    name_compare_bsearch);
1318 			if (srcobjp == NULL) {
1319 				init_err(ID_NOT_FOUND_MSG, funcname, src);
1320 				return;
1321 			}
1322 			src_node = srcobjp->node;
1323 		}
1324 
1325 		/* find dest node */
1326 		if (dst[0] == '/') {
1327 			/* picl node name, outside psvc subtree */
1328 			err = ptree_get_node_by_path(dst, &dst_node);
1329 			if (err != 0) {
1330 				init_err(NODE_NOT_FOUND_MSG, funcname, dst);
1331 				return;
1332 			}
1333 			prop_list[i].dst_node = dst_node;
1334 		} else {
1335 			dstobjp = (picl_psvc_t *)bsearch(dst, psvc_hdl.objects,
1336 			    psvc_hdl.obj_count, sizeof (picl_psvc_t),
1337 			    (int (*)(const void *, const void *))
1338 			    name_compare_bsearch);
1339 			if (dstobjp == NULL) {
1340 				init_err(ID_NOT_FOUND_MSG, funcname, dst);
1341 				return;
1342 			}
1343 			dst_node = dstobjp->node;
1344 			prop_list[i].dst_node = dst_node;
1345 		}
1346 
1347 		/* determine destination property size */
1348 		err = ptree_get_first_prop(dst_node, &dst_prophdl);
1349 		while (err == 0) {
1350 			err = ptree_get_propinfo(dst_prophdl, &dstinfo);
1351 			if (err != 0)
1352 				break;
1353 			if (strcmp(dst_prop, dstinfo.piclinfo.name) == 0)
1354 				break;
1355 			err = ptree_get_next_prop(dst_prophdl, &dst_prophdl);
1356 		}
1357 		if (err != 0) {
1358 			init_err(SIZE_NOT_FOUND_MSG, funcname, dst_prop);
1359 			return;
1360 		}
1361 
1362 		propinfo.version = PSVC_PLUGIN_VERSION;
1363 		propinfo.read = projected_read;
1364 		propinfo.write = projected_write;
1365 		propinfo.piclinfo.type = dstinfo.piclinfo.type;
1366 		propinfo.piclinfo.accessmode =
1367 		    PICL_READ | PICL_WRITE | PICL_VOLATILE;
1368 		propinfo.piclinfo.size = dstinfo.piclinfo.size;
1369 		(void) strcpy(propinfo.piclinfo.name, src_prop);
1370 
1371 		err = ptree_create_prop(&propinfo, 0, &src_prophdl);
1372 		if (err != 0) {
1373 			init_err(PTREE_CREATE_PROP_FAILED_MSG, funcname,
1374 			    picl_strerror(err));
1375 			return;
1376 		}
1377 
1378 		err = ptree_add_prop(src_node, src_prophdl);
1379 		if (err != 0) {
1380 			init_err(PTREE_ADD_PROP_FAILED_MSG, funcname,
1381 			    picl_strerror(err));
1382 			return;
1383 		}
1384 
1385 		prop_list[i].handle = src_prophdl;
1386 		(void) strcpy(prop_list[i].name, dst_prop);
1387 
1388 	}
1389 }
1390 
1391 /* Load the association table */
1392 static void load_associations(FILE *fp)
1393 {
1394 	char *funcname = "load_associations";
1395 	uint32_t count;
1396 	int found;
1397 	int j;
1398 	char assoc_name[32];
1399 	struct assoc_pair *assoc_tbl;
1400 	char name1[32];
1401 	char buf[BUFSZ];
1402 
1403 	/*
1404 	 * ignore count in the file, correct count is highest
1405 	 * association id + 1, now figured when loading ASSOC_STR
1406 	 * section.
1407 	 */
1408 	if (find_file_section(fp, "ASSOCIATIONS") != 0)
1409 		return;
1410 
1411 	buf[0] = '\0';
1412 	(void) fgets(buf, BUFSZ, fp);
1413 	while (strncmp("ASSOCIATIONS_END", buf, 16) != 0) {
1414 		found = sscanf(buf, "%31s %31s", name1, assoc_name);
1415 		if (found != 2) {
1416 			init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1417 			return;
1418 		}
1419 
1420 		if (count_records(fp, "ASSOCIATION_END", &count) != 0) {
1421 			init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1422 			return;
1423 		}
1424 
1425 		assoc_tbl = (struct assoc_pair *)malloc(
1426 		    sizeof (struct assoc_pair) * count);
1427 		if (assoc_tbl == NULL) {
1428 			init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1429 			return;
1430 		}
1431 
1432 		for (j = 0; j < count; ++j) {
1433 			buf[0] = '\0';
1434 			(void) fgets(buf, BUFSZ, fp);
1435 			found = sscanf(buf, "%31s %31s",
1436 			    assoc_tbl[j].antecedent, assoc_tbl[j].dependent);
1437 			if (found != 2) {
1438 				init_err(INVALID_FILE_FORMAT_MSG, funcname,
1439 				    0);
1440 				return;
1441 			}
1442 
1443 		}
1444 		buf[0] = '\0';
1445 		(void) fgets(buf, BUFSZ, fp);
1446 		if (strncmp(buf, "ASSOCIATION_END", 15) != 0) {
1447 			init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1448 			return;
1449 		}
1450 
1451 		/* Create separate list of dependents for each antecedent */
1452 		if (strcmp(assoc_name, "PSVC_TABLE") != 0) {
1453 			create_reference_properties(assoc_tbl, count,
1454 			    assoc_name);
1455 		}
1456 
1457 		free(assoc_tbl);
1458 		buf[0] = '\0';
1459 		(void) fgets(buf, BUFSZ, fp);
1460 	}
1461 
1462 }
1463 
1464 /* Enviornmental Lock Object's Read and Write routine */
1465 /* ARGSUSED */
1466 static int
1467 env_lock_read(ptree_rarg_t *rarg, void *buf)
1468 {
1469 	(void) strlcpy((char *)buf, env_lock_state, LOCK_STRING_MAX);
1470 	return (PSVC_SUCCESS);
1471 }
1472 
1473 /* ARGSUSED */
1474 static int
1475 env_lock_write(ptree_warg_t *warg, const void *buf)
1476 {
1477 	int32_t status = PSVC_SUCCESS;
1478 	char *var = (char *)buf;
1479 
1480 	/*
1481 	 * Check to make sure that the value is either Disabled or Enabled
1482 	 * as these are the only 2 states that this object can be set to.
1483 	 */
1484 	if ((strcmp(var, PSVC_LOCK_DISABLED) != 0) &&
1485 	    (strcmp(var, PSVC_LOCK_ENABLED) != 0)) {
1486 		errno = EINVAL;
1487 		return (PSVC_FAILURE);
1488 	}
1489 
1490 	(void) pthread_mutex_lock(&env_lock_mutex);
1491 
1492 	/*
1493 	 * If the state is already Enabled we can set the state to Disabled
1494 	 * to stop the policies.
1495 	 */
1496 	if (strcmp(env_lock_state, PSVC_LOCK_ENABLED) == 0) {
1497 		(void) pthread_mutex_unlock(&env_lock_mutex);
1498 		status = timed_lock_wait(PSVC_LOCK_DISABLED);
1499 		if (status == -1) {
1500 			syslog(LOG_ERR, SEM_WAIT_FAILED_MSG);
1501 		}
1502 		return (status);
1503 	}
1504 
1505 	/*
1506 	 * If the state is Running we must go into timed_lock_wait to aquire
1507 	 * the env_lock.
1508 	 */
1509 	if (strcmp(env_lock_state, PSVC_LOCK_RUNNING) == 0) {
1510 		(void) pthread_mutex_unlock(&env_lock_mutex);
1511 		status = timed_lock_wait(PSVC_LOCK_DISABLED);
1512 		if (status == -1) {
1513 			syslog(LOG_ERR, SEM_WAIT_FAILED_MSG);
1514 		}
1515 		return (status);
1516 	}
1517 
1518 	/*
1519 	 * If the state is already Disabled we need to first check to see if
1520 	 * we are resetting it to Disabled or changing it to Enabled. If we
1521 	 * are resetting it to Disabled then we need to stop the timer and
1522 	 * restart it. If we are changing it to Enabled we just set it to
1523 	 * enabled.
1524 	 */
1525 	if (strcmp(env_lock_state, PSVC_LOCK_DISABLED) == 0) {
1526 		if (strcmp(var, PSVC_LOCK_DISABLED) == 0) {
1527 			(void) pthread_mutex_lock(&timer_mutex);
1528 			if (timer_state == ACTIVE) {
1529 				timer_state = NOT_READY;
1530 				/* stop timer */
1531 				(void) pthread_cond_signal(&timer_cond);
1532 				(void) pthread_mutex_unlock(&timer_mutex);
1533 				/* wait for timer to reset */
1534 				while (timer_state != READY)
1535 					(void) sched_yield();
1536 				(void) pthread_mutex_lock(&timer_mutex);
1537 				timer_state = HAVE_REQUEST;
1538 				/* restart timer */
1539 				(void) pthread_cond_signal(&timer_cond);
1540 			}
1541 			(void) pthread_mutex_unlock(&timer_mutex);
1542 		} else {
1543 			(void) strlcpy(env_lock_state, var, LOCK_STRING_MAX);
1544 		}
1545 	}
1546 	(void) pthread_mutex_unlock(&env_lock_mutex);
1547 	return (PSVC_SUCCESS);
1548 }
1549 
1550 static int
1551 init_env_lock_node(picl_nodehdl_t root_node)
1552 {
1553 	int err;
1554 	ptree_propinfo_t propinfo;
1555 	char *funcname = "init_env_lock_node";
1556 
1557 	/* Here we are creating a Enviornmental Lock Node */
1558 	err = ptree_create_node("/plugins/environmental", "picl", &lock_node);
1559 	if (err != PICL_SUCCESS) {
1560 		init_err(PTREE_CREATE_NODE_FAILED_MSG, funcname,
1561 		    picl_strerror(err));
1562 		return (err);
1563 	}
1564 
1565 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION_1,
1566 	    PICL_PTYPE_CHARSTRING, PICL_READ | PICL_WRITE | PICL_VOLATILE,
1567 	    32, "State", env_lock_read, env_lock_write);
1568 	if (err != PICL_SUCCESS) {
1569 		init_err(NODE_PROP_FAILED_MSG, funcname, picl_strerror(err));
1570 		return (err);
1571 	}
1572 
1573 	err = ptree_create_and_add_prop(lock_node, &propinfo,
1574 	    NULL, NULL);
1575 	if (err != PICL_SUCCESS) {
1576 		init_err(PTREE_ADD_PROP_FAILED_MSG, funcname,
1577 		    picl_strerror(err));
1578 		return (err);
1579 	}
1580 
1581 	err = ptree_add_node(root_node, lock_node);
1582 	if (err != PICL_SUCCESS) {
1583 		init_err(PTREE_ADD_NODE_FAILED_MSG, funcname,
1584 		    picl_strerror(err));
1585 		return (err);
1586 	}
1587 
1588 	return (PSVC_SUCCESS);
1589 }
1590 
1591 void
1592 psvc_plugin_init(void)
1593 {
1594 	struct classinfo *cp;
1595 	picl_nodehdl_t root_node;
1596 	picl_nodehdl_t parent_node;
1597 	char *funcname = "psvc_plugin_init";
1598 	char platform[32];
1599 	char filename[256];
1600 	char buf[BUFSZ];
1601 	int32_t i, j;
1602 	int err, found;
1603 
1604 	psvc_paths = NULL;
1605 	psvc_hdl.obj_count = 0;
1606 	psvc_hdl.objects = NULL;
1607 	psvc_hdl.fp = NULL;
1608 	first_interval = NULL;
1609 
1610 	/*
1611 	 * So the volatile read/write routines can retrieve data from
1612 	 * psvc or picl
1613 	 */
1614 	err = psvc_init(&hdlp);
1615 	if (err != 0) {
1616 		init_err(PSVC_INIT_ERR_MSG, funcname, strerror(errno));
1617 	}
1618 
1619 	if (sysinfo(SI_PLATFORM, platform, sizeof (platform)) == -1) {
1620 		init_err(SYSINFO_FAILED_MSG, funcname, 0);
1621 		return;
1622 	}
1623 
1624 	(void) snprintf(filename, sizeof (filename),
1625 	    "/usr/platform/%s/lib/psvcobj.conf", platform);
1626 	if ((psvc_hdl.fp = fopen(filename, "r")) == NULL) {
1627 		init_err(FILE_OPEN_FAILED_MSG, funcname, filename);
1628 		return;
1629 	}
1630 
1631 	/* Create all PICL nodes */
1632 	if (find_file_section(psvc_hdl.fp, "OBJECT_INFO") == -1) {
1633 		init_err(INVALID_FILE_FORMAT1_MSG, funcname, filename);
1634 		return;
1635 	}
1636 	if (count_records(psvc_hdl.fp, "OBJECT_INFO_END", &psvc_hdl.obj_count)
1637 	    == -1) {
1638 		init_err(INVALID_FILE_FORMAT1_MSG, funcname, filename);
1639 		return;
1640 	}
1641 	if ((psvc_hdl.objects = (picl_psvc_t *)malloc(sizeof (picl_psvc_t) *
1642 	    psvc_hdl.obj_count)) == NULL) {
1643 		init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1644 		return;
1645 	}
1646 	(void) memset(psvc_hdl.objects, 0,
1647 	    sizeof (picl_psvc_t) * psvc_hdl.obj_count);
1648 
1649 	err = ptree_get_root(&root_node);
1650 	if (err != 0) {
1651 		init_err(PTREE_GET_ROOT_FAILED_MSG, funcname,
1652 		    picl_strerror(err));
1653 		return;
1654 	}
1655 
1656 	/* Following array is  accessed directly by the psvc policies. */
1657 	psvc_paths = (psvc_name_t *)malloc(sizeof (psvc_name_t) *
1658 	    psvc_hdl.obj_count);
1659 	psvc_picl_nodes = psvc_hdl.obj_count;
1660 	if (psvc_paths == NULL) {
1661 		init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1662 		return;
1663 	}
1664 	for (i = 0; i < psvc_hdl.obj_count; ++i) {
1665 		char *start;
1666 		int32_t class;
1667 		int32_t subclass;
1668 		int32_t	cp_count;
1669 		picl_psvc_t *objp = &psvc_hdl.objects[i];
1670 		buf[0] = '\0';
1671 		(void) fgets(buf, BUFSZ, psvc_hdl.fp);
1672 		if (strncmp(buf, "OBJECT_INFO_END", 15) == 0)
1673 			break;
1674 
1675 		start = strrchr(buf, '/');
1676 		if (start == NULL) {
1677 			init_err(INVALID_FILE_FORMAT1_MSG, funcname,
1678 			    filename);
1679 			return;
1680 		}
1681 		found = sscanf(start + 1, "%31s",  objp->name);
1682 		if (found != 1) {
1683 			init_err(INVALID_FILE_FORMAT1_MSG, funcname,
1684 			    filename);
1685 			return;
1686 		}
1687 
1688 		/* get class */
1689 		err = psvc_get_attr(hdlp, objp->name, PSVC_CLASS_ATTR, &class);
1690 		if (err != PSVC_SUCCESS) {
1691 			init_err(CLASS_NOT_FOUND_MSG, funcname, objp->name);
1692 			return;
1693 		}
1694 		if (class > NUM_CLASSES) {
1695 			init_err(UNKNOWN_CLASS_MSG, funcname, 0);
1696 			return;
1697 		}
1698 
1699 		err = psvc_get_attr(hdlp, objp->name, PSVC_SUBCLASS_ATTR,
1700 		    &subclass);
1701 		if (err != PSVC_SUCCESS) {
1702 			init_err(SUBCLASS_NOT_FOUND_MSG, funcname, objp->name);
1703 			return;
1704 		}
1705 
1706 		err = ptree_create_node(objp->name, class_name[class],
1707 		    &objp->node);
1708 		if (err != 0) {
1709 			init_err(PTREE_CREATE_NODE_FAILED_MSG, funcname,
1710 			    picl_strerror(err));
1711 			return;
1712 		}
1713 		if (strcmp(objp->name, PSVC_CHASSIS) == 0)
1714 			system_node = objp->node;
1715 
1716 		for (j = 0; j < COMMON_COUNT; ++j) {
1717 
1718 			err = node_property(objp->node,
1719 			    common[j].access & PICL_READ ?
1720 			    psvc_read_volatile : 0,
1721 			    common[j].access & PICL_WRITE ?
1722 			    psvc_write_volatile : 0,
1723 			    common[j].type, common[j].size,
1724 			    common[j].access, common[j].name, 0);
1725 			if (err != PSVC_SUCCESS) {
1726 				init_err(NODE_PROP_FAILED_MSG, funcname,
1727 				    picl_strerror(err));
1728 				return;
1729 			}
1730 		}
1731 		cp = &class_properties[class];
1732 		/* Locator LED Support */
1733 		if (class == 2 && subclass == 2) {
1734 			cp_count = 3;
1735 		} else {
1736 			cp_count = cp->count;
1737 		}
1738 
1739 		for (j = 0; j < cp_count; ++j) {
1740 			err = node_property(objp->node, psvc_read_volatile,
1741 			    psvc_write_volatile, cp->props[j].type,
1742 			    cp->props[j].size,
1743 			    cp->props[j].access, cp->props[j].name, 0);
1744 			if (err != PSVC_SUCCESS) {
1745 				init_err(NODE_PROP_FAILED_MSG, funcname,
1746 				    picl_strerror(err));
1747 				return;
1748 			}
1749 		}
1750 
1751 		/* Link the nodes into the PICL tree */
1752 		*start = 0;
1753 		if (start == buf) {	/* no parent */
1754 			parent_node = root_node;
1755 		} else {
1756 			err = ptree_get_node_by_path(buf, &parent_node);
1757 			if (err != PICL_SUCCESS) {
1758 				init_err(NODE_NOT_FOUND_MSG, funcname, buf);
1759 				return;
1760 			}
1761 		}
1762 
1763 		err = ptree_add_node(parent_node, objp->node);
1764 		if (err != PICL_SUCCESS) {
1765 			init_err(PTREE_ADD_NODE_FAILED_MSG, funcname,
1766 			    picl_strerror(err));
1767 			return;
1768 		}
1769 		(void) strcpy(psvc_paths[i].parent_path, buf);
1770 		(void) strcpy(psvc_paths[i].child_name, objp->name);
1771 		psvc_paths[i].child_node = objp->node;
1772 	}
1773 
1774 	qsort(psvc_hdl.objects, psvc_hdl.obj_count, sizeof (picl_psvc_t),
1775 	    (int (*)(const void *, const void *))name_compare_qsort);
1776 
1777 	load_associations(psvc_hdl.fp);
1778 	load_projected_properties(psvc_hdl.fp);
1779 
1780 	if (init_env_lock_node(root_node) != PSVC_SUCCESS)
1781 		return;
1782 
1783 	init_daemon();
1784 }
1785 
1786 void
1787 psvc_plugin_fini(void)
1788 {
1789 	int32_t i;
1790 	EInterval_t *ip, *next;
1791 
1792 	fini_daemon();
1793 	for (ip = first_interval; ip != 0; ip = next) {
1794 		for (i = 0; i < ip->num_tasks; ++i) {
1795 			(void) dlclose(ip->task_list[i].hdl);
1796 			free(ip->task_list[i].obj_list);
1797 		}
1798 		free(ip->task_list);
1799 		next = ip->next;
1800 		free(ip);
1801 	}
1802 	free(prop_list);
1803 	free(psvc_paths);
1804 	free(psvc_hdl.objects);
1805 	if (psvc_hdl.fp != NULL)
1806 		(void) fclose(psvc_hdl.fp);
1807 	psvc_fini(hdlp);
1808 }
1809 
1810 void
1811 psvc_plugin_register(void)
1812 {
1813 	picld_plugin_register(&psvc_reg);
1814 }
1815