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.
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.
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]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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,<>.
45 #include <semaphore.h>
50 #include <sys/types.h>
51 #include <sys/systeminfo.h>
52 #include <psvc_objects.h>
53 #include <psvc_objects_class.h>
63 int32_t (*funcp
)(void *, char *);
69 typedef struct interval_info
{
70 volatile int32_t interval
;
75 struct interval_info
*next
;
78 static EInterval_t
*first_interval
;
80 static psvc_opaque_t hdlp
;
83 pthread_mutex_t timer_mutex
;
84 pthread_cond_t timer_cond
;
85 pthread_t timer_thread_id
;
87 extern int ptree_get_node_by_path(const char *, picl_nodehdl_t
*);
92 #define HAVE_REQUEST 2
94 #define TIMER_SHUTDOWN 4
96 int timer_state
= NOT_READY
;
100 /* Lock State Loop State Definitions */
101 #define STATE_CHANGED 1
102 #define STATE_NOT_CHANGED 0
105 static int32_t debug_flag
= 1;
107 static int32_t debug_flag
= 0;
110 static char library
[PATH_MAX
];
112 #define PSVC_PLUGIN_VERSION PICLD_PLUGIN_VERSION_1
114 #pragma init(psvc_plugin_register) /* place in .init section */
117 char parent_path
[256];
119 picl_nodehdl_t child_node
;
121 psvc_name_t
*psvc_paths
;
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")
154 #define LOCK_STRING_MAX 32
156 picl_nodehdl_t system_node
;
157 static picl_nodehdl_t lock_node
;
158 static char env_lock_state
[LOCK_STRING_MAX
] = PSVC_LOCK_ENABLED
;
159 static pthread_mutex_t env_lock_mutex
;
161 static char *class_name
[] = {
162 "temperature-sensor",
175 #define NUM_CLASSES (sizeof (class_name) / sizeof (char *))
177 struct proj_prop
{ /* projected property */
178 picl_prophdl_t handle
;
179 picl_nodehdl_t dst_node
;
190 struct propinfo common
[] = {
191 {"State", PICL_PTYPE_CHARSTRING
, 32,
192 PICL_READ
| PICL_WRITE
| PICL_VOLATILE
},
193 {"FaultInformation", PICL_PTYPE_CHARSTRING
, 32,
194 PICL_READ
| PICL_VOLATILE
}
196 #define COMMON_COUNT (sizeof (common) / sizeof (struct propinfo))
198 struct propinfo led_properties
[] = {
199 {"Color", PICL_PTYPE_CHARSTRING
, 32, PICL_READ
| PICL_VOLATILE
},
200 {"IsLocator", PICL_PTYPE_CHARSTRING
, 32, PICL_READ
| PICL_VOLATILE
},
201 {"LocatorName", PICL_PTYPE_CHARSTRING
, 32, PICL_READ
| PICL_VOLATILE
}
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.
210 struct propinfo temperature_sensor_properties
[] = {
211 {"Temperature", PICL_PTYPE_INT
, 4, PICL_READ
| PICL_VOLATILE
},
212 {"LowWarningThreshold", PICL_PTYPE_INT
, 4, PICL_READ
| PICL_VOLATILE
},
213 {"LowShutdownThreshold", PICL_PTYPE_INT
, 4, PICL_READ
| PICL_VOLATILE
},
214 {"HighWarningThreshold", PICL_PTYPE_INT
, 4, PICL_READ
| PICL_VOLATILE
},
215 {"HighShutdownThreshold", PICL_PTYPE_INT
, 4, PICL_READ
| PICL_VOLATILE
}
217 #define TEMP_SENSOR_COUNT \
218 (sizeof (temperature_sensor_properties) / sizeof (struct propinfo))
220 struct propinfo digi_sensor_properties
[] = {
221 {"AtoDSensorValue", PICL_PTYPE_INT
, 4, PICL_READ
| PICL_VOLATILE
},
222 {"LowWarningThreshold", PICL_PTYPE_INT
, 4, PICL_READ
| PICL_VOLATILE
},
223 {"LowShutdownThreshold", PICL_PTYPE_INT
, 4, PICL_READ
| PICL_VOLATILE
},
224 {"HighWarningThreshold", PICL_PTYPE_INT
, 4, PICL_READ
| PICL_VOLATILE
},
225 {"HighShutdownThreshold", PICL_PTYPE_INT
, 4, PICL_READ
| PICL_VOLATILE
}
227 #define DIGI_SENSOR_COUNT \
228 (sizeof (digi_sensor_properties) / sizeof (struct propinfo))
230 struct propinfo boolgpio_properties
[] = {
231 {"Gpio-value", PICL_PTYPE_UNSIGNED_INT
, sizeof (boolean_t
),
232 PICL_READ
| PICL_WRITE
| PICL_VOLATILE
},
233 {"#Bits", PICL_PTYPE_UNSIGNED_INT
, 4, PICL_READ
|PICL_VOLATILE
}
235 #define BOOLGPIO_COUNT (sizeof (boolgpio_properties) / sizeof (struct propinfo))
237 struct propinfo gpio8_properties
[] = {
238 {"Gpio-value", PICL_PTYPE_UNSIGNED_INT
, 1,
239 PICL_READ
| PICL_WRITE
| PICL_VOLATILE
},
240 {"#Bits", PICL_PTYPE_UNSIGNED_INT
, 4, PICL_READ
|PICL_VOLATILE
}
242 #define GPIO8_COUNT (sizeof (gpio8_properties) / sizeof (struct propinfo))
244 struct propinfo digictrl_properties
[] = {
245 {"DtoAControlValue", PICL_PTYPE_INT
, 4,
246 PICL_READ
| PICL_WRITE
| PICL_VOLATILE
},
248 #define DIGICTRL_COUNT (sizeof (digictrl_properties) / sizeof (struct propinfo))
251 struct propinfo
*props
;
253 } class_properties
[] =
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 */
265 {gpio8_properties
, GPIO8_COUNT
},
273 } picl_prop_trans
[] =
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
}
298 #define PICL_PROP_TRANS_COUNT \
299 (sizeof (picl_prop_trans) / sizeof (struct prop_trans))
314 picl_psvc_t
*objects
;
318 struct proj_prop
*prop_list
;
319 uint32_t proj_prop_count
;
323 void psvc_plugin_init(void);
324 void psvc_plugin_fini(void);
326 picld_plugin_reg_t psvc_reg
= {
328 PICLD_PLUGIN_CRITICAL
,
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.
342 psvcplugin_add_children(char *parent_path
)
345 picl_nodehdl_t parent_node
;
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
);
360 psvcplugin_lookup(char *name
, char *parent
, picl_nodehdl_t
*node
)
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
;
375 struct timespec timeout
;
379 status
= pthread_mutex_lock(&timer_mutex
);
381 syslog(LOG_ERR
, MUTEX_LOCK_FAILED_MSG
, strerror(status
));
385 /* wait for thread to tell us to start timer */
388 status
= pthread_cond_wait(&timer_cond
, &timer_mutex
);
389 } while (timer_state
== READY
&& status
== 0);
391 if (timer_state
== TIMER_SHUTDOWN
) {
397 syslog(LOG_ERR
, CV_WAIT_FAILED_MSG
, strerror(status
));
401 * Will get signalled after semaphore acquired,
402 * or when timeout occurs.
404 (void) clock_gettime(CLOCK_REALTIME
, &timeout
);
405 timeout
.tv_sec
+= app_timeout
;
407 if (timer_state
== HAVE_REQUEST
) {
408 timer_state
= ACTIVE
;
410 status
= pthread_cond_timedwait(&timer_cond
,
411 &timer_mutex
, &timeout
);
412 } while (timer_state
== ACTIVE
&& 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
);
423 syslog(LOG_ERR
, CV_TWAIT_FAILED_MSG
,
431 lock_state_loop(char *set_lock_state
)
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
);
439 (void) pthread_mutex_unlock(&env_lock_mutex
);
440 return (STATE_CHANGED
);
443 static int timed_lock_wait(char *set_lock_state
)
447 /* Only want one timer active at a time */
449 status
= sem_wait(&timer_sem
);
450 } while (status
== -1 && errno
== EINTR
);
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
);
462 * We now spin checking the state env_lock_state for it to change to
465 while (lock_state_loop(set_lock_state
))
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 */
473 if (timer_state
== HAVE_REQUEST
) { /* cancel request */
474 timer_state
= NOT_READY
;
476 (void) pthread_mutex_unlock(&timer_mutex
);
477 (void) sem_post(&timer_sem
);
481 static void lock_and_run(ETask_t
*tp
, int32_t obj_num
)
485 /* Grab mutex to stop the env_lock from being changed. */
486 (void) pthread_mutex_lock(&env_lock_mutex
);
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.
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
);
497 syslog(LOG_ERR
, SEM_WAIT_FAILED_MSG
);
500 (void) strlcpy(env_lock_state
, PSVC_LOCK_RUNNING
,
502 (void) pthread_mutex_unlock(&env_lock_mutex
);
504 status
= (*tp
->funcp
)(hdlp
, (tp
->obj_list
+ obj_num
)->name
);
505 if (status
== PSVC_FAILURE
&& errno
!= ENODEV
) {
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
));
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
);
521 static void run_policies(EInterval_t
*ip
)
528 int remaining
= ip
->interval
;
530 /* check to see if we've been told to exit */
531 if (ip
->has_thread
&& (ip
->interval
== 0))
533 remaining
= sleep(remaining
);
534 } while (remaining
> 0);
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))
544 if (ip
->has_thread
&& (ip
->interval
== 0))
547 } while (ip
->interval
);
550 static void thread_setup(EInterval_t
*ip
)
554 status
= pthread_create(&ip
->thread
, NULL
, (void *(*)())run_policies
,
558 syslog(LOG_ERR
, "%s", strerror(errno
));
564 static int32_t load_policy(const char *library
, ETask_t
*tp
)
566 tp
->hdl
= dlopen(library
, RTLD_NOW
| RTLD_GLOBAL
);
567 if (tp
->hdl
== NULL
) {
569 char *errstr
= dlerror();
570 syslog(LOG_ERR
, "%s", errstr
);
574 tp
->funcp
= (int32_t (*)(void *, char *))dlsym(tp
->hdl
, tp
->routine
);
575 if (tp
->funcp
== NULL
) {
577 char *errstr
= dlerror();
578 syslog(LOG_ERR
, "%s", errstr
);
585 static int32_t get_timeout(FILE *fp
, int *timeout
)
591 /* skip blank lines */
593 cp
= fgets(buf
, BUFSZ
, fp
);
598 (void) sscanf(buf
, "%31s %d", name
, timeout
);
599 } while (*cp
== 0 || *cp
== '\n' || strcmp(name
, "TIMEOUT") != 0);
601 if (strcmp(name
, "TIMEOUT") != 0) {
609 static int32_t load_interval(FILE *fp
, EInterval_t
**ipp
)
616 int32_t status
, i
, j
;
621 /* skip blank lines */
623 cp
= fgets(buf
, BUFSZ
, fp
);
628 } while (*cp
== 0 || *cp
== '\n');
629 found
= sscanf(buf
, "%31s %d %d", name
, &interval
, &tasks
);
635 if (strcmp(name
, "INTERVAL") != 0) {
640 ip
= (EInterval_t
*)malloc(sizeof (EInterval_t
));
643 ip
->num_tasks
= tasks
;
644 ip
->interval
= interval
;
648 /* allocate and load table */
649 ip
->task_list
= (ETask_t
*)malloc(ip
->num_tasks
* sizeof (ETask_t
));
650 if (ip
->task_list
== NULL
)
652 for (i
= 0; i
< ip
->num_tasks
; ++i
) {
653 tp
= &ip
->task_list
[i
];
655 (void) fgets(buf
, BUFSZ
, fp
);
656 found
= sscanf(buf
, "%31s %1023s %63s",
657 name
, library
, tp
->routine
);
663 status
= load_policy(library
, tp
);
666 found
= fscanf(fp
, "%d", &tp
->num_objects
);
669 syslog(LOG_ERR
, "No list of objects for task");
674 (EName_t
*)malloc(tp
->num_objects
* sizeof (EName_t
));
675 if (tp
->obj_list
== NULL
)
678 for (j
= 0; j
< tp
->num_objects
; ++j
) {
679 found
= fscanf(fp
, "%31s", (char *)(tp
->obj_list
+ j
));
683 "Wrong number of objects for task");
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) {
692 syslog(LOG_ERR
, "Expected TASK_END, task %s",
699 (void) fgets(buf
, BUFSZ
, fp
);
700 if (strncmp(buf
, "INTERVAL_END", 12) != 0) {
702 syslog(LOG_ERR
, "Expected INTERVAL_END");
716 /* shut down the threads running the policies */
717 for (ip
= first_interval
; ip
!= NULL
; ip
= ip
->next
) {
718 if (ip
->has_thread
) {
720 * there is a thread for this interval; tell it to stop
721 * by clearing the interval
726 for (ip
= first_interval
; ip
!= NULL
; ip
= ip
->next
) {
727 if (ip
->has_thread
) {
728 (void) pthread_join(ip
->thread
, NULL
);
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
);
748 int32_t intervals
= 0;
752 char filename
[PATH_MAX
];
754 EInterval_t
*ip
, *prev
;
756 if (sysinfo(SI_PLATFORM
, platform
, sizeof (platform
)) == -1) {
758 syslog(LOG_ERR
, "%s", strerror(errno
));
762 (void) snprintf(filename
, sizeof (filename
),
763 "/usr/platform/%s/lib/platsvcd.conf", platform
);
764 if ((fp
= fopen(filename
, "r")) == NULL
) {
766 syslog(LOG_ERR
, "%s", strerror(errno
));
770 status
= get_timeout(fp
, &app_timeout
);
773 syslog(LOG_ERR
, "%s", strerror(errno
));
777 status
= sem_init(&timer_sem
, 0, 1);
780 syslog(LOG_ERR
, "%s", strerror(errno
));
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
);
789 timer_state
= NOT_READY
;
790 status
= pthread_create(&timer_thread_id
, NULL
,
791 (void *(*)())timer_thread
, 0);
794 syslog(LOG_ERR
, "%s", strerror(errno
));
798 /* get timer thread running */
799 while (timer_state
!= READY
)
800 (void) sched_yield();
803 status
= load_interval(fp
, &ip
);
807 if (first_interval
== 0)
814 if (ip
->interval
== 0) {
821 if (intervals
== 0) {
823 syslog(LOG_ERR
, "ERROR: No policies started");
829 syslog(LOG_ERR
, "%s", strerror(errno
));
835 static int32_t count_records(FILE *fp
, char *end
, uint32_t *countp
)
842 first_record
= ftell(fp
);
844 while ((ret
= fgets(buf
, BUFSZ
, fp
)) != NULL
) {
845 if (strncmp(end
, buf
, strlen(end
)) == 0)
855 (void) fseek(fp
, first_record
, SEEK_SET
);
861 * Find start of a section within the config file,
862 * Returns number of records in the section.
863 * FILE *fd is set to first data record within section.
866 find_file_section(FILE *fd
, char *start
)
873 (void) fseek(fd
, 0, SEEK_SET
);
874 while ((ret
= fgets(buf
, BUFSZ
, fd
)) != NULL
) {
875 if (strncmp(start
, buf
, strlen(start
)) == 0)
884 found
= sscanf(buf
, "%31s", name
);
894 static int32_t name_compare_qsort(picl_psvc_t
*s1
, picl_psvc_t
*s2
)
896 return (strcmp(s1
->name
, s2
->name
));
899 static int32_t name_compare_bsearch(char *s1
, picl_psvc_t
*s2
)
901 return (strcmp(s1
, s2
->name
));
905 * Create a property and add it to the specified node.
906 * PICL will take a segmentation violation if a volatile property
907 * has a non-zero size.
909 static int32_t node_property(picl_nodehdl_t node
,
910 int (*read
)(ptree_rarg_t
*, void *),
911 int (*write
)(ptree_warg_t
*, const void *), picl_prop_type_t type
,
912 unsigned int size
, unsigned int accessmode
, char *name
, void *value
)
914 ptree_propinfo_t propinfo
;
915 picl_prophdl_t prophdl
;
918 propinfo
.version
= PSVC_PLUGIN_VERSION
;
919 if (accessmode
& PICL_VOLATILE
) {
920 propinfo
.read
= read
;
921 propinfo
.write
= write
;
923 propinfo
.read
= NULL
;
924 propinfo
.write
= NULL
;
926 propinfo
.piclinfo
.type
= type
;
927 propinfo
.piclinfo
.accessmode
= accessmode
;
928 propinfo
.piclinfo
.size
= size
;
929 (void) strcpy(propinfo
.piclinfo
.name
, name
);
931 err
= ptree_create_prop(&propinfo
, value
, &prophdl
);
936 err
= ptree_add_prop(node
, prophdl
);
943 static void init_err(const char *fmt
, char *arg1
, char *arg2
)
947 (void) snprintf(msg
, sizeof (msg
), fmt
, arg1
, arg2
);
948 syslog(LOG_ERR
, "%s", msg
);
952 projected_lookup(picl_prophdl_t proph
, struct proj_prop
**dstp
)
956 for (i
= 0; i
< proj_prop_count
; ++i
) {
957 if (prop_list
[i
].handle
== proph
) {
958 *dstp
= &prop_list
[i
];
959 return (PICL_SUCCESS
);
963 return (PICL_INVALIDHANDLE
);
967 projected_read(ptree_rarg_t
*rarg
, void *buf
)
969 ptree_propinfo_t propinfo
;
970 struct proj_prop
*dstinfo
;
973 err
= projected_lookup(rarg
->proph
, &dstinfo
);
975 return (PICL_FAILURE
);
979 err
= ptree_get_propinfo(rarg
->proph
, &propinfo
);
982 err
= ptree_get_propval_by_name(dstinfo
->dst_node
,
983 dstinfo
->name
, buf
, propinfo
.piclinfo
.size
);
986 return (PICL_SUCCESS
);
990 projected_write(ptree_warg_t
*warg
, const void *buf
)
992 ptree_propinfo_t propinfo
;
993 struct proj_prop
*dstinfo
;
996 err
= projected_lookup(warg
->proph
, &dstinfo
);
998 return (PICL_FAILURE
);
1001 err
= ptree_get_propinfo(warg
->proph
, &propinfo
);
1004 err
= ptree_update_propval_by_name(dstinfo
->dst_node
,
1005 dstinfo
->name
, buf
, propinfo
.piclinfo
.size
);
1008 return (PICL_SUCCESS
);
1012 psvc_read_volatile(ptree_rarg_t
*rarg
, void *buf
)
1014 ptree_propinfo_t propinfo
;
1015 char name
[32], class[32];
1017 int32_t attr_num
= -1;
1018 int32_t use_attr_num
= 0;
1020 err
= ptree_get_propval_by_name(rarg
->nodeh
, "name", name
,
1026 err
= ptree_get_propval_by_name(rarg
->nodeh
, "_class", class,
1032 err
= ptree_get_propinfo(rarg
->proph
, &propinfo
);
1037 for (i
= 0; i
< PICL_PROP_TRANS_COUNT
; i
++) {
1038 if ((strcmp(class, picl_prop_trans
[i
].picl_class
) == 0) &&
1039 (strcmp(propinfo
.piclinfo
.name
,
1040 picl_prop_trans
[i
].picl_prop
) == 0)) {
1047 for (i
= 0; i
< ATTR_STR_TAB_SIZE
; i
++) {
1048 if (strcmp(propinfo
.piclinfo
.name
,
1049 attr_str_tab
[i
]) == 0) {
1057 err
= psvc_get_attr(hdlp
, name
, attr_num
, buf
);
1059 err
= psvc_get_attr(hdlp
, name
,
1060 picl_prop_trans
[attr_num
].psvc_prop
,
1064 return (PICL_FAILURE
);
1066 return (PICL_SUCCESS
);
1070 psvc_write_volatile(ptree_warg_t
*warg
, const void *buf
)
1072 ptree_propinfo_t propinfo
;
1073 char name
[32], class[32];
1075 int32_t attr_num
= -1;
1076 int32_t use_attr_num
= 0;
1078 if (warg
->cred
.dc_euid
!= 0)
1079 return (PICL_PERMDENIED
);
1081 err
= ptree_get_propval_by_name(warg
->nodeh
, "name", name
,
1087 err
= ptree_get_propval_by_name(warg
->nodeh
, "_class", class,
1093 err
= ptree_get_propinfo(warg
->proph
, &propinfo
);
1098 for (i
= 0; i
< PICL_PROP_TRANS_COUNT
; i
++) {
1099 if ((strcmp(class, picl_prop_trans
[i
].picl_class
) == 0) &&
1100 (strcmp(propinfo
.piclinfo
.name
,
1101 picl_prop_trans
[i
].picl_prop
) == 0)) {
1108 for (i
= 0; i
< ATTR_STR_TAB_SIZE
; i
++) {
1109 if (strcmp(propinfo
.piclinfo
.name
,
1110 attr_str_tab
[i
]) == 0) {
1118 err
= psvc_set_attr(hdlp
, name
, attr_num
, (void *)buf
);
1120 err
= psvc_set_attr(hdlp
, name
,
1121 picl_prop_trans
[attr_num
].psvc_prop
,
1125 return (PICL_FAILURE
);
1128 return (PICL_SUCCESS
);
1131 void create_reference_properties(struct assoc_pair
*assoc_tbl
, int32_t count
,
1134 picl_psvc_t
*aobjp
, *dobjp
;
1135 picl_prophdl_t tbl_hdl
;
1136 picl_nodehdl_t
*dep_list
;
1137 ptree_propinfo_t propinfo
;
1138 char *funcname
= "create_reference_properties";
1139 char name
[PICL_PROPNAMELEN_MAX
];
1140 int32_t i
, j
, offset
;
1143 char class[PICL_CLASSNAMELEN_MAX
];
1145 for (i
= 0; i
< count
; ++i
) {
1147 aobjp
= (picl_psvc_t
*)bsearch(assoc_tbl
[i
].antecedent
,
1148 psvc_hdl
.objects
, psvc_hdl
.obj_count
,
1149 sizeof (picl_psvc_t
),
1150 (int (*)(const void *, const void *))
1151 name_compare_bsearch
);
1152 if (aobjp
== NULL
) {
1153 init_err(ID_NOT_FOUND_MSG
,
1154 funcname
, assoc_tbl
[i
].antecedent
);
1158 /* skip if table already created */
1159 if (ptree_get_propval_by_name(aobjp
->node
, assoc_name
,
1160 &tbl_hdl
, sizeof (tbl_hdl
)) == 0) {
1164 /* create a new table */
1165 err
= ptree_create_table(&tbl_hdl
);
1167 init_err(PTREE_CREATE_TABLE_FAILED_MSG
,
1168 funcname
, picl_strerror(err
));
1172 err
= node_property(aobjp
->node
, NULL
, NULL
,
1173 PICL_PTYPE_TABLE
, sizeof (tbl_hdl
), PICL_READ
,
1174 assoc_name
, &tbl_hdl
);
1176 init_err(CREATE_PROP_FAILED_MSG
, funcname
,
1177 picl_strerror(err
));
1181 /* determine number of elements in the table */
1183 for (j
= i
; j
< count
; ++j
) {
1184 if (strcmp(aobjp
->name
, assoc_tbl
[j
].antecedent
) == 0)
1188 dep_list
= (picl_nodehdl_t
*)malloc(sizeof (picl_nodehdl_t
) *
1190 if (dep_list
== NULL
) {
1191 init_err(MALLOC_FAILED_MSG
, funcname
, strerror(errno
));
1194 /* build row of reference properties */
1196 for (j
= i
; j
< count
; ++j
) {
1197 if (strcmp(aobjp
->name
, assoc_tbl
[j
].antecedent
) != 0)
1200 dobjp
= (picl_psvc_t
*)bsearch(assoc_tbl
[j
].dependent
,
1202 psvc_hdl
.obj_count
, sizeof (picl_psvc_t
),
1203 (int (*)(const void *, const void *))
1204 name_compare_bsearch
);
1205 if (dobjp
== NULL
) {
1206 init_err(ID_NOT_FOUND_MSG
,
1207 funcname
, assoc_tbl
[j
].dependent
);
1212 * Reference property name must be
1213 * _classname_propertyname
1215 err
= ptree_get_propval_by_name(dobjp
->node
,
1216 "_class", class, sizeof (class));
1218 init_err(CLASS_NOT_FOUND_MSG
, funcname
,
1219 assoc_tbl
[j
].dependent
);
1222 (void) snprintf(name
, sizeof (name
), "_%s_subclass",
1225 propinfo
.version
= PSVC_PLUGIN_VERSION
;
1226 propinfo
.read
= NULL
;
1227 propinfo
.write
= NULL
;
1228 propinfo
.piclinfo
.type
= PICL_PTYPE_REFERENCE
;
1229 propinfo
.piclinfo
.accessmode
= PICL_READ
;
1230 propinfo
.piclinfo
.size
= sizeof (picl_nodehdl_t
);
1231 (void) strcpy(propinfo
.piclinfo
.name
, name
);
1233 err
= ptree_create_prop(&propinfo
, &dobjp
->node
,
1236 init_err(PTREE_CREATE_PROP_FAILED_MSG
,
1237 name
, picl_strerror(err
));
1244 /* add row to table */
1245 err
= ptree_add_row_to_table(tbl_hdl
, dependents
, dep_list
);
1247 init_err(PTREE_ADD_ROW_FAILED_MSG
, funcname
,
1248 picl_strerror(err
));
1257 /* Load projected properties */
1259 load_projected_properties(FILE *fp
)
1262 ptree_propinfo_t propinfo
;
1263 ptree_propinfo_t dstinfo
;
1264 picl_prophdl_t src_prophdl
, dst_prophdl
;
1265 picl_nodehdl_t src_node
, dst_node
;
1267 picl_psvc_t
*srcobjp
, *dstobjp
;
1268 char src
[32], dst
[256];
1269 char src_prop
[32], dst_prop
[32];
1271 char *funcname
= "load_projected_properties";
1273 if (find_file_section(fp
, "PROJECTED_PROPERTIES") != 0)
1276 if (count_records(fp
, "PROJECTED_PROPERTIES_END", &proj_prop_count
) !=
1278 init_err(INVALID_FILE_FORMAT_MSG
, funcname
, 0);
1282 prop_list
= (struct proj_prop
*)malloc(sizeof (struct proj_prop
)
1284 if (prop_list
== NULL
) {
1285 init_err(MALLOC_FAILED_MSG
, funcname
, strerror(errno
));
1289 for (i
= 0; i
< proj_prop_count
; ++i
) {
1291 (void) fgets(buf
, BUFSZ
, fp
);
1292 found
= sscanf(buf
, "%31s %31s %255s %31s", src
, src_prop
, dst
,
1295 init_err(INVALID_FILE_FORMAT_MSG
, funcname
, 0);
1300 if (src
[0] == '/') {
1301 /* picl node name, outside psvc subtree */
1302 err
= ptree_get_node_by_path(src
, &src_node
);
1304 init_err(NODE_NOT_FOUND_MSG
, funcname
, src
);
1308 srcobjp
= (picl_psvc_t
*)bsearch(src
, psvc_hdl
.objects
,
1309 psvc_hdl
.obj_count
, sizeof (picl_psvc_t
),
1310 (int (*)(const void *, const void *))
1311 name_compare_bsearch
);
1312 if (srcobjp
== NULL
) {
1313 init_err(ID_NOT_FOUND_MSG
, funcname
, src
);
1316 src_node
= srcobjp
->node
;
1319 /* find dest node */
1320 if (dst
[0] == '/') {
1321 /* picl node name, outside psvc subtree */
1322 err
= ptree_get_node_by_path(dst
, &dst_node
);
1324 init_err(NODE_NOT_FOUND_MSG
, funcname
, dst
);
1327 prop_list
[i
].dst_node
= dst_node
;
1329 dstobjp
= (picl_psvc_t
*)bsearch(dst
, psvc_hdl
.objects
,
1330 psvc_hdl
.obj_count
, sizeof (picl_psvc_t
),
1331 (int (*)(const void *, const void *))
1332 name_compare_bsearch
);
1333 if (dstobjp
== NULL
) {
1334 init_err(ID_NOT_FOUND_MSG
, funcname
, dst
);
1337 dst_node
= dstobjp
->node
;
1338 prop_list
[i
].dst_node
= dst_node
;
1341 /* determine destination property size */
1342 err
= ptree_get_first_prop(dst_node
, &dst_prophdl
);
1344 err
= ptree_get_propinfo(dst_prophdl
, &dstinfo
);
1347 if (strcmp(dst_prop
, dstinfo
.piclinfo
.name
) == 0)
1349 err
= ptree_get_next_prop(dst_prophdl
, &dst_prophdl
);
1352 init_err(SIZE_NOT_FOUND_MSG
, funcname
, dst_prop
);
1356 propinfo
.version
= PSVC_PLUGIN_VERSION
;
1357 propinfo
.read
= projected_read
;
1358 propinfo
.write
= projected_write
;
1359 propinfo
.piclinfo
.type
= dstinfo
.piclinfo
.type
;
1360 propinfo
.piclinfo
.accessmode
=
1361 PICL_READ
| PICL_WRITE
| PICL_VOLATILE
;
1362 propinfo
.piclinfo
.size
= dstinfo
.piclinfo
.size
;
1363 (void) strcpy(propinfo
.piclinfo
.name
, src_prop
);
1365 err
= ptree_create_prop(&propinfo
, 0, &src_prophdl
);
1367 init_err(PTREE_CREATE_PROP_FAILED_MSG
, funcname
,
1368 picl_strerror(err
));
1372 err
= ptree_add_prop(src_node
, src_prophdl
);
1374 init_err(PTREE_ADD_PROP_FAILED_MSG
, funcname
,
1375 picl_strerror(err
));
1379 prop_list
[i
].handle
= src_prophdl
;
1380 (void) strcpy(prop_list
[i
].name
, dst_prop
);
1385 /* Load the association table */
1386 static void load_associations(FILE *fp
)
1388 char *funcname
= "load_associations";
1392 char assoc_name
[32];
1393 struct assoc_pair
*assoc_tbl
;
1398 * ignore count in the file, correct count is highest
1399 * association id + 1, now figured when loading ASSOC_STR
1402 if (find_file_section(fp
, "ASSOCIATIONS") != 0)
1406 (void) fgets(buf
, BUFSZ
, fp
);
1407 while (strncmp("ASSOCIATIONS_END", buf
, 16) != 0) {
1408 found
= sscanf(buf
, "%31s %31s", name1
, assoc_name
);
1410 init_err(INVALID_FILE_FORMAT_MSG
, funcname
, 0);
1414 if (count_records(fp
, "ASSOCIATION_END", &count
) != 0) {
1415 init_err(INVALID_FILE_FORMAT_MSG
, funcname
, 0);
1419 assoc_tbl
= (struct assoc_pair
*)malloc(
1420 sizeof (struct assoc_pair
) * count
);
1421 if (assoc_tbl
== NULL
) {
1422 init_err(MALLOC_FAILED_MSG
, funcname
, strerror(errno
));
1426 for (j
= 0; j
< count
; ++j
) {
1428 (void) fgets(buf
, BUFSZ
, fp
);
1429 found
= sscanf(buf
, "%31s %31s",
1430 assoc_tbl
[j
].antecedent
, assoc_tbl
[j
].dependent
);
1432 init_err(INVALID_FILE_FORMAT_MSG
, funcname
,
1439 (void) fgets(buf
, BUFSZ
, fp
);
1440 if (strncmp(buf
, "ASSOCIATION_END", 15) != 0) {
1441 init_err(INVALID_FILE_FORMAT_MSG
, funcname
, 0);
1445 /* Create separate list of dependents for each antecedent */
1446 if (strcmp(assoc_name
, "PSVC_TABLE") != 0) {
1447 create_reference_properties(assoc_tbl
, count
,
1453 (void) fgets(buf
, BUFSZ
, fp
);
1458 /* Enviornmental Lock Object's Read and Write routine */
1461 env_lock_read(ptree_rarg_t
*rarg
, void *buf
)
1463 (void) strlcpy((char *)buf
, env_lock_state
, LOCK_STRING_MAX
);
1464 return (PSVC_SUCCESS
);
1469 env_lock_write(ptree_warg_t
*warg
, const void *buf
)
1471 int32_t status
= PSVC_SUCCESS
;
1472 char *var
= (char *)buf
;
1475 * Check to make sure that the value is either Disabled or Enabled
1476 * as these are the only 2 states that this object can be set to.
1478 if ((strcmp(var
, PSVC_LOCK_DISABLED
) != 0) &&
1479 (strcmp(var
, PSVC_LOCK_ENABLED
) != 0)) {
1481 return (PSVC_FAILURE
);
1484 (void) pthread_mutex_lock(&env_lock_mutex
);
1487 * If the state is already Enabled we can set the state to Disabled
1488 * to stop the policies.
1490 if (strcmp(env_lock_state
, PSVC_LOCK_ENABLED
) == 0) {
1491 (void) pthread_mutex_unlock(&env_lock_mutex
);
1492 status
= timed_lock_wait(PSVC_LOCK_DISABLED
);
1494 syslog(LOG_ERR
, SEM_WAIT_FAILED_MSG
);
1500 * If the state is Running we must go into timed_lock_wait to aquire
1503 if (strcmp(env_lock_state
, PSVC_LOCK_RUNNING
) == 0) {
1504 (void) pthread_mutex_unlock(&env_lock_mutex
);
1505 status
= timed_lock_wait(PSVC_LOCK_DISABLED
);
1507 syslog(LOG_ERR
, SEM_WAIT_FAILED_MSG
);
1513 * If the state is already Disabled we need to first check to see if
1514 * we are resetting it to Disabled or changing it to Enabled. If we
1515 * are resetting it to Disabled then we need to stop the timer and
1516 * restart it. If we are changing it to Enabled we just set it to
1519 if (strcmp(env_lock_state
, PSVC_LOCK_DISABLED
) == 0) {
1520 if (strcmp(var
, PSVC_LOCK_DISABLED
) == 0) {
1521 (void) pthread_mutex_lock(&timer_mutex
);
1522 if (timer_state
== ACTIVE
) {
1523 timer_state
= NOT_READY
;
1525 (void) pthread_cond_signal(&timer_cond
);
1526 (void) pthread_mutex_unlock(&timer_mutex
);
1527 /* wait for timer to reset */
1528 while (timer_state
!= READY
)
1529 (void) sched_yield();
1530 (void) pthread_mutex_lock(&timer_mutex
);
1531 timer_state
= HAVE_REQUEST
;
1533 (void) pthread_cond_signal(&timer_cond
);
1535 (void) pthread_mutex_unlock(&timer_mutex
);
1537 (void) strlcpy(env_lock_state
, var
, LOCK_STRING_MAX
);
1540 (void) pthread_mutex_unlock(&env_lock_mutex
);
1541 return (PSVC_SUCCESS
);
1545 init_env_lock_node(picl_nodehdl_t root_node
)
1548 ptree_propinfo_t propinfo
;
1549 char *funcname
= "init_env_lock_node";
1551 /* Here we are creating a Enviornmental Lock Node */
1552 err
= ptree_create_node("/plugins/environmental", "picl", &lock_node
);
1553 if (err
!= PICL_SUCCESS
) {
1554 init_err(PTREE_CREATE_NODE_FAILED_MSG
, funcname
,
1555 picl_strerror(err
));
1559 err
= ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION_1
,
1560 PICL_PTYPE_CHARSTRING
, PICL_READ
| PICL_WRITE
| PICL_VOLATILE
,
1561 32, "State", env_lock_read
, env_lock_write
);
1562 if (err
!= PICL_SUCCESS
) {
1563 init_err(NODE_PROP_FAILED_MSG
, funcname
, picl_strerror(err
));
1567 err
= ptree_create_and_add_prop(lock_node
, &propinfo
,
1569 if (err
!= PICL_SUCCESS
) {
1570 init_err(PTREE_ADD_PROP_FAILED_MSG
, funcname
,
1571 picl_strerror(err
));
1575 err
= ptree_add_node(root_node
, lock_node
);
1576 if (err
!= PICL_SUCCESS
) {
1577 init_err(PTREE_ADD_NODE_FAILED_MSG
, funcname
,
1578 picl_strerror(err
));
1582 return (PSVC_SUCCESS
);
1586 psvc_plugin_init(void)
1588 struct classinfo
*cp
;
1589 picl_nodehdl_t root_node
;
1590 picl_nodehdl_t parent_node
;
1591 char *funcname
= "psvc_plugin_init";
1599 psvc_hdl
.obj_count
= 0;
1600 psvc_hdl
.objects
= NULL
;
1602 first_interval
= NULL
;
1605 * So the volatile read/write routines can retrieve data from
1608 err
= psvc_init(&hdlp
);
1610 init_err(PSVC_INIT_ERR_MSG
, funcname
, strerror(errno
));
1613 if (sysinfo(SI_PLATFORM
, platform
, sizeof (platform
)) == -1) {
1614 init_err(SYSINFO_FAILED_MSG
, funcname
, 0);
1618 (void) snprintf(filename
, sizeof (filename
),
1619 "/usr/platform/%s/lib/psvcobj.conf", platform
);
1620 if ((psvc_hdl
.fp
= fopen(filename
, "r")) == NULL
) {
1621 init_err(FILE_OPEN_FAILED_MSG
, funcname
, filename
);
1625 /* Create all PICL nodes */
1626 if (find_file_section(psvc_hdl
.fp
, "OBJECT_INFO") == -1) {
1627 init_err(INVALID_FILE_FORMAT1_MSG
, funcname
, filename
);
1630 if (count_records(psvc_hdl
.fp
, "OBJECT_INFO_END", &psvc_hdl
.obj_count
)
1632 init_err(INVALID_FILE_FORMAT1_MSG
, funcname
, filename
);
1635 if ((psvc_hdl
.objects
= (picl_psvc_t
*)malloc(sizeof (picl_psvc_t
) *
1636 psvc_hdl
.obj_count
)) == NULL
) {
1637 init_err(MALLOC_FAILED_MSG
, funcname
, strerror(errno
));
1640 (void) memset(psvc_hdl
.objects
, 0,
1641 sizeof (picl_psvc_t
) * psvc_hdl
.obj_count
);
1643 err
= ptree_get_root(&root_node
);
1645 init_err(PTREE_GET_ROOT_FAILED_MSG
, funcname
,
1646 picl_strerror(err
));
1650 /* Following array is accessed directly by the psvc policies. */
1651 psvc_paths
= (psvc_name_t
*)malloc(sizeof (psvc_name_t
) *
1652 psvc_hdl
.obj_count
);
1653 psvc_picl_nodes
= psvc_hdl
.obj_count
;
1654 if (psvc_paths
== NULL
) {
1655 init_err(MALLOC_FAILED_MSG
, funcname
, strerror(errno
));
1658 for (i
= 0; i
< psvc_hdl
.obj_count
; ++i
) {
1663 picl_psvc_t
*objp
= &psvc_hdl
.objects
[i
];
1665 (void) fgets(buf
, BUFSZ
, psvc_hdl
.fp
);
1666 if (strncmp(buf
, "OBJECT_INFO_END", 15) == 0)
1669 start
= strrchr(buf
, '/');
1670 if (start
== NULL
) {
1671 init_err(INVALID_FILE_FORMAT1_MSG
, funcname
,
1675 found
= sscanf(start
+ 1, "%31s", objp
->name
);
1677 init_err(INVALID_FILE_FORMAT1_MSG
, funcname
,
1683 err
= psvc_get_attr(hdlp
, objp
->name
, PSVC_CLASS_ATTR
, &class);
1684 if (err
!= PSVC_SUCCESS
) {
1685 init_err(CLASS_NOT_FOUND_MSG
, funcname
, objp
->name
);
1688 if (class > NUM_CLASSES
) {
1689 init_err(UNKNOWN_CLASS_MSG
, funcname
, 0);
1693 err
= psvc_get_attr(hdlp
, objp
->name
, PSVC_SUBCLASS_ATTR
,
1695 if (err
!= PSVC_SUCCESS
) {
1696 init_err(SUBCLASS_NOT_FOUND_MSG
, funcname
, objp
->name
);
1700 err
= ptree_create_node(objp
->name
, class_name
[class],
1703 init_err(PTREE_CREATE_NODE_FAILED_MSG
, funcname
,
1704 picl_strerror(err
));
1707 if (strcmp(objp
->name
, PSVC_CHASSIS
) == 0)
1708 system_node
= objp
->node
;
1710 for (j
= 0; j
< COMMON_COUNT
; ++j
) {
1712 err
= node_property(objp
->node
,
1713 common
[j
].access
& PICL_READ
?
1714 psvc_read_volatile
: 0,
1715 common
[j
].access
& PICL_WRITE
?
1716 psvc_write_volatile
: 0,
1717 common
[j
].type
, common
[j
].size
,
1718 common
[j
].access
, common
[j
].name
, 0);
1719 if (err
!= PSVC_SUCCESS
) {
1720 init_err(NODE_PROP_FAILED_MSG
, funcname
,
1721 picl_strerror(err
));
1725 cp
= &class_properties
[class];
1726 /* Locator LED Support */
1727 if (class == 2 && subclass
== 2) {
1730 cp_count
= cp
->count
;
1733 for (j
= 0; j
< cp_count
; ++j
) {
1734 err
= node_property(objp
->node
, psvc_read_volatile
,
1735 psvc_write_volatile
, cp
->props
[j
].type
,
1737 cp
->props
[j
].access
, cp
->props
[j
].name
, 0);
1738 if (err
!= PSVC_SUCCESS
) {
1739 init_err(NODE_PROP_FAILED_MSG
, funcname
,
1740 picl_strerror(err
));
1745 /* Link the nodes into the PICL tree */
1747 if (start
== buf
) { /* no parent */
1748 parent_node
= root_node
;
1750 err
= ptree_get_node_by_path(buf
, &parent_node
);
1751 if (err
!= PICL_SUCCESS
) {
1752 init_err(NODE_NOT_FOUND_MSG
, funcname
, buf
);
1757 err
= ptree_add_node(parent_node
, objp
->node
);
1758 if (err
!= PICL_SUCCESS
) {
1759 init_err(PTREE_ADD_NODE_FAILED_MSG
, funcname
,
1760 picl_strerror(err
));
1763 (void) strcpy(psvc_paths
[i
].parent_path
, buf
);
1764 (void) strcpy(psvc_paths
[i
].child_name
, objp
->name
);
1765 psvc_paths
[i
].child_node
= objp
->node
;
1768 qsort(psvc_hdl
.objects
, psvc_hdl
.obj_count
, sizeof (picl_psvc_t
),
1769 (int (*)(const void *, const void *))name_compare_qsort
);
1771 load_associations(psvc_hdl
.fp
);
1772 load_projected_properties(psvc_hdl
.fp
);
1774 if (init_env_lock_node(root_node
) != PSVC_SUCCESS
)
1781 psvc_plugin_fini(void)
1784 EInterval_t
*ip
, *next
;
1787 for (ip
= first_interval
; ip
!= 0; ip
= next
) {
1788 for (i
= 0; i
< ip
->num_tasks
; ++i
) {
1789 (void) dlclose(ip
->task_list
[i
].hdl
);
1790 free(ip
->task_list
[i
].obj_list
);
1792 free(ip
->task_list
);
1798 free(psvc_hdl
.objects
);
1799 if (psvc_hdl
.fp
!= NULL
)
1800 (void) fclose(psvc_hdl
.fp
);
1805 psvc_plugin_register(void)
1807 picld_plugin_register(&psvc_reg
);