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