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