xref: /onnv-gate/usr/src/cmd/picl/plugins/sun4u/psvc/psvcplugin/psvcplugin.c (revision 11740:b0979c952e12)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*11740SJustin.Frank@Sun.COM  * Common Development and Distribution License (the "License").
6*11740SJustin.Frank@Sun.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*11740SJustin.Frank@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * PICL plug-in to create environment tree nodes.
280Sstevel@tonic-gate  * This plugin should only be installed in the platform directories
290Sstevel@tonic-gate  * of supported systems, such as /usr/platform/picl/plugins/SUNW,<>.
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <picl.h>
330Sstevel@tonic-gate #include <picltree.h>
340Sstevel@tonic-gate #include <stdio.h>
350Sstevel@tonic-gate #include <time.h>
360Sstevel@tonic-gate #include <dlfcn.h>
370Sstevel@tonic-gate #include <fcntl.h>
380Sstevel@tonic-gate #include <unistd.h>
390Sstevel@tonic-gate #include <stdlib.h>
400Sstevel@tonic-gate #include <limits.h>
410Sstevel@tonic-gate #include  <ctype.h>
420Sstevel@tonic-gate #include <pthread.h>
430Sstevel@tonic-gate #include <libintl.h>
440Sstevel@tonic-gate #include <errno.h>
450Sstevel@tonic-gate #include <semaphore.h>
460Sstevel@tonic-gate #include <sched.h>
470Sstevel@tonic-gate #include <syslog.h>
480Sstevel@tonic-gate #include <string.h>
490Sstevel@tonic-gate #include <signal.h>
500Sstevel@tonic-gate #include <sys/types.h>
510Sstevel@tonic-gate #include <sys/systeminfo.h>
520Sstevel@tonic-gate #include <psvc_objects.h>
530Sstevel@tonic-gate #include <psvc_objects_class.h>
540Sstevel@tonic-gate 
550Sstevel@tonic-gate #define	BUFSZ	512
560Sstevel@tonic-gate 
570Sstevel@tonic-gate typedef struct {
580Sstevel@tonic-gate 	char	name[32];
590Sstevel@tonic-gate } EName_t;
600Sstevel@tonic-gate 
610Sstevel@tonic-gate typedef struct {
62*11740SJustin.Frank@Sun.COM 	void *hdl;
630Sstevel@tonic-gate 	int32_t (*funcp)(void *, char *);
640Sstevel@tonic-gate 	int32_t	num_objects;
650Sstevel@tonic-gate 	EName_t *obj_list;
660Sstevel@tonic-gate 	char    routine[64];
670Sstevel@tonic-gate } ETask_t;
680Sstevel@tonic-gate 
690Sstevel@tonic-gate typedef struct interval_info {
70*11740SJustin.Frank@Sun.COM 	volatile int32_t   interval;
710Sstevel@tonic-gate 	int32_t	  num_tasks;
720Sstevel@tonic-gate 	ETask_t   *task_list;
730Sstevel@tonic-gate 	pthread_t thread;
74*11740SJustin.Frank@Sun.COM 	int32_t   has_thread;
750Sstevel@tonic-gate 	struct interval_info *next;
760Sstevel@tonic-gate } EInterval_t;
770Sstevel@tonic-gate 
780Sstevel@tonic-gate static EInterval_t *first_interval;
790Sstevel@tonic-gate 
800Sstevel@tonic-gate static psvc_opaque_t hdlp;
810Sstevel@tonic-gate 
820Sstevel@tonic-gate sem_t timer_sem;
83*11740SJustin.Frank@Sun.COM pthread_mutex_t timer_mutex;
84*11740SJustin.Frank@Sun.COM pthread_cond_t timer_cond;
850Sstevel@tonic-gate pthread_t timer_thread_id;
860Sstevel@tonic-gate 
870Sstevel@tonic-gate extern int ptree_get_node_by_path(const char *, picl_nodehdl_t *);
880Sstevel@tonic-gate 
890Sstevel@tonic-gate /* Timer states */
900Sstevel@tonic-gate #define	NOT_READY	0
910Sstevel@tonic-gate #define	READY		1
920Sstevel@tonic-gate #define	HAVE_REQUEST	2
930Sstevel@tonic-gate #define	ACTIVE		3
94*11740SJustin.Frank@Sun.COM #define	TIMER_SHUTDOWN	4
950Sstevel@tonic-gate 
960Sstevel@tonic-gate int timer_state = NOT_READY;
970Sstevel@tonic-gate 
980Sstevel@tonic-gate int app_timeout;
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate /* Lock State Loop State Definitions */
1010Sstevel@tonic-gate #define	STATE_CHANGED		1
1020Sstevel@tonic-gate #define	STATE_NOT_CHANGED	0
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate #ifdef DEBUG
1050Sstevel@tonic-gate static int32_t debug_flag = 1;
1060Sstevel@tonic-gate #else
1070Sstevel@tonic-gate static int32_t debug_flag = 0;
1080Sstevel@tonic-gate #endif
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate static char library[PATH_MAX];
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate #define	PSVC_PLUGIN_VERSION	PICLD_PLUGIN_VERSION_1
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate #pragma init(psvc_plugin_register)	/* place in .init section */
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate typedef struct  {
1170Sstevel@tonic-gate 	char	parent_path[256];
1180Sstevel@tonic-gate 	char    child_name[32];
1190Sstevel@tonic-gate 	picl_nodehdl_t	child_node;
1200Sstevel@tonic-gate } psvc_name_t;
1210Sstevel@tonic-gate psvc_name_t *psvc_paths;
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate #define	MUTEX_LOCK_FAILED_MSG	gettext("platsvcd: pthread_mutex_lock %s\n")
1240Sstevel@tonic-gate #define	CV_WAIT_FAILED_MSG	gettext("platsvcd: pthread_cond_wait %s\n")
1250Sstevel@tonic-gate #define	CV_TWAIT_FAILED_MSG gettext("platsvcd: pthread_cond_timed_wait %s\n")
1260Sstevel@tonic-gate #define	SEM_WAIT_FAILED_MSG	gettext("platsvcd: sem_wait failed %s\n")
1270Sstevel@tonic-gate #define	PSVC_APP_DEATH_MSG	gettext("PSVC application death detected\n")
1280Sstevel@tonic-gate #define	POLICY_FAILED_MSG	gettext("ERROR running %s on %s (%d)")
1290Sstevel@tonic-gate #define	ID_NOT_FOUND_MSG	gettext("%s: Can't determine id of %s\n")
1300Sstevel@tonic-gate #define	CLASS_NOT_FOUND_MSG	gettext("%s: Can't determine class of %s\n")
1310Sstevel@tonic-gate #define	SUBCLASS_NOT_FOUND_MSG	gettext("%s: Can't determine subclass of %s\n")
1320Sstevel@tonic-gate #define	NODE_NOT_FOUND_MSG	gettext("%s: Can't determine node of %s\n")
1330Sstevel@tonic-gate #define	SIZE_NOT_FOUND_MSG	gettext("%s: Couldn't determine size of %s\n")
1340Sstevel@tonic-gate #define	PTREE_CREATE_TABLE_FAILED_MSG		\
1350Sstevel@tonic-gate 	gettext("%s: ptree_create_table failed, %s\n")
1360Sstevel@tonic-gate #define	PTREE_CREATE_PROP_FAILED_MSG		\
1370Sstevel@tonic-gate 	gettext("%s: ptree_create_prop failed, %s\n")
1380Sstevel@tonic-gate #define	PTREE_CREATE_NODE_FAILED_MSG		\
1390Sstevel@tonic-gate 	gettext("%s: ptree_create_node failed, %s\n")
1400Sstevel@tonic-gate #define	PTREE_ADD_ROW_FAILED_MSG gettext("%s: ptree_add_row_to_table: %s\n")
1410Sstevel@tonic-gate #define	PTREE_ADD_NODE_FAILED_MSG gettext("%s: ptree_add_node: %s\n")
1420Sstevel@tonic-gate #define	PTREE_ADD_PROP_FAILED_MSG gettext("%s: ptree_add_prop: %s\n")
1430Sstevel@tonic-gate #define	PTREE_GET_ROOT_FAILED_MSG gettext("%s: ptree_get_root: %s\n")
1440Sstevel@tonic-gate #define	CREATE_PROP_FAILED_MSG	gettext("%s: Error creating property %s\n")
1450Sstevel@tonic-gate #define	INVALID_FILE_FORMAT_MSG		gettext("%s: Invalid file format\n")
1460Sstevel@tonic-gate #define	INVALID_FILE_FORMAT1_MSG	gettext("%s: Invalid file format %s\n")
1470Sstevel@tonic-gate #define	PSVC_INIT_ERR_MSG	gettext("%s: Error in psvc_init(): %s\n")
1480Sstevel@tonic-gate #define	SYSINFO_FAILED_MSG	gettext("%s: Can't determine platform type\n")
1490Sstevel@tonic-gate #define	FILE_OPEN_FAILED_MSG	gettext("%s: Can't open file %s\n")
1500Sstevel@tonic-gate #define	MALLOC_FAILED_MSG	gettext("%s: malloc failed, %s\n")
1510Sstevel@tonic-gate #define	UNKNOWN_CLASS_MSG	gettext("%s: Unknown class\n")
1520Sstevel@tonic-gate #define	NODE_PROP_FAILED_MSG	gettext("%s: node_property: %s\n")
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate #define	LOCK_STRING_MAX 32
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate picl_nodehdl_t system_node;
1570Sstevel@tonic-gate static picl_nodehdl_t lock_node;
1580Sstevel@tonic-gate static char env_lock_state[LOCK_STRING_MAX] = PSVC_LOCK_ENABLED;
159*11740SJustin.Frank@Sun.COM static pthread_mutex_t env_lock_mutex;
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate static char *class_name[] = {
1620Sstevel@tonic-gate "temperature-sensor",
1630Sstevel@tonic-gate "fan",
1640Sstevel@tonic-gate "led",
1650Sstevel@tonic-gate "picl",
1660Sstevel@tonic-gate "digital-sensor",
1670Sstevel@tonic-gate "digital-control",
1680Sstevel@tonic-gate "gpio",
1690Sstevel@tonic-gate "fan-tachometer",
1700Sstevel@tonic-gate "switch",
1710Sstevel@tonic-gate "keyswitch",
1720Sstevel@tonic-gate "gpio",
1730Sstevel@tonic-gate "i2c"
1740Sstevel@tonic-gate };
1750Sstevel@tonic-gate #define	NUM_CLASSES (sizeof (class_name) / sizeof (char *))
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate struct proj_prop {	/* projected property */
1780Sstevel@tonic-gate 	picl_prophdl_t	handle;
1790Sstevel@tonic-gate 	picl_nodehdl_t  dst_node;
1800Sstevel@tonic-gate 	char		name[32];
1810Sstevel@tonic-gate };
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate struct propinfo {
1840Sstevel@tonic-gate 	char		*name;
1850Sstevel@tonic-gate 	uint32_t	type;
1860Sstevel@tonic-gate 	uint32_t	size;
1870Sstevel@tonic-gate 	uint32_t	access;
1880Sstevel@tonic-gate };
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate struct propinfo common[] = {
1910Sstevel@tonic-gate 	{"State", PICL_PTYPE_CHARSTRING, 32,
1920Sstevel@tonic-gate 	PICL_READ | PICL_WRITE | PICL_VOLATILE},
1930Sstevel@tonic-gate 	{"FaultInformation", PICL_PTYPE_CHARSTRING, 32,
1940Sstevel@tonic-gate 	PICL_READ | PICL_VOLATILE}
1950Sstevel@tonic-gate };
1960Sstevel@tonic-gate #define	COMMON_COUNT (sizeof (common) / sizeof (struct propinfo))
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate struct propinfo led_properties[] = {
1990Sstevel@tonic-gate 	{"Color", PICL_PTYPE_CHARSTRING, 32, PICL_READ | PICL_VOLATILE},
2000Sstevel@tonic-gate 	{"IsLocator", PICL_PTYPE_CHARSTRING, 32, PICL_READ | PICL_VOLATILE},
2010Sstevel@tonic-gate 	{"LocatorName", PICL_PTYPE_CHARSTRING, 32, PICL_READ | PICL_VOLATILE}
2020Sstevel@tonic-gate };
2030Sstevel@tonic-gate /*
2040Sstevel@tonic-gate  * We define the amount of LED properties to 1 because not all LED's have
2050Sstevel@tonic-gate  * the two remainding properties.  This number is augmented in psvc_plugin_init
2060Sstevel@tonic-gate  * when it sees an LED of subclass 2.
2070Sstevel@tonic-gate  */
2080Sstevel@tonic-gate #define	LED_COUNT 1
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate struct propinfo temperature_sensor_properties[] = {
2110Sstevel@tonic-gate 	{"Temperature", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE},
2120Sstevel@tonic-gate 	{"LowWarningThreshold", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE},
2130Sstevel@tonic-gate 	{"LowShutdownThreshold", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE},
2140Sstevel@tonic-gate 	{"HighWarningThreshold", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE},
2150Sstevel@tonic-gate 	{"HighShutdownThreshold", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE}
2160Sstevel@tonic-gate };
2170Sstevel@tonic-gate #define	TEMP_SENSOR_COUNT \
2180Sstevel@tonic-gate 	(sizeof (temperature_sensor_properties) / sizeof (struct propinfo))
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate struct propinfo digi_sensor_properties[] = {
2210Sstevel@tonic-gate 	{"AtoDSensorValue", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE},
2220Sstevel@tonic-gate 	{"LowWarningThreshold", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE},
2230Sstevel@tonic-gate 	{"LowShutdownThreshold", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE},
2240Sstevel@tonic-gate 	{"HighWarningThreshold", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE},
2250Sstevel@tonic-gate 	{"HighShutdownThreshold", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE}
2260Sstevel@tonic-gate };
2270Sstevel@tonic-gate #define	DIGI_SENSOR_COUNT \
2280Sstevel@tonic-gate 	(sizeof (digi_sensor_properties) / sizeof (struct propinfo))
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate struct propinfo boolgpio_properties[] = {
2310Sstevel@tonic-gate 	{"Gpio-value", PICL_PTYPE_UNSIGNED_INT, sizeof (boolean_t),
2320Sstevel@tonic-gate 	PICL_READ | PICL_WRITE | PICL_VOLATILE},
2330Sstevel@tonic-gate 	{"#Bits", PICL_PTYPE_UNSIGNED_INT, 4, PICL_READ |PICL_VOLATILE}
2340Sstevel@tonic-gate };
2350Sstevel@tonic-gate #define	BOOLGPIO_COUNT (sizeof (boolgpio_properties) / sizeof (struct propinfo))
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate struct propinfo gpio8_properties[] = {
2380Sstevel@tonic-gate 	{"Gpio-value", PICL_PTYPE_UNSIGNED_INT, 1,
2390Sstevel@tonic-gate 	PICL_READ | PICL_WRITE | PICL_VOLATILE},
2400Sstevel@tonic-gate 	{"#Bits", PICL_PTYPE_UNSIGNED_INT, 4, PICL_READ |PICL_VOLATILE}
2410Sstevel@tonic-gate };
2420Sstevel@tonic-gate #define	GPIO8_COUNT (sizeof (gpio8_properties) / sizeof (struct propinfo))
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate struct propinfo digictrl_properties[] = {
2450Sstevel@tonic-gate 	{"DtoAControlValue", PICL_PTYPE_INT, 4,
2460Sstevel@tonic-gate 	PICL_READ | PICL_WRITE | PICL_VOLATILE},
2470Sstevel@tonic-gate };
2480Sstevel@tonic-gate #define	DIGICTRL_COUNT (sizeof (digictrl_properties) / sizeof (struct propinfo))
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate struct classinfo {
2510Sstevel@tonic-gate 	struct propinfo	*props;
2520Sstevel@tonic-gate 	int32_t		count;
2530Sstevel@tonic-gate } class_properties[] =
2540Sstevel@tonic-gate {
2550Sstevel@tonic-gate 	{temperature_sensor_properties, TEMP_SENSOR_COUNT}, /* temp sensor */
2560Sstevel@tonic-gate 	{0, 0},				/* fan, only has projected properties */
2570Sstevel@tonic-gate 	{led_properties, LED_COUNT},
2580Sstevel@tonic-gate 	{0, 0},						  /* system class */
2590Sstevel@tonic-gate 	{digi_sensor_properties, DIGI_SENSOR_COUNT}, /* digital sensor */
2600Sstevel@tonic-gate 	{digictrl_properties, DIGICTRL_COUNT},
2610Sstevel@tonic-gate 	{boolgpio_properties, BOOLGPIO_COUNT},
2620Sstevel@tonic-gate 	{digi_sensor_properties, DIGI_SENSOR_COUNT}, /* fan tach */
2630Sstevel@tonic-gate 	{0, 0},
2640Sstevel@tonic-gate 	{0, 0},
2650Sstevel@tonic-gate 	{gpio8_properties, GPIO8_COUNT},
2660Sstevel@tonic-gate 	{0, 0},
2670Sstevel@tonic-gate };
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate struct prop_trans {
2700Sstevel@tonic-gate 	char *picl_class;
2710Sstevel@tonic-gate 	char *picl_prop;
2720Sstevel@tonic-gate 	int32_t psvc_prop;
2730Sstevel@tonic-gate } picl_prop_trans[] =
2740Sstevel@tonic-gate {
2750Sstevel@tonic-gate 	{"digital-sensor", "AtoDSensorValue", PSVC_SENSOR_VALUE_ATTR},
2760Sstevel@tonic-gate 	{"digital-sensor", "LowWarningThreshold", PSVC_LO_WARN_ATTR},
2770Sstevel@tonic-gate 	{"digital-sensor", "LowShutdownThreshold", PSVC_LO_SHUT_ATTR},
2780Sstevel@tonic-gate 	{"digital-sensor", "HighWarningThreshold", PSVC_HI_WARN_ATTR},
2790Sstevel@tonic-gate 	{"digital-sensor", "HighShutdownThreshold", PSVC_HI_SHUT_ATTR},
2800Sstevel@tonic-gate 	{"digital-control", "DtoAControlValue", PSVC_CONTROL_VALUE_ATTR},
2810Sstevel@tonic-gate 	{"fan-tachometer", "AtoDSensorValue", PSVC_SENSOR_VALUE_ATTR},
2820Sstevel@tonic-gate 	{"fan-tachometer", "LowWarningThreshold", PSVC_LO_WARN_ATTR},
2830Sstevel@tonic-gate 	{"fan-tachometer", "LowShutdownThreshold", PSVC_LO_SHUT_ATTR},
2840Sstevel@tonic-gate 	{"fan-tachometer", "HighWarningThreshold", PSVC_HI_WARN_ATTR},
2850Sstevel@tonic-gate 	{"fan-tachometer", "HighShutdownThreshold", PSVC_HI_SHUT_ATTR},
2860Sstevel@tonic-gate 	{"temperature-sensor", "Temperature", PSVC_SENSOR_VALUE_ATTR},
2870Sstevel@tonic-gate 	{"temperature-sensor", "LowWarningThreshold", PSVC_LO_WARN_ATTR},
2880Sstevel@tonic-gate 	{"temperature-sensor", "LowShutdownThreshold", PSVC_LO_SHUT_ATTR},
2890Sstevel@tonic-gate 	{"temperature-sensor", "HighWarningThreshold", PSVC_HI_WARN_ATTR},
2900Sstevel@tonic-gate 	{"temperature-sensor", "HighShutdownThreshold", PSVC_HI_SHUT_ATTR},
2910Sstevel@tonic-gate 	{"led", "State", PSVC_LED_STATE_ATTR},
2920Sstevel@tonic-gate 	{"led", "Color", PSVC_LED_COLOR_ATTR},
2930Sstevel@tonic-gate 	{"switch", "State", PSVC_SWITCH_STATE_ATTR},
2940Sstevel@tonic-gate 	{"keyswitch", "State", PSVC_SWITCH_STATE_ATTR},
2950Sstevel@tonic-gate 	{"i2c", "State", PSVC_PROBE_RESULT_ATTR}
2960Sstevel@tonic-gate };
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate #define	PICL_PROP_TRANS_COUNT \
2990Sstevel@tonic-gate 	(sizeof (picl_prop_trans) / sizeof (struct prop_trans))
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate typedef struct {
3030Sstevel@tonic-gate 	char		name[32];
3040Sstevel@tonic-gate 	picl_nodehdl_t	node;
3050Sstevel@tonic-gate } picl_psvc_t;
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate struct assoc_pair {
3080Sstevel@tonic-gate 	char	antecedent[32];
3090Sstevel@tonic-gate 	char	dependent[32];
3100Sstevel@tonic-gate };
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate struct handle {
3130Sstevel@tonic-gate 	uint32_t    obj_count;
3140Sstevel@tonic-gate 	picl_psvc_t *objects;
3150Sstevel@tonic-gate 	FILE	*fp;
3160Sstevel@tonic-gate } psvc_hdl;
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate struct proj_prop *prop_list;
3190Sstevel@tonic-gate uint32_t proj_prop_count;
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate int psvc_picl_nodes;
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate void psvc_plugin_init(void);
3240Sstevel@tonic-gate void psvc_plugin_fini(void);
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate picld_plugin_reg_t psvc_reg = {
3270Sstevel@tonic-gate 	PSVC_PLUGIN_VERSION,
3280Sstevel@tonic-gate 	PICLD_PLUGIN_CRITICAL,
3290Sstevel@tonic-gate 	"PSVC",
3300Sstevel@tonic-gate 	psvc_plugin_init,
3310Sstevel@tonic-gate 	psvc_plugin_fini
3320Sstevel@tonic-gate };
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate /*
3350Sstevel@tonic-gate  * psvcplugin_add_children was written so that devices which are hotplugable
3360Sstevel@tonic-gate  * will be able to add in all thier children and children's children. The
3370Sstevel@tonic-gate  * routine takes in the path of a parent and then searches the psvc_paths
3380Sstevel@tonic-gate  * array to find all of it's children.  It in turns adds the child and then
3390Sstevel@tonic-gate  * recursively check to see if it had children and add them too.
3400Sstevel@tonic-gate  */
3410Sstevel@tonic-gate void
psvcplugin_add_children(char * parent_path)3420Sstevel@tonic-gate psvcplugin_add_children(char *parent_path)
3430Sstevel@tonic-gate {
3440Sstevel@tonic-gate 	int i;
3450Sstevel@tonic-gate 	picl_nodehdl_t parent_node;
3460Sstevel@tonic-gate 	char next_path[256];
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	for (i = 0; i < psvc_picl_nodes; ++i) {
3490Sstevel@tonic-gate 		if (strcmp(parent_path, psvc_paths[i].parent_path) == 0) {
3500Sstevel@tonic-gate 			ptree_get_node_by_path(parent_path, &parent_node);
3510Sstevel@tonic-gate 			ptree_add_node(parent_node, psvc_paths[i].child_node);
352*11740SJustin.Frank@Sun.COM 			(void) snprintf(next_path, sizeof (next_path), "%s/%s",
3530Sstevel@tonic-gate 			    parent_path, psvc_paths[i].child_name);
3540Sstevel@tonic-gate 			psvcplugin_add_children(next_path);
3550Sstevel@tonic-gate 		}
3560Sstevel@tonic-gate 	}
3570Sstevel@tonic-gate }
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate void
psvcplugin_lookup(char * name,char * parent,picl_nodehdl_t * node)3600Sstevel@tonic-gate psvcplugin_lookup(char *name, char *parent, picl_nodehdl_t *node)
3610Sstevel@tonic-gate {
3620Sstevel@tonic-gate 	int i;
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 	for (i = 0; i < psvc_picl_nodes; ++i) {
3650Sstevel@tonic-gate 		if (strcmp(name, psvc_paths[i].child_name) == 0) {
366*11740SJustin.Frank@Sun.COM 			(void) strcpy(parent, psvc_paths[i].parent_path);
3670Sstevel@tonic-gate 			*node = psvc_paths[i].child_node;
3680Sstevel@tonic-gate 		}
3690Sstevel@tonic-gate 	}
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate void
timer_thread(void)373*11740SJustin.Frank@Sun.COM timer_thread(void)
3740Sstevel@tonic-gate {
3750Sstevel@tonic-gate 	struct timespec timeout;
3760Sstevel@tonic-gate 	int status;
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	status = pthread_mutex_lock(&timer_mutex);
3800Sstevel@tonic-gate 	if (status != 0) {
3810Sstevel@tonic-gate 		syslog(LOG_ERR, MUTEX_LOCK_FAILED_MSG, strerror(status));
3820Sstevel@tonic-gate 	}
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	for (;;) {
3850Sstevel@tonic-gate 		/* wait for thread to tell us to start timer */
3860Sstevel@tonic-gate 		timer_state = READY;
3870Sstevel@tonic-gate 		do {
3880Sstevel@tonic-gate 			status = pthread_cond_wait(&timer_cond, &timer_mutex);
3890Sstevel@tonic-gate 		} while (timer_state == READY && status == 0);
3900Sstevel@tonic-gate 
391*11740SJustin.Frank@Sun.COM 		if (timer_state == TIMER_SHUTDOWN) {
392*11740SJustin.Frank@Sun.COM 			pthread_exit(NULL);
393*11740SJustin.Frank@Sun.COM 			/* not reached */
394*11740SJustin.Frank@Sun.COM 		}
395*11740SJustin.Frank@Sun.COM 
3960Sstevel@tonic-gate 		if (status != 0) {
3970Sstevel@tonic-gate 			syslog(LOG_ERR, CV_WAIT_FAILED_MSG, strerror(status));
3980Sstevel@tonic-gate 		}
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 		/*
4010Sstevel@tonic-gate 		 * Will get signalled after semaphore acquired,
4020Sstevel@tonic-gate 		 * or when timeout occurs.
4030Sstevel@tonic-gate 		 */
404*11740SJustin.Frank@Sun.COM 		(void) clock_gettime(CLOCK_REALTIME, &timeout);
4050Sstevel@tonic-gate 		timeout.tv_sec += app_timeout;
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 		if (timer_state == HAVE_REQUEST) {
4080Sstevel@tonic-gate 			timer_state = ACTIVE;
4090Sstevel@tonic-gate 			do {
4100Sstevel@tonic-gate 				status = pthread_cond_timedwait(&timer_cond,
411*11740SJustin.Frank@Sun.COM 				    &timer_mutex, &timeout);
4120Sstevel@tonic-gate 			} while (timer_state == ACTIVE && status == 0);
4130Sstevel@tonic-gate 		}
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 		if (status != 0) {
4160Sstevel@tonic-gate 			if (status == ETIMEDOUT) {
4170Sstevel@tonic-gate 				syslog(LOG_ERR, PSVC_APP_DEATH_MSG);
418*11740SJustin.Frank@Sun.COM 				(void) pthread_mutex_lock(&env_lock_mutex);
419*11740SJustin.Frank@Sun.COM 				(void) strlcpy(env_lock_state,
420*11740SJustin.Frank@Sun.COM 				    PSVC_LOCK_ENABLED, LOCK_STRING_MAX);
421*11740SJustin.Frank@Sun.COM 				(void) pthread_mutex_unlock(&env_lock_mutex);
4220Sstevel@tonic-gate 			} else {
4230Sstevel@tonic-gate 				syslog(LOG_ERR, CV_TWAIT_FAILED_MSG,
424*11740SJustin.Frank@Sun.COM 				    strerror(status));
4250Sstevel@tonic-gate 			}
4260Sstevel@tonic-gate 		}
4270Sstevel@tonic-gate 	}
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate static int
lock_state_loop(char * set_lock_state)4310Sstevel@tonic-gate lock_state_loop(char *set_lock_state)
4320Sstevel@tonic-gate {
433*11740SJustin.Frank@Sun.COM 	(void) pthread_mutex_lock(&env_lock_mutex);
4340Sstevel@tonic-gate 	if (strcmp(env_lock_state, PSVC_LOCK_ENABLED) == 0) {
435*11740SJustin.Frank@Sun.COM 		(void) strlcpy(env_lock_state, set_lock_state, LOCK_STRING_MAX);
436*11740SJustin.Frank@Sun.COM 		(void) pthread_mutex_unlock(&env_lock_mutex);
4370Sstevel@tonic-gate 		return (STATE_NOT_CHANGED);
4380Sstevel@tonic-gate 	}
439*11740SJustin.Frank@Sun.COM 	(void) pthread_mutex_unlock(&env_lock_mutex);
4400Sstevel@tonic-gate 	return (STATE_CHANGED);
4410Sstevel@tonic-gate }
4420Sstevel@tonic-gate 
timed_lock_wait(char * set_lock_state)4430Sstevel@tonic-gate static int timed_lock_wait(char *set_lock_state)
4440Sstevel@tonic-gate {
4450Sstevel@tonic-gate 	int32_t status;
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 	/* Only want one timer active at a time */
4480Sstevel@tonic-gate 	do {
4490Sstevel@tonic-gate 		status = sem_wait(&timer_sem);
4500Sstevel@tonic-gate 	} while (status == -1 && errno == EINTR);
4510Sstevel@tonic-gate 	if (status == -1)
4520Sstevel@tonic-gate 		return (status);
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	while (timer_state != READY)
455*11740SJustin.Frank@Sun.COM 		(void) sched_yield();
456*11740SJustin.Frank@Sun.COM 	(void) pthread_mutex_lock(&timer_mutex);
4570Sstevel@tonic-gate 	timer_state = HAVE_REQUEST;
458*11740SJustin.Frank@Sun.COM 	(void) pthread_cond_signal(&timer_cond);	/* start timer */
459*11740SJustin.Frank@Sun.COM 	(void) pthread_mutex_unlock(&timer_mutex);
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 	/*
4620Sstevel@tonic-gate 	 * We now spin checking the state env_lock_state for it to change to
4630Sstevel@tonic-gate 	 * enabled.
4640Sstevel@tonic-gate 	 */
4650Sstevel@tonic-gate 	while (lock_state_loop(set_lock_state))
466*11740SJustin.Frank@Sun.COM 		(void) sleep(1);
4670Sstevel@tonic-gate 
468*11740SJustin.Frank@Sun.COM 	(void) pthread_mutex_lock(&timer_mutex);
4690Sstevel@tonic-gate 	if (timer_state == ACTIVE) {
4700Sstevel@tonic-gate 		timer_state = NOT_READY;
471*11740SJustin.Frank@Sun.COM 		(void) pthread_cond_signal(&timer_cond);	/* stop timer */
4720Sstevel@tonic-gate 	}
4730Sstevel@tonic-gate 	if (timer_state == HAVE_REQUEST) {		/* cancel request */
4740Sstevel@tonic-gate 		timer_state = NOT_READY;
4750Sstevel@tonic-gate 	}
476*11740SJustin.Frank@Sun.COM 	(void) pthread_mutex_unlock(&timer_mutex);
477*11740SJustin.Frank@Sun.COM 	(void) sem_post(&timer_sem);
4780Sstevel@tonic-gate 	return (0);
4790Sstevel@tonic-gate }
4800Sstevel@tonic-gate 
lock_and_run(ETask_t * tp,int32_t obj_num)4810Sstevel@tonic-gate static void lock_and_run(ETask_t *tp, int32_t obj_num)
4820Sstevel@tonic-gate {
4830Sstevel@tonic-gate 	int32_t status;
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	/* Grab mutex to stop the env_lock from being changed. */
486*11740SJustin.Frank@Sun.COM 	(void) pthread_mutex_lock(&env_lock_mutex);
4870Sstevel@tonic-gate 	/*
4880Sstevel@tonic-gate 	 * Check to see if the lock is anything but Enabled. If so, we then
4890Sstevel@tonic-gate 	 * goto our timer routine to wait for it to become enabled.
4900Sstevel@tonic-gate 	 * If not then set it to RUNNING and run policy.
4910Sstevel@tonic-gate 	 */
4920Sstevel@tonic-gate 	if (strcmp(env_lock_state, PSVC_LOCK_ENABLED) != 0) {
4930Sstevel@tonic-gate 		/* drop mutex and goto timer */
494*11740SJustin.Frank@Sun.COM 		(void) pthread_mutex_unlock(&env_lock_mutex);
4950Sstevel@tonic-gate 		status = timed_lock_wait(PSVC_LOCK_RUNNING);
4960Sstevel@tonic-gate 		if (status == -1) {
4970Sstevel@tonic-gate 			syslog(LOG_ERR, SEM_WAIT_FAILED_MSG);
4980Sstevel@tonic-gate 		}
4990Sstevel@tonic-gate 	} else {
500*11740SJustin.Frank@Sun.COM 		(void) strlcpy(env_lock_state, PSVC_LOCK_RUNNING,
501*11740SJustin.Frank@Sun.COM 		    LOCK_STRING_MAX);
502*11740SJustin.Frank@Sun.COM 		(void) pthread_mutex_unlock(&env_lock_mutex);
5030Sstevel@tonic-gate 	}
5040Sstevel@tonic-gate 	status = (*tp->funcp)(hdlp, (tp->obj_list + obj_num)->name);
5050Sstevel@tonic-gate 	if (status == PSVC_FAILURE && errno != ENODEV) {
5060Sstevel@tonic-gate 		char dev_name[32];
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 		psvc_get_attr(hdlp, (tp->obj_list + obj_num)->name,
5090Sstevel@tonic-gate 		    PSVC_LABEL_ATTR, dev_name);
5100Sstevel@tonic-gate 		syslog(LOG_ERR, POLICY_FAILED_MSG, tp->routine, dev_name,
5110Sstevel@tonic-gate 		    (tp->obj_list + obj_num)->name);
512*11740SJustin.Frank@Sun.COM 		syslog(LOG_ERR, "%s", strerror(errno));
5130Sstevel@tonic-gate 	}
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 	/* The policy is done so set the lock back to ENABLED. */
516*11740SJustin.Frank@Sun.COM 	(void) pthread_mutex_lock(&env_lock_mutex);
517*11740SJustin.Frank@Sun.COM 	(void) strlcpy(env_lock_state, PSVC_LOCK_ENABLED, LOCK_STRING_MAX);
518*11740SJustin.Frank@Sun.COM 	(void) pthread_mutex_unlock(&env_lock_mutex);
5190Sstevel@tonic-gate }
5200Sstevel@tonic-gate 
run_policies(EInterval_t * ip)5210Sstevel@tonic-gate static void run_policies(EInterval_t *ip)
5220Sstevel@tonic-gate {
5230Sstevel@tonic-gate 	ETask_t *tp;
5240Sstevel@tonic-gate 	int32_t i, j;
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 	do {
5270Sstevel@tonic-gate 		if (ip->interval) {
5280Sstevel@tonic-gate 			int remaining = ip->interval;
5290Sstevel@tonic-gate 			do {
530*11740SJustin.Frank@Sun.COM 				/* check to see if we've been told to exit */
531*11740SJustin.Frank@Sun.COM 				if (ip->has_thread && (ip->interval == 0))
532*11740SJustin.Frank@Sun.COM 					break;
5330Sstevel@tonic-gate 				remaining = sleep(remaining);
5340Sstevel@tonic-gate 			} while (remaining > 0);
5350Sstevel@tonic-gate 		}
5360Sstevel@tonic-gate 		for (i = 0; i < ip->num_tasks; ++i) {
5370Sstevel@tonic-gate 			tp = &ip->task_list[i];
5380Sstevel@tonic-gate 			for (j = 0; j < tp->num_objects; ++j) {
539*11740SJustin.Frank@Sun.COM 				/* check to see if we've been told to exit */
540*11740SJustin.Frank@Sun.COM 				if (ip->has_thread && (ip->interval == 0))
541*11740SJustin.Frank@Sun.COM 					break;
5420Sstevel@tonic-gate 				lock_and_run(tp, j);
5430Sstevel@tonic-gate 			}
544*11740SJustin.Frank@Sun.COM 			if (ip->has_thread && (ip->interval == 0))
545*11740SJustin.Frank@Sun.COM 				break;
5460Sstevel@tonic-gate 		}
5470Sstevel@tonic-gate 	} while (ip->interval);
5480Sstevel@tonic-gate }
5490Sstevel@tonic-gate 
thread_setup(EInterval_t * ip)5500Sstevel@tonic-gate static void thread_setup(EInterval_t *ip)
5510Sstevel@tonic-gate {
5520Sstevel@tonic-gate 	int32_t status;
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate 	status = pthread_create(&ip->thread, NULL, (void *(*)())run_policies,
555*11740SJustin.Frank@Sun.COM 	    ip);
5560Sstevel@tonic-gate 	if (status != 0) {
5570Sstevel@tonic-gate 		if (debug_flag)
558*11740SJustin.Frank@Sun.COM 			syslog(LOG_ERR, "%s", strerror(errno));
5590Sstevel@tonic-gate 		exit(-1);
5600Sstevel@tonic-gate 	}
561*11740SJustin.Frank@Sun.COM 	ip->has_thread = 1;
5620Sstevel@tonic-gate }
5630Sstevel@tonic-gate 
load_policy(const char * library,ETask_t * tp)564*11740SJustin.Frank@Sun.COM static int32_t load_policy(const char *library, ETask_t *tp)
5650Sstevel@tonic-gate {
566*11740SJustin.Frank@Sun.COM 	tp->hdl = dlopen(library, RTLD_NOW | RTLD_GLOBAL);
567*11740SJustin.Frank@Sun.COM 	if (tp->hdl == NULL) {
5680Sstevel@tonic-gate 		if (debug_flag) {
5690Sstevel@tonic-gate 			char *errstr = dlerror();
570*11740SJustin.Frank@Sun.COM 			syslog(LOG_ERR, "%s", errstr);
5710Sstevel@tonic-gate 		}
5720Sstevel@tonic-gate 		exit(1);
5730Sstevel@tonic-gate 	}
574*11740SJustin.Frank@Sun.COM 	tp->funcp = (int32_t (*)(void *, char *))dlsym(tp->hdl, tp->routine);
575*11740SJustin.Frank@Sun.COM 	if (tp->funcp == NULL) {
5760Sstevel@tonic-gate 		if (debug_flag) {
5770Sstevel@tonic-gate 			char *errstr = dlerror();
578*11740SJustin.Frank@Sun.COM 			syslog(LOG_ERR, "%s", errstr);
5790Sstevel@tonic-gate 		}
5800Sstevel@tonic-gate 		exit(1);
5810Sstevel@tonic-gate 	}
5820Sstevel@tonic-gate 	return (0);
5830Sstevel@tonic-gate }
5840Sstevel@tonic-gate 
get_timeout(FILE * fp,int * timeout)5850Sstevel@tonic-gate static int32_t get_timeout(FILE *fp, int *timeout)
5860Sstevel@tonic-gate {
5870Sstevel@tonic-gate 	char buf[BUFSZ];
5880Sstevel@tonic-gate 	char name[32];
5890Sstevel@tonic-gate 	char *cp;
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 	/* skip blank lines */
5920Sstevel@tonic-gate 	do {
5930Sstevel@tonic-gate 		cp = fgets(buf, BUFSZ, fp);
5940Sstevel@tonic-gate 		if (cp == NULL)
5950Sstevel@tonic-gate 			return (1);
5960Sstevel@tonic-gate 		while (isspace(*cp))
5970Sstevel@tonic-gate 			++cp;
598*11740SJustin.Frank@Sun.COM 		(void) sscanf(buf, "%31s %d", name, timeout);
5990Sstevel@tonic-gate 	} while (*cp == 0 || *cp == '\n' || strcmp(name, "TIMEOUT") != 0);
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 	if (strcmp(name, "TIMEOUT") != 0) {
6020Sstevel@tonic-gate 		errno = EINVAL;
6030Sstevel@tonic-gate 		return (-1);
6040Sstevel@tonic-gate 	}
6050Sstevel@tonic-gate 	return (0);
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate }
6080Sstevel@tonic-gate 
load_interval(FILE * fp,EInterval_t ** ipp)6090Sstevel@tonic-gate static int32_t load_interval(FILE *fp, EInterval_t **ipp)
6100Sstevel@tonic-gate {
6110Sstevel@tonic-gate 	char buf[BUFSZ];
6120Sstevel@tonic-gate 	int32_t found;
6130Sstevel@tonic-gate 	EInterval_t *ip;
6140Sstevel@tonic-gate 	ETask_t *tp;
6150Sstevel@tonic-gate 	int32_t tasks;
6160Sstevel@tonic-gate 	int32_t status, i, j;
6170Sstevel@tonic-gate 	int32_t interval;
6180Sstevel@tonic-gate 	char name[32];
6190Sstevel@tonic-gate 	char *cp;
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	/* skip blank lines */
6220Sstevel@tonic-gate 	do {
6230Sstevel@tonic-gate 		cp = fgets(buf, BUFSZ, fp);
6240Sstevel@tonic-gate 		if (cp == NULL)
6250Sstevel@tonic-gate 			return (1);
6260Sstevel@tonic-gate 		while (isspace(*cp))
6270Sstevel@tonic-gate 			++cp;
6280Sstevel@tonic-gate 	} while (*cp == 0 || *cp == '\n');
629*11740SJustin.Frank@Sun.COM 	found = sscanf(buf, "%31s %d %d", name, &interval, &tasks);
6300Sstevel@tonic-gate 	if (found != 3) {
6310Sstevel@tonic-gate 		errno = EINVAL;
6320Sstevel@tonic-gate 		return (-1);
6330Sstevel@tonic-gate 	}
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 	if (strcmp(name, "INTERVAL") != 0) {
6360Sstevel@tonic-gate 		errno = EINVAL;
6370Sstevel@tonic-gate 		return (-1);
6380Sstevel@tonic-gate 	}
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 	ip = (EInterval_t *)malloc(sizeof (EInterval_t));
6410Sstevel@tonic-gate 	if (ip == NULL)
6420Sstevel@tonic-gate 		return (-1);
6430Sstevel@tonic-gate 	ip->num_tasks = tasks;
6440Sstevel@tonic-gate 	ip->interval = interval;
6450Sstevel@tonic-gate 	ip->next = NULL;
646*11740SJustin.Frank@Sun.COM 	ip->has_thread = 0;
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 	/* allocate and load table */
6490Sstevel@tonic-gate 	ip->task_list = (ETask_t *)malloc(ip->num_tasks * sizeof (ETask_t));
6500Sstevel@tonic-gate 	if (ip->task_list == NULL)
6510Sstevel@tonic-gate 		return (-1);
6520Sstevel@tonic-gate 	for (i = 0; i < ip->num_tasks; ++i) {
6530Sstevel@tonic-gate 		tp = &ip->task_list[i];
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 		(void) fgets(buf, BUFSZ, fp);
656*11740SJustin.Frank@Sun.COM 		found = sscanf(buf, "%31s %1023s %63s",
657*11740SJustin.Frank@Sun.COM 		    name, library, tp->routine);
6580Sstevel@tonic-gate 		if (found != 3) {
6590Sstevel@tonic-gate 			errno = EINVAL;
6600Sstevel@tonic-gate 			return (-1);
6610Sstevel@tonic-gate 		}
6620Sstevel@tonic-gate 
663*11740SJustin.Frank@Sun.COM 		status = load_policy(library, tp);
6640Sstevel@tonic-gate 		if (status == -1)
6650Sstevel@tonic-gate 			return (-1);
6660Sstevel@tonic-gate 		found = fscanf(fp, "%d", &tp->num_objects);
6670Sstevel@tonic-gate 		if (found != 1) {
6680Sstevel@tonic-gate 			if (debug_flag)
6690Sstevel@tonic-gate 				syslog(LOG_ERR, "No list of objects for task");
6700Sstevel@tonic-gate 			errno = EINVAL;
6710Sstevel@tonic-gate 			return (-1);
6720Sstevel@tonic-gate 		}
6730Sstevel@tonic-gate 		tp->obj_list =
674*11740SJustin.Frank@Sun.COM 		    (EName_t *)malloc(tp->num_objects * sizeof (EName_t));
6750Sstevel@tonic-gate 		if (tp->obj_list == NULL)
6760Sstevel@tonic-gate 			return (-1);
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 		for (j = 0; j < tp->num_objects; ++j) {
679*11740SJustin.Frank@Sun.COM 			found = fscanf(fp, "%31s", (char *)(tp->obj_list + j));
6800Sstevel@tonic-gate 			if (found != 1) {
6810Sstevel@tonic-gate 				if (debug_flag)
6820Sstevel@tonic-gate 					syslog(LOG_ERR,
6830Sstevel@tonic-gate 					"Wrong number of objects for task");
6840Sstevel@tonic-gate 				errno = EINVAL;
6850Sstevel@tonic-gate 				return (-1);
6860Sstevel@tonic-gate 			}
6870Sstevel@tonic-gate 		}
6880Sstevel@tonic-gate 		(void) fgets(buf, BUFSZ, fp);  /* reads newline on data line */
6890Sstevel@tonic-gate 		(void) fgets(buf, BUFSZ, fp);
6900Sstevel@tonic-gate 		if (strncmp(buf, "TASK_END", 8) != 0) {
6910Sstevel@tonic-gate 			if (debug_flag)
6920Sstevel@tonic-gate 				syslog(LOG_ERR, "Expected TASK_END, task %s",
693*11740SJustin.Frank@Sun.COM 				    tp->routine);
6940Sstevel@tonic-gate 			errno = EINVAL;
6950Sstevel@tonic-gate 			return (-1);
6960Sstevel@tonic-gate 		}
6970Sstevel@tonic-gate 	}
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	(void) fgets(buf, BUFSZ, fp);
7000Sstevel@tonic-gate 	if (strncmp(buf, "INTERVAL_END", 12) != 0) {
7010Sstevel@tonic-gate 		if (debug_flag)
7020Sstevel@tonic-gate 			syslog(LOG_ERR, "Expected INTERVAL_END");
7030Sstevel@tonic-gate 		errno = EINVAL;
7040Sstevel@tonic-gate 		return (-1);
7050Sstevel@tonic-gate 	}
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate 	*ipp = ip;
7080Sstevel@tonic-gate 	return (0);
7090Sstevel@tonic-gate }
7100Sstevel@tonic-gate 
711*11740SJustin.Frank@Sun.COM void
fini_daemon(void)712*11740SJustin.Frank@Sun.COM fini_daemon(void)
713*11740SJustin.Frank@Sun.COM {
714*11740SJustin.Frank@Sun.COM 	EInterval_t *ip;
715*11740SJustin.Frank@Sun.COM 
716*11740SJustin.Frank@Sun.COM 	/* shut down the threads running the policies */
717*11740SJustin.Frank@Sun.COM 	for (ip = first_interval; ip != NULL; ip = ip->next) {
718*11740SJustin.Frank@Sun.COM 		if (ip->has_thread) {
719*11740SJustin.Frank@Sun.COM 			/*
720*11740SJustin.Frank@Sun.COM 			 * there is a thread for this interval; tell it to stop
721*11740SJustin.Frank@Sun.COM 			 * by clearing the interval
722*11740SJustin.Frank@Sun.COM 			 */
723*11740SJustin.Frank@Sun.COM 			ip->interval = 0;
724*11740SJustin.Frank@Sun.COM 		}
725*11740SJustin.Frank@Sun.COM 	}
726*11740SJustin.Frank@Sun.COM 	for (ip = first_interval; ip != NULL; ip = ip->next) {
727*11740SJustin.Frank@Sun.COM 		if (ip->has_thread) {
728*11740SJustin.Frank@Sun.COM 			(void) pthread_join(ip->thread, NULL);
729*11740SJustin.Frank@Sun.COM 		}
730*11740SJustin.Frank@Sun.COM 	}
731*11740SJustin.Frank@Sun.COM 	/* shut down the timer thread */
732*11740SJustin.Frank@Sun.COM 	while (timer_state != READY)
733*11740SJustin.Frank@Sun.COM 		(void) sched_yield();
734*11740SJustin.Frank@Sun.COM 	(void) pthread_mutex_lock(&timer_mutex);
735*11740SJustin.Frank@Sun.COM 	timer_state = TIMER_SHUTDOWN;
736*11740SJustin.Frank@Sun.COM 	(void) pthread_cond_signal(&timer_cond);
737*11740SJustin.Frank@Sun.COM 	(void) pthread_mutex_unlock(&timer_mutex);
738*11740SJustin.Frank@Sun.COM 	(void) pthread_join(timer_thread_id, NULL);
739*11740SJustin.Frank@Sun.COM 	(void) pthread_mutex_destroy(&env_lock_mutex);
740*11740SJustin.Frank@Sun.COM 	(void) pthread_mutex_destroy(&timer_mutex);
741*11740SJustin.Frank@Sun.COM 	(void) pthread_cond_destroy(&timer_cond);
742*11740SJustin.Frank@Sun.COM 	(void) sem_destroy(&timer_sem);
743*11740SJustin.Frank@Sun.COM }
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate void
init_daemon(void)7460Sstevel@tonic-gate init_daemon(void)
7470Sstevel@tonic-gate {
7480Sstevel@tonic-gate 	int32_t intervals = 0;
7490Sstevel@tonic-gate 	int32_t threads = 0;
7500Sstevel@tonic-gate 	int32_t status;
7510Sstevel@tonic-gate 	FILE *fp;
7520Sstevel@tonic-gate 	char filename[PATH_MAX];
7530Sstevel@tonic-gate 	char platform[64];
7540Sstevel@tonic-gate 	EInterval_t *ip, *prev;
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 	if (sysinfo(SI_PLATFORM, platform, sizeof (platform)) == -1) {
7570Sstevel@tonic-gate 		if (debug_flag)
758*11740SJustin.Frank@Sun.COM 			syslog(LOG_ERR, "%s", strerror(errno));
7590Sstevel@tonic-gate 		return;
7600Sstevel@tonic-gate 	}
7610Sstevel@tonic-gate 
762*11740SJustin.Frank@Sun.COM 	(void) snprintf(filename, sizeof (filename),
763*11740SJustin.Frank@Sun.COM 	    "/usr/platform/%s/lib/platsvcd.conf", platform);
7640Sstevel@tonic-gate 	if ((fp = fopen(filename, "r")) == NULL) {
7650Sstevel@tonic-gate 		if (debug_flag)
766*11740SJustin.Frank@Sun.COM 			syslog(LOG_ERR, "%s", strerror(errno));
7670Sstevel@tonic-gate 		return;
7680Sstevel@tonic-gate 	}
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	status = get_timeout(fp, &app_timeout);
7710Sstevel@tonic-gate 	if (status != 0) {
7720Sstevel@tonic-gate 		if (debug_flag)
773*11740SJustin.Frank@Sun.COM 			syslog(LOG_ERR, "%s", strerror(errno));
7740Sstevel@tonic-gate 		return;
7750Sstevel@tonic-gate 	}
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 	status = sem_init(&timer_sem, 0, 1);
7780Sstevel@tonic-gate 	if (status == -1) {
7790Sstevel@tonic-gate 		if (debug_flag)
780*11740SJustin.Frank@Sun.COM 			syslog(LOG_ERR, "%s", strerror(errno));
7810Sstevel@tonic-gate 		return;
7820Sstevel@tonic-gate 	}
7830Sstevel@tonic-gate 
784*11740SJustin.Frank@Sun.COM 	(void) strlcpy(env_lock_state, PSVC_LOCK_ENABLED, LOCK_STRING_MAX);
785*11740SJustin.Frank@Sun.COM 	(void) pthread_mutex_init(&env_lock_mutex, NULL);
786*11740SJustin.Frank@Sun.COM 	(void) pthread_mutex_init(&timer_mutex, NULL);
787*11740SJustin.Frank@Sun.COM 	(void) pthread_cond_init(&timer_cond, NULL);
788*11740SJustin.Frank@Sun.COM 
789*11740SJustin.Frank@Sun.COM 	timer_state = NOT_READY;
7900Sstevel@tonic-gate 	status = pthread_create(&timer_thread_id, NULL,
791*11740SJustin.Frank@Sun.COM 	    (void *(*)())timer_thread, 0);
7920Sstevel@tonic-gate 	if (status != 0) {
7930Sstevel@tonic-gate 		if (debug_flag)
794*11740SJustin.Frank@Sun.COM 			syslog(LOG_ERR, "%s", strerror(errno));
7950Sstevel@tonic-gate 		return;
7960Sstevel@tonic-gate 	}
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate 	/* get timer thread running */
7990Sstevel@tonic-gate 	while (timer_state != READY)
800*11740SJustin.Frank@Sun.COM 		(void) sched_yield();
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate 	for (;;) {
8030Sstevel@tonic-gate 		status = load_interval(fp, &ip);
8040Sstevel@tonic-gate 		if (status != 0)
8050Sstevel@tonic-gate 			break;
8060Sstevel@tonic-gate 
8070Sstevel@tonic-gate #ifdef	lint
8080Sstevel@tonic-gate 		prev = NULL;
8090Sstevel@tonic-gate #endif
8100Sstevel@tonic-gate 		if (first_interval == 0)
8110Sstevel@tonic-gate 			first_interval = ip;
8120Sstevel@tonic-gate 		else
8130Sstevel@tonic-gate 			prev->next = ip;
8140Sstevel@tonic-gate 		prev = ip;
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 		++intervals;
8170Sstevel@tonic-gate 		if (ip->interval == 0) {
8180Sstevel@tonic-gate 			run_policies(ip);
8190Sstevel@tonic-gate 		} else {
8200Sstevel@tonic-gate 			thread_setup(ip);
8210Sstevel@tonic-gate 			++threads;
8220Sstevel@tonic-gate 		}
8230Sstevel@tonic-gate 	}
8240Sstevel@tonic-gate 	if (intervals == 0) {
8250Sstevel@tonic-gate 		if (debug_flag)
8260Sstevel@tonic-gate 			syslog(LOG_ERR, "ERROR: No policies started");
8270Sstevel@tonic-gate 		return;
8280Sstevel@tonic-gate 	}
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 	if (status == -1) {
8310Sstevel@tonic-gate 		if (debug_flag)
832*11740SJustin.Frank@Sun.COM 			syslog(LOG_ERR, "%s", strerror(errno));
8330Sstevel@tonic-gate 		return;
8340Sstevel@tonic-gate 	}
8350Sstevel@tonic-gate }
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 
count_records(FILE * fp,char * end,uint32_t * countp)8380Sstevel@tonic-gate static int32_t count_records(FILE *fp, char *end, uint32_t *countp)
8390Sstevel@tonic-gate {
8400Sstevel@tonic-gate 	long first_record;
8410Sstevel@tonic-gate 	char *ret;
8420Sstevel@tonic-gate 	char buf[BUFSZ];
8430Sstevel@tonic-gate 	uint32_t count = 0;
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 	first_record = ftell(fp);
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 	while ((ret = fgets(buf, BUFSZ, fp)) != NULL) {
8480Sstevel@tonic-gate 		if (strncmp(end, buf, strlen(end)) == 0)
8490Sstevel@tonic-gate 			break;
8500Sstevel@tonic-gate 		++count;
8510Sstevel@tonic-gate 	}
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate 	if (ret == NULL) {
8540Sstevel@tonic-gate 		errno = EINVAL;
8550Sstevel@tonic-gate 		return (-1);
8560Sstevel@tonic-gate 	}
8570Sstevel@tonic-gate 
858*11740SJustin.Frank@Sun.COM 	(void) fseek(fp, first_record, SEEK_SET);
8590Sstevel@tonic-gate 	*countp = count;
8600Sstevel@tonic-gate 	return (0);
8610Sstevel@tonic-gate }
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate /*
8640Sstevel@tonic-gate  * Find start of a section within the config file,
8650Sstevel@tonic-gate  * Returns number of records in the section.
8660Sstevel@tonic-gate  * FILE *fd is set to first data record within section.
8670Sstevel@tonic-gate  */
8680Sstevel@tonic-gate static int32_t
find_file_section(FILE * fd,char * start)8690Sstevel@tonic-gate find_file_section(FILE *fd, char *start)
8700Sstevel@tonic-gate {
8710Sstevel@tonic-gate 	char *ret;
8720Sstevel@tonic-gate 	char buf[BUFSZ];
8730Sstevel@tonic-gate 	char name[32];
8740Sstevel@tonic-gate 	int found;
8750Sstevel@tonic-gate 
876*11740SJustin.Frank@Sun.COM 	(void) fseek(fd, 0, SEEK_SET);
8770Sstevel@tonic-gate 	while ((ret = fgets(buf, BUFSZ, fd)) != NULL) {
8780Sstevel@tonic-gate 		if (strncmp(start, buf, strlen(start)) == 0)
8790Sstevel@tonic-gate 			break;
8800Sstevel@tonic-gate 	}
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	if (ret == NULL) {
8830Sstevel@tonic-gate 		errno = EINVAL;
8840Sstevel@tonic-gate 		return (-1);
8850Sstevel@tonic-gate 	}
8860Sstevel@tonic-gate 
887*11740SJustin.Frank@Sun.COM 	found = sscanf(buf, "%31s", name);
8880Sstevel@tonic-gate 	if (found != 1) {
8890Sstevel@tonic-gate 		errno = EINVAL;
8900Sstevel@tonic-gate 		return (-1);
8910Sstevel@tonic-gate 	} else {
8920Sstevel@tonic-gate 		return (0);
8930Sstevel@tonic-gate 	}
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate }
8960Sstevel@tonic-gate 
name_compare_qsort(picl_psvc_t * s1,picl_psvc_t * s2)8970Sstevel@tonic-gate static int32_t name_compare_qsort(picl_psvc_t *s1, picl_psvc_t *s2)
8980Sstevel@tonic-gate {
8990Sstevel@tonic-gate 	return (strcmp(s1->name, s2->name));
9000Sstevel@tonic-gate }
9010Sstevel@tonic-gate 
name_compare_bsearch(char * s1,picl_psvc_t * s2)9020Sstevel@tonic-gate static int32_t name_compare_bsearch(char *s1, picl_psvc_t *s2)
9030Sstevel@tonic-gate {
9040Sstevel@tonic-gate 	return (strcmp(s1, s2->name));
9050Sstevel@tonic-gate }
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate /*
9080Sstevel@tonic-gate  * Create a property and add it to the specified node.
9090Sstevel@tonic-gate  * PICL will take a segmentation violation if a volatile property
9100Sstevel@tonic-gate  * has a non-zero size.
9110Sstevel@tonic-gate  */
node_property(picl_nodehdl_t node,int (* read)(ptree_rarg_t *,void *),int (* write)(ptree_warg_t *,const void *),picl_prop_type_t type,unsigned int size,unsigned int accessmode,char * name,void * value)9120Sstevel@tonic-gate static int32_t node_property(picl_nodehdl_t node,
9130Sstevel@tonic-gate 	int (*read)(ptree_rarg_t *, void *),
9140Sstevel@tonic-gate 	int (*write)(ptree_warg_t *, const void *), picl_prop_type_t type,
9150Sstevel@tonic-gate 	unsigned int size, unsigned int accessmode, char *name, void *value)
9160Sstevel@tonic-gate {
9170Sstevel@tonic-gate 	ptree_propinfo_t propinfo;
9180Sstevel@tonic-gate 	picl_prophdl_t prophdl;
9190Sstevel@tonic-gate 	int err;
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate 	propinfo.version = PSVC_PLUGIN_VERSION;
9220Sstevel@tonic-gate 	if (accessmode & PICL_VOLATILE) {
9230Sstevel@tonic-gate 		propinfo.read = read;
9240Sstevel@tonic-gate 		propinfo.write = write;
9250Sstevel@tonic-gate 	} else {
9260Sstevel@tonic-gate 		propinfo.read = NULL;
9270Sstevel@tonic-gate 		propinfo.write = NULL;
9280Sstevel@tonic-gate 	}
9290Sstevel@tonic-gate 	propinfo.piclinfo.type = type;
9300Sstevel@tonic-gate 	propinfo.piclinfo.accessmode = accessmode;
9310Sstevel@tonic-gate 	propinfo.piclinfo.size = size;
932*11740SJustin.Frank@Sun.COM 	(void) strcpy(propinfo.piclinfo.name, name);
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate 	err = ptree_create_prop(&propinfo, value, &prophdl);
9350Sstevel@tonic-gate 	if (err != 0) {
9360Sstevel@tonic-gate 		return (err);
9370Sstevel@tonic-gate 	}
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate 	err = ptree_add_prop(node, prophdl);
9400Sstevel@tonic-gate 	if (err != 0)
9410Sstevel@tonic-gate 		return (err);
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate 	return (0);
9440Sstevel@tonic-gate }
9450Sstevel@tonic-gate 
init_err(const char * fmt,char * arg1,char * arg2)946*11740SJustin.Frank@Sun.COM static void init_err(const char *fmt, char *arg1, char *arg2)
9470Sstevel@tonic-gate {
9480Sstevel@tonic-gate 	char msg[256];
9490Sstevel@tonic-gate 
950*11740SJustin.Frank@Sun.COM 	(void) snprintf(msg, sizeof (msg), fmt, arg1, arg2);
951*11740SJustin.Frank@Sun.COM 	syslog(LOG_ERR, "%s", msg);
9520Sstevel@tonic-gate }
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate static int
projected_lookup(picl_prophdl_t proph,struct proj_prop ** dstp)9550Sstevel@tonic-gate projected_lookup(picl_prophdl_t proph, struct proj_prop **dstp)
9560Sstevel@tonic-gate {
9570Sstevel@tonic-gate 	int i;
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 	for (i = 0; i < proj_prop_count; ++i) {
9600Sstevel@tonic-gate 		if (prop_list[i].handle == proph) {
9610Sstevel@tonic-gate 			*dstp = &prop_list[i];
9620Sstevel@tonic-gate 			return (PICL_SUCCESS);
9630Sstevel@tonic-gate 		}
9640Sstevel@tonic-gate 	}
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 	return (PICL_INVALIDHANDLE);
9670Sstevel@tonic-gate }
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate int
projected_read(ptree_rarg_t * rarg,void * buf)9700Sstevel@tonic-gate projected_read(ptree_rarg_t *rarg, void *buf)
9710Sstevel@tonic-gate {
9720Sstevel@tonic-gate 	ptree_propinfo_t propinfo;
9730Sstevel@tonic-gate 	struct proj_prop *dstinfo;
9740Sstevel@tonic-gate 	int err;
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate 	err = projected_lookup(rarg->proph, &dstinfo);
9770Sstevel@tonic-gate 	if (err != 0) {
9780Sstevel@tonic-gate 		return (PICL_FAILURE);
9790Sstevel@tonic-gate 	}
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate 	err = ptree_get_propinfo(rarg->proph, &propinfo);
9830Sstevel@tonic-gate 	if (err != 0)
9840Sstevel@tonic-gate 		return (err);
9850Sstevel@tonic-gate 	err = ptree_get_propval_by_name(dstinfo->dst_node,
986*11740SJustin.Frank@Sun.COM 	    dstinfo->name, buf, propinfo.piclinfo.size);
9870Sstevel@tonic-gate 	if (err != 0)
9880Sstevel@tonic-gate 		return (err);
9890Sstevel@tonic-gate 	return (PICL_SUCCESS);
9900Sstevel@tonic-gate }
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate int
projected_write(ptree_warg_t * warg,const void * buf)9930Sstevel@tonic-gate projected_write(ptree_warg_t *warg, const void *buf)
9940Sstevel@tonic-gate {
9950Sstevel@tonic-gate 	ptree_propinfo_t propinfo;
9960Sstevel@tonic-gate 	struct proj_prop *dstinfo;
9970Sstevel@tonic-gate 	int err;
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 	err = projected_lookup(warg->proph, &dstinfo);
10000Sstevel@tonic-gate 	if (err != 0) {
10010Sstevel@tonic-gate 		return (PICL_FAILURE);
10020Sstevel@tonic-gate 	}
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 	err = ptree_get_propinfo(warg->proph, &propinfo);
10050Sstevel@tonic-gate 	if (err != 0)
10060Sstevel@tonic-gate 		return (err);
10070Sstevel@tonic-gate 	err = ptree_update_propval_by_name(dstinfo->dst_node,
1008*11740SJustin.Frank@Sun.COM 	    dstinfo->name, buf, propinfo.piclinfo.size);
10090Sstevel@tonic-gate 	if (err != 0)
10100Sstevel@tonic-gate 		return (err);
10110Sstevel@tonic-gate 	return (PICL_SUCCESS);
10120Sstevel@tonic-gate }
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate int
psvc_read_volatile(ptree_rarg_t * rarg,void * buf)10150Sstevel@tonic-gate psvc_read_volatile(ptree_rarg_t *rarg, void *buf)
10160Sstevel@tonic-gate {
10170Sstevel@tonic-gate 	ptree_propinfo_t propinfo;
10180Sstevel@tonic-gate 	char name[32], class[32];
10190Sstevel@tonic-gate 	int err, i;
10200Sstevel@tonic-gate 	int32_t attr_num = -1;
10210Sstevel@tonic-gate 	int32_t use_attr_num = 0;
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 	err = ptree_get_propval_by_name(rarg->nodeh, "name", name,
1024*11740SJustin.Frank@Sun.COM 	    sizeof (name));
10250Sstevel@tonic-gate 	if (err != 0) {
10260Sstevel@tonic-gate 		return (err);
10270Sstevel@tonic-gate 	}
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate 	err = ptree_get_propval_by_name(rarg->nodeh, "_class", class,
1030*11740SJustin.Frank@Sun.COM 	    sizeof (class));
10310Sstevel@tonic-gate 	if (err != 0) {
10320Sstevel@tonic-gate 		return (err);
10330Sstevel@tonic-gate 	}
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 	err = ptree_get_propinfo(rarg->proph, &propinfo);
10360Sstevel@tonic-gate 	if (err != 0) {
10370Sstevel@tonic-gate 		return (err);
10380Sstevel@tonic-gate 	}
10390Sstevel@tonic-gate 
10400Sstevel@tonic-gate 	for (i = 0; i < PICL_PROP_TRANS_COUNT; i++) {
10410Sstevel@tonic-gate 		if ((strcmp(class, picl_prop_trans[i].picl_class) == 0) &&
10420Sstevel@tonic-gate 		    (strcmp(propinfo.piclinfo.name,
1043*11740SJustin.Frank@Sun.COM 		    picl_prop_trans[i].picl_prop) == 0)) {
10440Sstevel@tonic-gate 			attr_num = i;
10450Sstevel@tonic-gate 			break;
10460Sstevel@tonic-gate 		}
10470Sstevel@tonic-gate 	}
10480Sstevel@tonic-gate 
10490Sstevel@tonic-gate 	if (attr_num == -1)
10500Sstevel@tonic-gate 		for (i = 0; i < ATTR_STR_TAB_SIZE; i++) {
10510Sstevel@tonic-gate 			if (strcmp(propinfo.piclinfo.name,
1052*11740SJustin.Frank@Sun.COM 			    attr_str_tab[i]) == 0) {
10530Sstevel@tonic-gate 				attr_num = i;
10540Sstevel@tonic-gate 				use_attr_num = 1;
10550Sstevel@tonic-gate 				break;
10560Sstevel@tonic-gate 			}
10570Sstevel@tonic-gate 		}
10580Sstevel@tonic-gate 
10590Sstevel@tonic-gate 	if (use_attr_num)
10600Sstevel@tonic-gate 		err = psvc_get_attr(hdlp, name, attr_num, buf);
10610Sstevel@tonic-gate 	else
10620Sstevel@tonic-gate 		err = psvc_get_attr(hdlp, name,
10630Sstevel@tonic-gate 		    picl_prop_trans[attr_num].psvc_prop,
10640Sstevel@tonic-gate 		    buf);
10650Sstevel@tonic-gate 
10660Sstevel@tonic-gate 	if (err != 0) {
10670Sstevel@tonic-gate 		return (PICL_FAILURE);
10680Sstevel@tonic-gate 	}
10690Sstevel@tonic-gate 	return (PICL_SUCCESS);
10700Sstevel@tonic-gate }
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate int
psvc_write_volatile(ptree_warg_t * warg,const void * buf)10730Sstevel@tonic-gate psvc_write_volatile(ptree_warg_t *warg, const void *buf)
10740Sstevel@tonic-gate {
10750Sstevel@tonic-gate 	ptree_propinfo_t propinfo;
10760Sstevel@tonic-gate 	char name[32], class[32];
10770Sstevel@tonic-gate 	int err, i;
10780Sstevel@tonic-gate 	int32_t attr_num = -1;
10790Sstevel@tonic-gate 	int32_t use_attr_num = 0;
10800Sstevel@tonic-gate 
10810Sstevel@tonic-gate 	if (warg->cred.dc_euid != 0)
10820Sstevel@tonic-gate 		return (PICL_PERMDENIED);
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate 	err = ptree_get_propval_by_name(warg->nodeh, "name", name,
1085*11740SJustin.Frank@Sun.COM 	    sizeof (name));
10860Sstevel@tonic-gate 	if (err != 0) {
10870Sstevel@tonic-gate 		return (err);
10880Sstevel@tonic-gate 	}
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 	err = ptree_get_propval_by_name(warg->nodeh, "_class", class,
1091*11740SJustin.Frank@Sun.COM 	    sizeof (class));
10920Sstevel@tonic-gate 	if (err != 0) {
10930Sstevel@tonic-gate 		return (err);
10940Sstevel@tonic-gate 	}
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate 	err = ptree_get_propinfo(warg->proph, &propinfo);
10970Sstevel@tonic-gate 	if (err != 0) {
10980Sstevel@tonic-gate 		return (err);
10990Sstevel@tonic-gate 	}
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 	for (i = 0; i < PICL_PROP_TRANS_COUNT; i++) {
11020Sstevel@tonic-gate 		if ((strcmp(class, picl_prop_trans[i].picl_class) == 0) &&
11030Sstevel@tonic-gate 		    (strcmp(propinfo.piclinfo.name,
1104*11740SJustin.Frank@Sun.COM 		    picl_prop_trans[i].picl_prop) == 0)) {
11050Sstevel@tonic-gate 			attr_num = i;
11060Sstevel@tonic-gate 			break;
11070Sstevel@tonic-gate 		}
11080Sstevel@tonic-gate 	}
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate 	if (attr_num == -1)
11110Sstevel@tonic-gate 		for (i = 0; i < ATTR_STR_TAB_SIZE; i++) {
11120Sstevel@tonic-gate 			if (strcmp(propinfo.piclinfo.name,
1113*11740SJustin.Frank@Sun.COM 			    attr_str_tab[i]) == 0) {
11140Sstevel@tonic-gate 			attr_num = i;
11150Sstevel@tonic-gate 			use_attr_num = 1;
11160Sstevel@tonic-gate 			break;
11170Sstevel@tonic-gate 			}
11180Sstevel@tonic-gate 		}
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate 	if (use_attr_num)
11210Sstevel@tonic-gate 		err = psvc_set_attr(hdlp, name, attr_num, (void *)buf);
11220Sstevel@tonic-gate 	else
11230Sstevel@tonic-gate 		err = psvc_set_attr(hdlp, name,
11240Sstevel@tonic-gate 		    picl_prop_trans[attr_num].psvc_prop,
11250Sstevel@tonic-gate 		    (void *)buf);
11260Sstevel@tonic-gate 
11270Sstevel@tonic-gate 	if (err != 0) {
11280Sstevel@tonic-gate 		return (PICL_FAILURE);
11290Sstevel@tonic-gate 	}
11300Sstevel@tonic-gate 
11310Sstevel@tonic-gate 	return (PICL_SUCCESS);
11320Sstevel@tonic-gate }
11330Sstevel@tonic-gate 
create_reference_properties(struct assoc_pair * assoc_tbl,int32_t count,char * assoc_name)11340Sstevel@tonic-gate void create_reference_properties(struct assoc_pair *assoc_tbl, int32_t count,
11350Sstevel@tonic-gate 	char *assoc_name)
11360Sstevel@tonic-gate {
11370Sstevel@tonic-gate 	picl_psvc_t *aobjp, *dobjp;
11380Sstevel@tonic-gate 	picl_prophdl_t tbl_hdl;
11390Sstevel@tonic-gate 	picl_nodehdl_t *dep_list;
11400Sstevel@tonic-gate 	ptree_propinfo_t propinfo;
11410Sstevel@tonic-gate 	char *funcname = "create_reference_properties";
11420Sstevel@tonic-gate 	char name[PICL_PROPNAMELEN_MAX];
11430Sstevel@tonic-gate 	int32_t i, j, offset;
11440Sstevel@tonic-gate 	int32_t dependents;
11450Sstevel@tonic-gate 	int32_t err;
11460Sstevel@tonic-gate 	char class[PICL_CLASSNAMELEN_MAX];
11470Sstevel@tonic-gate 
11480Sstevel@tonic-gate 	for (i = 0; i < count; ++i) {
11490Sstevel@tonic-gate 		/* antecedent */
11500Sstevel@tonic-gate 		aobjp = (picl_psvc_t *)bsearch(assoc_tbl[i].antecedent,
1151*11740SJustin.Frank@Sun.COM 		    psvc_hdl.objects, psvc_hdl.obj_count,
1152*11740SJustin.Frank@Sun.COM 		    sizeof (picl_psvc_t),
1153*11740SJustin.Frank@Sun.COM 		    (int (*)(const void *, const void *))
1154*11740SJustin.Frank@Sun.COM 		    name_compare_bsearch);
11550Sstevel@tonic-gate 		if (aobjp == NULL) {
11560Sstevel@tonic-gate 			init_err(ID_NOT_FOUND_MSG,
1157*11740SJustin.Frank@Sun.COM 			    funcname, assoc_tbl[i].antecedent);
11580Sstevel@tonic-gate 			return;
11590Sstevel@tonic-gate 		}
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 		/* skip if table already created */
11620Sstevel@tonic-gate 		if (ptree_get_propval_by_name(aobjp->node, assoc_name,
1163*11740SJustin.Frank@Sun.COM 		    &tbl_hdl, sizeof (tbl_hdl)) == 0) {
11640Sstevel@tonic-gate 			continue;
11650Sstevel@tonic-gate 		}
11660Sstevel@tonic-gate 
11670Sstevel@tonic-gate 		/* create a new table */
11680Sstevel@tonic-gate 		err = ptree_create_table(&tbl_hdl);
11690Sstevel@tonic-gate 		if (err != 0) {
11700Sstevel@tonic-gate 			init_err(PTREE_CREATE_TABLE_FAILED_MSG,
1171*11740SJustin.Frank@Sun.COM 			    funcname, picl_strerror(err));
11720Sstevel@tonic-gate 			return;
11730Sstevel@tonic-gate 		}
11740Sstevel@tonic-gate 
11750Sstevel@tonic-gate 		err = node_property(aobjp->node, NULL, NULL,
1176*11740SJustin.Frank@Sun.COM 		    PICL_PTYPE_TABLE, sizeof (tbl_hdl), PICL_READ,
1177*11740SJustin.Frank@Sun.COM 		    assoc_name, &tbl_hdl);
11780Sstevel@tonic-gate 		if (err != 0) {
11790Sstevel@tonic-gate 			init_err(CREATE_PROP_FAILED_MSG, funcname,
1180*11740SJustin.Frank@Sun.COM 			    picl_strerror(err));
11810Sstevel@tonic-gate 			return;
11820Sstevel@tonic-gate 		}
11830Sstevel@tonic-gate 
11840Sstevel@tonic-gate 		/* determine number of elements in the table */
11850Sstevel@tonic-gate 		dependents = 0;
11860Sstevel@tonic-gate 		for (j = i; j < count; ++j) {
11870Sstevel@tonic-gate 			if (strcmp(aobjp->name, assoc_tbl[j].antecedent) == 0)
11880Sstevel@tonic-gate 				++dependents;
11890Sstevel@tonic-gate 		}
11900Sstevel@tonic-gate 
11910Sstevel@tonic-gate 		dep_list = (picl_nodehdl_t *)malloc(sizeof (picl_nodehdl_t) *
11920Sstevel@tonic-gate 		    dependents);
11930Sstevel@tonic-gate 		if (dep_list == NULL) {
11940Sstevel@tonic-gate 			init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
11950Sstevel@tonic-gate 			return;
11960Sstevel@tonic-gate 		}
11970Sstevel@tonic-gate 		/* build row of reference properties */
11980Sstevel@tonic-gate 		offset = 0;
11990Sstevel@tonic-gate 		for (j = i; j < count; ++j) {
12000Sstevel@tonic-gate 			if (strcmp(aobjp->name, assoc_tbl[j].antecedent) != 0)
12010Sstevel@tonic-gate 				continue;
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate 			dobjp = (picl_psvc_t *)bsearch(assoc_tbl[j].dependent,
1204*11740SJustin.Frank@Sun.COM 			    psvc_hdl.objects,
1205*11740SJustin.Frank@Sun.COM 			    psvc_hdl.obj_count, sizeof (picl_psvc_t),
1206*11740SJustin.Frank@Sun.COM 			    (int (*)(const void *, const void *))
1207*11740SJustin.Frank@Sun.COM 			    name_compare_bsearch);
12080Sstevel@tonic-gate 			if (dobjp == NULL) {
12090Sstevel@tonic-gate 				init_err(ID_NOT_FOUND_MSG,
1210*11740SJustin.Frank@Sun.COM 				    funcname, assoc_tbl[j].dependent);
12110Sstevel@tonic-gate 				return;
12120Sstevel@tonic-gate 			}
12130Sstevel@tonic-gate 
12140Sstevel@tonic-gate 			/*
12150Sstevel@tonic-gate 			 * Reference property name must be
12160Sstevel@tonic-gate 			 * _classname_propertyname
12170Sstevel@tonic-gate 			 */
12180Sstevel@tonic-gate 			err = ptree_get_propval_by_name(dobjp->node,
1219*11740SJustin.Frank@Sun.COM 			    "_class", class, sizeof (class));
12200Sstevel@tonic-gate 			if (err != 0) {
12210Sstevel@tonic-gate 				init_err(CLASS_NOT_FOUND_MSG, funcname,
1222*11740SJustin.Frank@Sun.COM 				    assoc_tbl[j].dependent);
12230Sstevel@tonic-gate 				return;
12240Sstevel@tonic-gate 			}
1225*11740SJustin.Frank@Sun.COM 			(void) snprintf(name, sizeof (name), "_%s_subclass",
1226*11740SJustin.Frank@Sun.COM 			    class);
12270Sstevel@tonic-gate 
12280Sstevel@tonic-gate 			propinfo.version = PSVC_PLUGIN_VERSION;
12290Sstevel@tonic-gate 			propinfo.read = NULL;
12300Sstevel@tonic-gate 			propinfo.write = NULL;
12310Sstevel@tonic-gate 			propinfo.piclinfo.type = PICL_PTYPE_REFERENCE;
12320Sstevel@tonic-gate 			propinfo.piclinfo.accessmode = PICL_READ;
12330Sstevel@tonic-gate 			propinfo.piclinfo.size = sizeof (picl_nodehdl_t);
1234*11740SJustin.Frank@Sun.COM 			(void) strcpy(propinfo.piclinfo.name, name);
12350Sstevel@tonic-gate 
12360Sstevel@tonic-gate 			err = ptree_create_prop(&propinfo, &dobjp->node,
1237*11740SJustin.Frank@Sun.COM 			    dep_list + offset);
12380Sstevel@tonic-gate 			if (err != 0) {
12390Sstevel@tonic-gate 				init_err(PTREE_CREATE_PROP_FAILED_MSG,
1240*11740SJustin.Frank@Sun.COM 				    name, picl_strerror(err));
12410Sstevel@tonic-gate 				return;
12420Sstevel@tonic-gate 			}
12430Sstevel@tonic-gate 
12440Sstevel@tonic-gate 			++offset;
12450Sstevel@tonic-gate 		}
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate 		/* add row to table */
12480Sstevel@tonic-gate 		err = ptree_add_row_to_table(tbl_hdl, dependents, dep_list);
12490Sstevel@tonic-gate 		if (err != 0) {
12500Sstevel@tonic-gate 			init_err(PTREE_ADD_ROW_FAILED_MSG, funcname,
1251*11740SJustin.Frank@Sun.COM 			    picl_strerror(err));
12520Sstevel@tonic-gate 			return;
12530Sstevel@tonic-gate 		}
12540Sstevel@tonic-gate 
12550Sstevel@tonic-gate 	}
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate 
12580Sstevel@tonic-gate }
12590Sstevel@tonic-gate 
12600Sstevel@tonic-gate /* Load projected properties */
12610Sstevel@tonic-gate static void
load_projected_properties(FILE * fp)12620Sstevel@tonic-gate load_projected_properties(FILE *fp)
12630Sstevel@tonic-gate {
12640Sstevel@tonic-gate 	int32_t found;
12650Sstevel@tonic-gate 	ptree_propinfo_t propinfo;
12660Sstevel@tonic-gate 	ptree_propinfo_t dstinfo;
12670Sstevel@tonic-gate 	picl_prophdl_t src_prophdl, dst_prophdl;
12680Sstevel@tonic-gate 	picl_nodehdl_t src_node, dst_node;
12690Sstevel@tonic-gate 	int err, i;
12700Sstevel@tonic-gate 	picl_psvc_t *srcobjp, *dstobjp;
12710Sstevel@tonic-gate 	char src[32], dst[256];
12720Sstevel@tonic-gate 	char src_prop[32], dst_prop[32];
12730Sstevel@tonic-gate 	char buf[BUFSZ];
12740Sstevel@tonic-gate 	char *funcname = "load_projected_properties";
12750Sstevel@tonic-gate 
12760Sstevel@tonic-gate 	if (find_file_section(fp, "PROJECTED_PROPERTIES") != 0)
12770Sstevel@tonic-gate 		return;
12780Sstevel@tonic-gate 
12790Sstevel@tonic-gate 	if (count_records(fp, "PROJECTED_PROPERTIES_END", &proj_prop_count) !=
1280*11740SJustin.Frank@Sun.COM 	    0) {
12810Sstevel@tonic-gate 		init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
12820Sstevel@tonic-gate 		return;
12830Sstevel@tonic-gate 	}
12840Sstevel@tonic-gate 
12850Sstevel@tonic-gate 	prop_list = (struct proj_prop *)malloc(sizeof (struct proj_prop)
1286*11740SJustin.Frank@Sun.COM 	    * proj_prop_count);
12870Sstevel@tonic-gate 	if (prop_list == NULL) {
12880Sstevel@tonic-gate 		init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
12890Sstevel@tonic-gate 		return;
12900Sstevel@tonic-gate 	}
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 	for (i = 0; i < proj_prop_count; ++i) {
1293*11740SJustin.Frank@Sun.COM 		buf[0] = '\0';
1294*11740SJustin.Frank@Sun.COM 		(void) fgets(buf, BUFSZ, fp);
1295*11740SJustin.Frank@Sun.COM 		found = sscanf(buf, "%31s %31s %255s %31s", src, src_prop, dst,
1296*11740SJustin.Frank@Sun.COM 		    dst_prop);
12970Sstevel@tonic-gate 		if (found != 4) {
12980Sstevel@tonic-gate 			init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
12990Sstevel@tonic-gate 			return;
13000Sstevel@tonic-gate 		}
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 		/* find src node */
13030Sstevel@tonic-gate 		if (src[0] == '/') {
13040Sstevel@tonic-gate 			/* picl node name, outside psvc subtree */
13050Sstevel@tonic-gate 			err = ptree_get_node_by_path(src, &src_node);
13060Sstevel@tonic-gate 			if (err != 0) {
13070Sstevel@tonic-gate 				init_err(NODE_NOT_FOUND_MSG, funcname, src);
13080Sstevel@tonic-gate 				return;
13090Sstevel@tonic-gate 			}
13100Sstevel@tonic-gate 		} else {
13110Sstevel@tonic-gate 			srcobjp = (picl_psvc_t *)bsearch(src, psvc_hdl.objects,
1312*11740SJustin.Frank@Sun.COM 			    psvc_hdl.obj_count, sizeof (picl_psvc_t),
1313*11740SJustin.Frank@Sun.COM 			    (int (*)(const void *, const void *))
1314*11740SJustin.Frank@Sun.COM 			    name_compare_bsearch);
13150Sstevel@tonic-gate 			if (srcobjp == NULL) {
13160Sstevel@tonic-gate 				init_err(ID_NOT_FOUND_MSG, funcname, src);
13170Sstevel@tonic-gate 				return;
13180Sstevel@tonic-gate 			}
13190Sstevel@tonic-gate 			src_node = srcobjp->node;
13200Sstevel@tonic-gate 		}
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate 		/* find dest node */
13230Sstevel@tonic-gate 		if (dst[0] == '/') {
13240Sstevel@tonic-gate 			/* picl node name, outside psvc subtree */
13250Sstevel@tonic-gate 			err = ptree_get_node_by_path(dst, &dst_node);
13260Sstevel@tonic-gate 			if (err != 0) {
13270Sstevel@tonic-gate 				init_err(NODE_NOT_FOUND_MSG, funcname, dst);
13280Sstevel@tonic-gate 				return;
13290Sstevel@tonic-gate 			}
13300Sstevel@tonic-gate 			prop_list[i].dst_node = dst_node;
13310Sstevel@tonic-gate 		} else {
13320Sstevel@tonic-gate 			dstobjp = (picl_psvc_t *)bsearch(dst, psvc_hdl.objects,
1333*11740SJustin.Frank@Sun.COM 			    psvc_hdl.obj_count, sizeof (picl_psvc_t),
1334*11740SJustin.Frank@Sun.COM 			    (int (*)(const void *, const void *))
1335*11740SJustin.Frank@Sun.COM 			    name_compare_bsearch);
13360Sstevel@tonic-gate 			if (dstobjp == NULL) {
13370Sstevel@tonic-gate 				init_err(ID_NOT_FOUND_MSG, funcname, dst);
13380Sstevel@tonic-gate 				return;
13390Sstevel@tonic-gate 			}
13400Sstevel@tonic-gate 			dst_node = dstobjp->node;
13410Sstevel@tonic-gate 			prop_list[i].dst_node = dst_node;
13420Sstevel@tonic-gate 		}
13430Sstevel@tonic-gate 
13440Sstevel@tonic-gate 		/* determine destination property size */
13450Sstevel@tonic-gate 		err = ptree_get_first_prop(dst_node, &dst_prophdl);
13460Sstevel@tonic-gate 		while (err == 0) {
13470Sstevel@tonic-gate 			err = ptree_get_propinfo(dst_prophdl, &dstinfo);
13480Sstevel@tonic-gate 			if (err != 0)
13490Sstevel@tonic-gate 				break;
13500Sstevel@tonic-gate 			if (strcmp(dst_prop, dstinfo.piclinfo.name) == 0)
13510Sstevel@tonic-gate 				break;
13520Sstevel@tonic-gate 			err = ptree_get_next_prop(dst_prophdl, &dst_prophdl);
13530Sstevel@tonic-gate 		}
13540Sstevel@tonic-gate 		if (err != 0) {
13550Sstevel@tonic-gate 			init_err(SIZE_NOT_FOUND_MSG, funcname, dst_prop);
13560Sstevel@tonic-gate 			return;
13570Sstevel@tonic-gate 		}
13580Sstevel@tonic-gate 
13590Sstevel@tonic-gate 		propinfo.version = PSVC_PLUGIN_VERSION;
13600Sstevel@tonic-gate 		propinfo.read = projected_read;
13610Sstevel@tonic-gate 		propinfo.write = projected_write;
13620Sstevel@tonic-gate 		propinfo.piclinfo.type = dstinfo.piclinfo.type;
13630Sstevel@tonic-gate 		propinfo.piclinfo.accessmode =
1364*11740SJustin.Frank@Sun.COM 		    PICL_READ | PICL_WRITE | PICL_VOLATILE;
13650Sstevel@tonic-gate 		propinfo.piclinfo.size = dstinfo.piclinfo.size;
1366*11740SJustin.Frank@Sun.COM 		(void) strcpy(propinfo.piclinfo.name, src_prop);
13670Sstevel@tonic-gate 
13680Sstevel@tonic-gate 		err = ptree_create_prop(&propinfo, 0, &src_prophdl);
13690Sstevel@tonic-gate 		if (err != 0) {
13700Sstevel@tonic-gate 			init_err(PTREE_CREATE_PROP_FAILED_MSG, funcname,
1371*11740SJustin.Frank@Sun.COM 			    picl_strerror(err));
13720Sstevel@tonic-gate 			return;
13730Sstevel@tonic-gate 		}
13740Sstevel@tonic-gate 
13750Sstevel@tonic-gate 		err = ptree_add_prop(src_node, src_prophdl);
13760Sstevel@tonic-gate 		if (err != 0) {
13770Sstevel@tonic-gate 			init_err(PTREE_ADD_PROP_FAILED_MSG, funcname,
1378*11740SJustin.Frank@Sun.COM 			    picl_strerror(err));
13790Sstevel@tonic-gate 			return;
13800Sstevel@tonic-gate 		}
13810Sstevel@tonic-gate 
13820Sstevel@tonic-gate 		prop_list[i].handle = src_prophdl;
1383*11740SJustin.Frank@Sun.COM 		(void) strcpy(prop_list[i].name, dst_prop);
13840Sstevel@tonic-gate 
13850Sstevel@tonic-gate 	}
13860Sstevel@tonic-gate }
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate /* Load the association table */
load_associations(FILE * fp)13890Sstevel@tonic-gate static void load_associations(FILE *fp)
13900Sstevel@tonic-gate {
13910Sstevel@tonic-gate 	char *funcname = "load_associations";
13920Sstevel@tonic-gate 	uint32_t count;
13930Sstevel@tonic-gate 	int found;
13940Sstevel@tonic-gate 	int j;
13950Sstevel@tonic-gate 	char assoc_name[32];
13960Sstevel@tonic-gate 	struct assoc_pair *assoc_tbl;
13970Sstevel@tonic-gate 	char name1[32];
13980Sstevel@tonic-gate 	char buf[BUFSZ];
13990Sstevel@tonic-gate 
14000Sstevel@tonic-gate 	/*
14010Sstevel@tonic-gate 	 * ignore count in the file, correct count is highest
14020Sstevel@tonic-gate 	 * association id + 1, now figured when loading ASSOC_STR
14030Sstevel@tonic-gate 	 * section.
14040Sstevel@tonic-gate 	 */
14050Sstevel@tonic-gate 	if (find_file_section(fp, "ASSOCIATIONS") != 0)
14060Sstevel@tonic-gate 		return;
14070Sstevel@tonic-gate 
1408*11740SJustin.Frank@Sun.COM 	buf[0] = '\0';
1409*11740SJustin.Frank@Sun.COM 	(void) fgets(buf, BUFSZ, fp);
14100Sstevel@tonic-gate 	while (strncmp("ASSOCIATIONS_END", buf, 16) != 0) {
1411*11740SJustin.Frank@Sun.COM 		found = sscanf(buf, "%31s %31s", name1, assoc_name);
14120Sstevel@tonic-gate 		if (found != 2) {
14130Sstevel@tonic-gate 			init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
14140Sstevel@tonic-gate 			return;
14150Sstevel@tonic-gate 		}
14160Sstevel@tonic-gate 
14170Sstevel@tonic-gate 		if (count_records(fp, "ASSOCIATION_END", &count) != 0) {
14180Sstevel@tonic-gate 			init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
14190Sstevel@tonic-gate 			return;
14200Sstevel@tonic-gate 		}
14210Sstevel@tonic-gate 
14220Sstevel@tonic-gate 		assoc_tbl = (struct assoc_pair *)malloc(
1423*11740SJustin.Frank@Sun.COM 		    sizeof (struct assoc_pair) * count);
14240Sstevel@tonic-gate 		if (assoc_tbl == NULL) {
14250Sstevel@tonic-gate 			init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
14260Sstevel@tonic-gate 			return;
14270Sstevel@tonic-gate 		}
14280Sstevel@tonic-gate 
14290Sstevel@tonic-gate 		for (j = 0; j < count; ++j) {
1430*11740SJustin.Frank@Sun.COM 			buf[0] = '\0';
1431*11740SJustin.Frank@Sun.COM 			(void) fgets(buf, BUFSZ, fp);
1432*11740SJustin.Frank@Sun.COM 			found = sscanf(buf, "%31s %31s",
1433*11740SJustin.Frank@Sun.COM 			    assoc_tbl[j].antecedent, assoc_tbl[j].dependent);
14340Sstevel@tonic-gate 			if (found != 2) {
14350Sstevel@tonic-gate 				init_err(INVALID_FILE_FORMAT_MSG, funcname,
1436*11740SJustin.Frank@Sun.COM 				    0);
14370Sstevel@tonic-gate 				return;
14380Sstevel@tonic-gate 			}
14390Sstevel@tonic-gate 
14400Sstevel@tonic-gate 		}
1441*11740SJustin.Frank@Sun.COM 		buf[0] = '\0';
1442*11740SJustin.Frank@Sun.COM 		(void) fgets(buf, BUFSZ, fp);
14430Sstevel@tonic-gate 		if (strncmp(buf, "ASSOCIATION_END", 15) != 0) {
14440Sstevel@tonic-gate 			init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
14450Sstevel@tonic-gate 			return;
14460Sstevel@tonic-gate 		}
14470Sstevel@tonic-gate 
14480Sstevel@tonic-gate 		/* Create separate list of dependents for each antecedent */
14490Sstevel@tonic-gate 		if (strcmp(assoc_name, "PSVC_TABLE") != 0) {
14500Sstevel@tonic-gate 			create_reference_properties(assoc_tbl, count,
1451*11740SJustin.Frank@Sun.COM 			    assoc_name);
14520Sstevel@tonic-gate 		}
14530Sstevel@tonic-gate 
14540Sstevel@tonic-gate 		free(assoc_tbl);
1455*11740SJustin.Frank@Sun.COM 		buf[0] = '\0';
1456*11740SJustin.Frank@Sun.COM 		(void) fgets(buf, BUFSZ, fp);
14570Sstevel@tonic-gate 	}
14580Sstevel@tonic-gate 
14590Sstevel@tonic-gate }
14600Sstevel@tonic-gate 
14610Sstevel@tonic-gate /* Enviornmental Lock Object's Read and Write routine */
1462*11740SJustin.Frank@Sun.COM /* ARGSUSED */
14630Sstevel@tonic-gate static int
env_lock_read(ptree_rarg_t * rarg,void * buf)14640Sstevel@tonic-gate env_lock_read(ptree_rarg_t *rarg, void *buf)
14650Sstevel@tonic-gate {
1466*11740SJustin.Frank@Sun.COM 	(void) strlcpy((char *)buf, env_lock_state, LOCK_STRING_MAX);
14670Sstevel@tonic-gate 	return (PSVC_SUCCESS);
14680Sstevel@tonic-gate }
14690Sstevel@tonic-gate 
1470*11740SJustin.Frank@Sun.COM /* ARGSUSED */
14710Sstevel@tonic-gate static int
env_lock_write(ptree_warg_t * warg,const void * buf)14720Sstevel@tonic-gate env_lock_write(ptree_warg_t *warg, const void *buf)
14730Sstevel@tonic-gate {
14740Sstevel@tonic-gate 	int32_t status = PSVC_SUCCESS;
14750Sstevel@tonic-gate 	char *var = (char *)buf;
14760Sstevel@tonic-gate 
14770Sstevel@tonic-gate 	/*
14780Sstevel@tonic-gate 	 * Check to make sure that the value is either Disabled or Enabled
14790Sstevel@tonic-gate 	 * as these are the only 2 states that this object can be set to.
14800Sstevel@tonic-gate 	 */
14810Sstevel@tonic-gate 	if ((strcmp(var, PSVC_LOCK_DISABLED) != 0) &&
14820Sstevel@tonic-gate 	    (strcmp(var, PSVC_LOCK_ENABLED) != 0)) {
14830Sstevel@tonic-gate 		errno = EINVAL;
14840Sstevel@tonic-gate 		return (PSVC_FAILURE);
14850Sstevel@tonic-gate 	}
14860Sstevel@tonic-gate 
1487*11740SJustin.Frank@Sun.COM 	(void) pthread_mutex_lock(&env_lock_mutex);
14880Sstevel@tonic-gate 
14890Sstevel@tonic-gate 	/*
14900Sstevel@tonic-gate 	 * If the state is already Enabled we can set the state to Disabled
14910Sstevel@tonic-gate 	 * to stop the policies.
14920Sstevel@tonic-gate 	 */
14930Sstevel@tonic-gate 	if (strcmp(env_lock_state, PSVC_LOCK_ENABLED) == 0) {
1494*11740SJustin.Frank@Sun.COM 		(void) pthread_mutex_unlock(&env_lock_mutex);
14950Sstevel@tonic-gate 		status = timed_lock_wait(PSVC_LOCK_DISABLED);
14960Sstevel@tonic-gate 		if (status == -1) {
14970Sstevel@tonic-gate 			syslog(LOG_ERR, SEM_WAIT_FAILED_MSG);
14980Sstevel@tonic-gate 		}
14990Sstevel@tonic-gate 		return (status);
15000Sstevel@tonic-gate 	}
15010Sstevel@tonic-gate 
15020Sstevel@tonic-gate 	/*
15030Sstevel@tonic-gate 	 * If the state is Running we must go into timed_lock_wait to aquire
15040Sstevel@tonic-gate 	 * the env_lock.
15050Sstevel@tonic-gate 	 */
15060Sstevel@tonic-gate 	if (strcmp(env_lock_state, PSVC_LOCK_RUNNING) == 0) {
1507*11740SJustin.Frank@Sun.COM 		(void) pthread_mutex_unlock(&env_lock_mutex);
15080Sstevel@tonic-gate 		status = timed_lock_wait(PSVC_LOCK_DISABLED);
15090Sstevel@tonic-gate 		if (status == -1) {
15100Sstevel@tonic-gate 			syslog(LOG_ERR, SEM_WAIT_FAILED_MSG);
15110Sstevel@tonic-gate 		}
15120Sstevel@tonic-gate 		return (status);
15130Sstevel@tonic-gate 	}
15140Sstevel@tonic-gate 
15150Sstevel@tonic-gate 	/*
15160Sstevel@tonic-gate 	 * If the state is already Disabled we need to first check to see if
15170Sstevel@tonic-gate 	 * we are resetting it to Disabled or changing it to Enabled. If we
15180Sstevel@tonic-gate 	 * are resetting it to Disabled then we need to stop the timer and
15190Sstevel@tonic-gate 	 * restart it. If we are changing it to Enabled we just set it to
15200Sstevel@tonic-gate 	 * enabled.
15210Sstevel@tonic-gate 	 */
15220Sstevel@tonic-gate 	if (strcmp(env_lock_state, PSVC_LOCK_DISABLED) == 0) {
15230Sstevel@tonic-gate 		if (strcmp(var, PSVC_LOCK_DISABLED) == 0) {
1524*11740SJustin.Frank@Sun.COM 			(void) pthread_mutex_lock(&timer_mutex);
15250Sstevel@tonic-gate 			if (timer_state == ACTIVE) {
15260Sstevel@tonic-gate 				timer_state = NOT_READY;
15270Sstevel@tonic-gate 				/* stop timer */
1528*11740SJustin.Frank@Sun.COM 				(void) pthread_cond_signal(&timer_cond);
1529*11740SJustin.Frank@Sun.COM 				(void) pthread_mutex_unlock(&timer_mutex);
15300Sstevel@tonic-gate 				/* wait for timer to reset */
15310Sstevel@tonic-gate 				while (timer_state != READY)
1532*11740SJustin.Frank@Sun.COM 					(void) sched_yield();
1533*11740SJustin.Frank@Sun.COM 				(void) pthread_mutex_lock(&timer_mutex);
15340Sstevel@tonic-gate 				timer_state = HAVE_REQUEST;
15350Sstevel@tonic-gate 				/* restart timer */
1536*11740SJustin.Frank@Sun.COM 				(void) pthread_cond_signal(&timer_cond);
15370Sstevel@tonic-gate 			}
1538*11740SJustin.Frank@Sun.COM 			(void) pthread_mutex_unlock(&timer_mutex);
15390Sstevel@tonic-gate 		} else {
1540*11740SJustin.Frank@Sun.COM 			(void) strlcpy(env_lock_state, var, LOCK_STRING_MAX);
15410Sstevel@tonic-gate 		}
15420Sstevel@tonic-gate 	}
1543*11740SJustin.Frank@Sun.COM 	(void) pthread_mutex_unlock(&env_lock_mutex);
15440Sstevel@tonic-gate 	return (PSVC_SUCCESS);
15450Sstevel@tonic-gate }
15460Sstevel@tonic-gate 
15470Sstevel@tonic-gate static int
init_env_lock_node(picl_nodehdl_t root_node)15480Sstevel@tonic-gate init_env_lock_node(picl_nodehdl_t root_node)
15490Sstevel@tonic-gate {
15500Sstevel@tonic-gate 	int err;
15510Sstevel@tonic-gate 	ptree_propinfo_t propinfo;
15520Sstevel@tonic-gate 	char *funcname = "init_env_lock_node";
15530Sstevel@tonic-gate 
15540Sstevel@tonic-gate 	/* Here we are creating a Enviornmental Lock Node */
15550Sstevel@tonic-gate 	err = ptree_create_node("/plugins/environmental", "picl", &lock_node);
15560Sstevel@tonic-gate 	if (err != PICL_SUCCESS) {
15570Sstevel@tonic-gate 		init_err(PTREE_CREATE_NODE_FAILED_MSG, funcname,
15580Sstevel@tonic-gate 		    picl_strerror(err));
15590Sstevel@tonic-gate 		return (err);
15600Sstevel@tonic-gate 	}
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION_1,
15630Sstevel@tonic-gate 	    PICL_PTYPE_CHARSTRING, PICL_READ | PICL_WRITE | PICL_VOLATILE,
1564*11740SJustin.Frank@Sun.COM 	    32, "State", env_lock_read, env_lock_write);
15650Sstevel@tonic-gate 	if (err != PICL_SUCCESS) {
15660Sstevel@tonic-gate 		init_err(NODE_PROP_FAILED_MSG, funcname, picl_strerror(err));
15670Sstevel@tonic-gate 		return (err);
15680Sstevel@tonic-gate 	}
15690Sstevel@tonic-gate 
15700Sstevel@tonic-gate 	err = ptree_create_and_add_prop(lock_node, &propinfo,
15710Sstevel@tonic-gate 	    NULL, NULL);
15720Sstevel@tonic-gate 	if (err != PICL_SUCCESS) {
15730Sstevel@tonic-gate 		init_err(PTREE_ADD_PROP_FAILED_MSG, funcname,
15740Sstevel@tonic-gate 		    picl_strerror(err));
15750Sstevel@tonic-gate 		return (err);
15760Sstevel@tonic-gate 	}
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate 	err = ptree_add_node(root_node, lock_node);
15790Sstevel@tonic-gate 	if (err != PICL_SUCCESS) {
15800Sstevel@tonic-gate 		init_err(PTREE_ADD_NODE_FAILED_MSG, funcname,
15810Sstevel@tonic-gate 		    picl_strerror(err));
15820Sstevel@tonic-gate 		return (err);
15830Sstevel@tonic-gate 	}
15840Sstevel@tonic-gate 
15850Sstevel@tonic-gate 	return (PSVC_SUCCESS);
15860Sstevel@tonic-gate }
15870Sstevel@tonic-gate 
15880Sstevel@tonic-gate void
psvc_plugin_init(void)15890Sstevel@tonic-gate psvc_plugin_init(void)
15900Sstevel@tonic-gate {
15910Sstevel@tonic-gate 	struct classinfo *cp;
15920Sstevel@tonic-gate 	picl_nodehdl_t root_node;
15930Sstevel@tonic-gate 	picl_nodehdl_t parent_node;
15940Sstevel@tonic-gate 	char *funcname = "psvc_plugin_init";
15950Sstevel@tonic-gate 	char platform[32];
15960Sstevel@tonic-gate 	char filename[256];
15970Sstevel@tonic-gate 	char buf[BUFSZ];
15980Sstevel@tonic-gate 	int32_t i, j;
15990Sstevel@tonic-gate 	int err, found;
16000Sstevel@tonic-gate 
16010Sstevel@tonic-gate 	psvc_paths = NULL;
16020Sstevel@tonic-gate 	psvc_hdl.obj_count = 0;
16030Sstevel@tonic-gate 	psvc_hdl.objects = NULL;
16040Sstevel@tonic-gate 	psvc_hdl.fp = NULL;
16050Sstevel@tonic-gate 	first_interval = NULL;
16060Sstevel@tonic-gate 
16070Sstevel@tonic-gate 	/*
16080Sstevel@tonic-gate 	 * So the volatile read/write routines can retrieve data from
16090Sstevel@tonic-gate 	 * psvc or picl
16100Sstevel@tonic-gate 	 */
16110Sstevel@tonic-gate 	err = psvc_init(&hdlp);
16120Sstevel@tonic-gate 	if (err != 0) {
16130Sstevel@tonic-gate 		init_err(PSVC_INIT_ERR_MSG, funcname, strerror(errno));
16140Sstevel@tonic-gate 	}
16150Sstevel@tonic-gate 
16160Sstevel@tonic-gate 	if (sysinfo(SI_PLATFORM, platform, sizeof (platform)) == -1) {
16170Sstevel@tonic-gate 		init_err(SYSINFO_FAILED_MSG, funcname, 0);
16180Sstevel@tonic-gate 		return;
16190Sstevel@tonic-gate 	}
16200Sstevel@tonic-gate 
1621*11740SJustin.Frank@Sun.COM 	(void) snprintf(filename, sizeof (filename),
1622*11740SJustin.Frank@Sun.COM 	    "/usr/platform/%s/lib/psvcobj.conf", platform);
16230Sstevel@tonic-gate 	if ((psvc_hdl.fp = fopen(filename, "r")) == NULL) {
16240Sstevel@tonic-gate 		init_err(FILE_OPEN_FAILED_MSG, funcname, filename);
16250Sstevel@tonic-gate 		return;
16260Sstevel@tonic-gate 	}
16270Sstevel@tonic-gate 
16280Sstevel@tonic-gate 	/* Create all PICL nodes */
16290Sstevel@tonic-gate 	if (find_file_section(psvc_hdl.fp, "OBJECT_INFO") == -1) {
16300Sstevel@tonic-gate 		init_err(INVALID_FILE_FORMAT1_MSG, funcname, filename);
16310Sstevel@tonic-gate 		return;
16320Sstevel@tonic-gate 	}
16330Sstevel@tonic-gate 	if (count_records(psvc_hdl.fp, "OBJECT_INFO_END", &psvc_hdl.obj_count)
16340Sstevel@tonic-gate 	    == -1) {
16350Sstevel@tonic-gate 		init_err(INVALID_FILE_FORMAT1_MSG, funcname, filename);
16360Sstevel@tonic-gate 		return;
16370Sstevel@tonic-gate 	}
16380Sstevel@tonic-gate 	if ((psvc_hdl.objects = (picl_psvc_t *)malloc(sizeof (picl_psvc_t) *
1639*11740SJustin.Frank@Sun.COM 	    psvc_hdl.obj_count)) == NULL) {
16400Sstevel@tonic-gate 		init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
16410Sstevel@tonic-gate 		return;
16420Sstevel@tonic-gate 	}
1643*11740SJustin.Frank@Sun.COM 	(void) memset(psvc_hdl.objects, 0,
1644*11740SJustin.Frank@Sun.COM 	    sizeof (picl_psvc_t) * psvc_hdl.obj_count);
16450Sstevel@tonic-gate 
16460Sstevel@tonic-gate 	err = ptree_get_root(&root_node);
16470Sstevel@tonic-gate 	if (err != 0) {
16480Sstevel@tonic-gate 		init_err(PTREE_GET_ROOT_FAILED_MSG, funcname,
1649*11740SJustin.Frank@Sun.COM 		    picl_strerror(err));
16500Sstevel@tonic-gate 		return;
16510Sstevel@tonic-gate 	}
16520Sstevel@tonic-gate 
16530Sstevel@tonic-gate 	/* Following array is  accessed directly by the psvc policies. */
16540Sstevel@tonic-gate 	psvc_paths = (psvc_name_t *)malloc(sizeof (psvc_name_t) *
1655*11740SJustin.Frank@Sun.COM 	    psvc_hdl.obj_count);
16560Sstevel@tonic-gate 	psvc_picl_nodes = psvc_hdl.obj_count;
16570Sstevel@tonic-gate 	if (psvc_paths == NULL) {
16580Sstevel@tonic-gate 		init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
16590Sstevel@tonic-gate 		return;
16600Sstevel@tonic-gate 	}
16610Sstevel@tonic-gate 	for (i = 0; i < psvc_hdl.obj_count; ++i) {
16620Sstevel@tonic-gate 		char *start;
16630Sstevel@tonic-gate 		int32_t class;
16640Sstevel@tonic-gate 		int32_t subclass;
16650Sstevel@tonic-gate 		int32_t	cp_count;
16660Sstevel@tonic-gate 		picl_psvc_t *objp = &psvc_hdl.objects[i];
1667*11740SJustin.Frank@Sun.COM 		buf[0] = '\0';
1668*11740SJustin.Frank@Sun.COM 		(void) fgets(buf, BUFSZ, psvc_hdl.fp);
16690Sstevel@tonic-gate 		if (strncmp(buf, "OBJECT_INFO_END", 15) == 0)
16700Sstevel@tonic-gate 			break;
16710Sstevel@tonic-gate 
16720Sstevel@tonic-gate 		start = strrchr(buf, '/');
16730Sstevel@tonic-gate 		if (start == NULL) {
16740Sstevel@tonic-gate 			init_err(INVALID_FILE_FORMAT1_MSG, funcname,
1675*11740SJustin.Frank@Sun.COM 			    filename);
16760Sstevel@tonic-gate 			return;
16770Sstevel@tonic-gate 		}
1678*11740SJustin.Frank@Sun.COM 		found = sscanf(start + 1, "%31s",  objp->name);
16790Sstevel@tonic-gate 		if (found != 1) {
16800Sstevel@tonic-gate 			init_err(INVALID_FILE_FORMAT1_MSG, funcname,
1681*11740SJustin.Frank@Sun.COM 			    filename);
16820Sstevel@tonic-gate 			return;
16830Sstevel@tonic-gate 		}
16840Sstevel@tonic-gate 
16850Sstevel@tonic-gate 		/* get class */
16860Sstevel@tonic-gate 		err = psvc_get_attr(hdlp, objp->name, PSVC_CLASS_ATTR, &class);
16870Sstevel@tonic-gate 		if (err != PSVC_SUCCESS) {
16880Sstevel@tonic-gate 			init_err(CLASS_NOT_FOUND_MSG, funcname, objp->name);
16890Sstevel@tonic-gate 			return;
16900Sstevel@tonic-gate 		}
16910Sstevel@tonic-gate 		if (class > NUM_CLASSES) {
16920Sstevel@tonic-gate 			init_err(UNKNOWN_CLASS_MSG, funcname, 0);
16930Sstevel@tonic-gate 			return;
16940Sstevel@tonic-gate 		}
16950Sstevel@tonic-gate 
16960Sstevel@tonic-gate 		err = psvc_get_attr(hdlp, objp->name, PSVC_SUBCLASS_ATTR,
1697*11740SJustin.Frank@Sun.COM 		    &subclass);
16980Sstevel@tonic-gate 		if (err != PSVC_SUCCESS) {
16990Sstevel@tonic-gate 			init_err(SUBCLASS_NOT_FOUND_MSG, funcname, objp->name);
17000Sstevel@tonic-gate 			return;
17010Sstevel@tonic-gate 		}
17020Sstevel@tonic-gate 
17030Sstevel@tonic-gate 		err = ptree_create_node(objp->name, class_name[class],
1704*11740SJustin.Frank@Sun.COM 		    &objp->node);
17050Sstevel@tonic-gate 		if (err != 0) {
17060Sstevel@tonic-gate 			init_err(PTREE_CREATE_NODE_FAILED_MSG, funcname,
1707*11740SJustin.Frank@Sun.COM 			    picl_strerror(err));
17080Sstevel@tonic-gate 			return;
17090Sstevel@tonic-gate 		}
17100Sstevel@tonic-gate 		if (strcmp(objp->name, PSVC_CHASSIS) == 0)
17110Sstevel@tonic-gate 			system_node = objp->node;
17120Sstevel@tonic-gate 
17130Sstevel@tonic-gate 		for (j = 0; j < COMMON_COUNT; ++j) {
17140Sstevel@tonic-gate 
17150Sstevel@tonic-gate 			err = node_property(objp->node,
17160Sstevel@tonic-gate 			    common[j].access & PICL_READ ?
17170Sstevel@tonic-gate 			    psvc_read_volatile : 0,
17180Sstevel@tonic-gate 			    common[j].access & PICL_WRITE ?
17190Sstevel@tonic-gate 			    psvc_write_volatile : 0,
17200Sstevel@tonic-gate 			    common[j].type, common[j].size,
17210Sstevel@tonic-gate 			    common[j].access, common[j].name, 0);
17220Sstevel@tonic-gate 			if (err != PSVC_SUCCESS) {
17230Sstevel@tonic-gate 				init_err(NODE_PROP_FAILED_MSG, funcname,
1724*11740SJustin.Frank@Sun.COM 				    picl_strerror(err));
17250Sstevel@tonic-gate 				return;
17260Sstevel@tonic-gate 			}
17270Sstevel@tonic-gate 		}
17280Sstevel@tonic-gate 		cp = &class_properties[class];
17290Sstevel@tonic-gate 		/* Locator LED Support */
17300Sstevel@tonic-gate 		if (class == 2 && subclass == 2) {
17310Sstevel@tonic-gate 			cp_count = 3;
17320Sstevel@tonic-gate 		} else {
17330Sstevel@tonic-gate 			cp_count = cp->count;
17340Sstevel@tonic-gate 		}
17350Sstevel@tonic-gate 
17360Sstevel@tonic-gate 		for (j = 0; j < cp_count; ++j) {
17370Sstevel@tonic-gate 			err = node_property(objp->node, psvc_read_volatile,
1738*11740SJustin.Frank@Sun.COM 			    psvc_write_volatile, cp->props[j].type,
1739*11740SJustin.Frank@Sun.COM 			    cp->props[j].size,
1740*11740SJustin.Frank@Sun.COM 			    cp->props[j].access, cp->props[j].name, 0);
17410Sstevel@tonic-gate 			if (err != PSVC_SUCCESS) {
17420Sstevel@tonic-gate 				init_err(NODE_PROP_FAILED_MSG, funcname,
1743*11740SJustin.Frank@Sun.COM 				    picl_strerror(err));
17440Sstevel@tonic-gate 				return;
17450Sstevel@tonic-gate 			}
17460Sstevel@tonic-gate 		}
17470Sstevel@tonic-gate 
17480Sstevel@tonic-gate 		/* Link the nodes into the PICL tree */
17490Sstevel@tonic-gate 		*start = 0;
17500Sstevel@tonic-gate 		if (start == buf) {	/* no parent */
17510Sstevel@tonic-gate 			parent_node = root_node;
17520Sstevel@tonic-gate 		} else {
17530Sstevel@tonic-gate 			err = ptree_get_node_by_path(buf, &parent_node);
17540Sstevel@tonic-gate 			if (err != PICL_SUCCESS) {
17550Sstevel@tonic-gate 				init_err(NODE_NOT_FOUND_MSG, funcname, buf);
17560Sstevel@tonic-gate 				return;
17570Sstevel@tonic-gate 			}
17580Sstevel@tonic-gate 		}
17590Sstevel@tonic-gate 
17600Sstevel@tonic-gate 		err = ptree_add_node(parent_node, objp->node);
17610Sstevel@tonic-gate 		if (err != PICL_SUCCESS) {
17620Sstevel@tonic-gate 			init_err(PTREE_ADD_NODE_FAILED_MSG, funcname,
1763*11740SJustin.Frank@Sun.COM 			    picl_strerror(err));
17640Sstevel@tonic-gate 			return;
17650Sstevel@tonic-gate 		}
1766*11740SJustin.Frank@Sun.COM 		(void) strcpy(psvc_paths[i].parent_path, buf);
1767*11740SJustin.Frank@Sun.COM 		(void) strcpy(psvc_paths[i].child_name, objp->name);
17680Sstevel@tonic-gate 		psvc_paths[i].child_node = objp->node;
17690Sstevel@tonic-gate 	}
17700Sstevel@tonic-gate 
17710Sstevel@tonic-gate 	qsort(psvc_hdl.objects, psvc_hdl.obj_count, sizeof (picl_psvc_t),
1772*11740SJustin.Frank@Sun.COM 	    (int (*)(const void *, const void *))name_compare_qsort);
17730Sstevel@tonic-gate 
17740Sstevel@tonic-gate 	load_associations(psvc_hdl.fp);
17750Sstevel@tonic-gate 	load_projected_properties(psvc_hdl.fp);
17760Sstevel@tonic-gate 
17770Sstevel@tonic-gate 	if (init_env_lock_node(root_node) != PSVC_SUCCESS)
17780Sstevel@tonic-gate 		return;
17790Sstevel@tonic-gate 
17800Sstevel@tonic-gate 	init_daemon();
17810Sstevel@tonic-gate }
17820Sstevel@tonic-gate 
17830Sstevel@tonic-gate void
psvc_plugin_fini(void)17840Sstevel@tonic-gate psvc_plugin_fini(void)
17850Sstevel@tonic-gate {
17860Sstevel@tonic-gate 	int32_t i;
17870Sstevel@tonic-gate 	EInterval_t *ip, *next;
17880Sstevel@tonic-gate 
1789*11740SJustin.Frank@Sun.COM 	fini_daemon();
17900Sstevel@tonic-gate 	for (ip = first_interval; ip != 0; ip = next) {
1791*11740SJustin.Frank@Sun.COM 		for (i = 0; i < ip->num_tasks; ++i) {
1792*11740SJustin.Frank@Sun.COM 			(void) dlclose(ip->task_list[i].hdl);
17930Sstevel@tonic-gate 			free(ip->task_list[i].obj_list);
1794*11740SJustin.Frank@Sun.COM 		}
17950Sstevel@tonic-gate 		free(ip->task_list);
17960Sstevel@tonic-gate 		next = ip->next;
17970Sstevel@tonic-gate 		free(ip);
17980Sstevel@tonic-gate 	}
1799*11740SJustin.Frank@Sun.COM 	free(prop_list);
1800*11740SJustin.Frank@Sun.COM 	free(psvc_paths);
1801*11740SJustin.Frank@Sun.COM 	free(psvc_hdl.objects);
1802*11740SJustin.Frank@Sun.COM 	if (psvc_hdl.fp != NULL)
1803*11740SJustin.Frank@Sun.COM 		(void) fclose(psvc_hdl.fp);
18040Sstevel@tonic-gate 	psvc_fini(hdlp);
18050Sstevel@tonic-gate }
18060Sstevel@tonic-gate 
18070Sstevel@tonic-gate void
psvc_plugin_register(void)18080Sstevel@tonic-gate psvc_plugin_register(void)
18090Sstevel@tonic-gate {
18100Sstevel@tonic-gate 	picld_plugin_register(&psvc_reg);
18110Sstevel@tonic-gate }
1812