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
);
810 if (first_interval
== 0)
817 if (ip
->interval
== 0) {
824 if (intervals
== 0) {
826 syslog(LOG_ERR
, "ERROR: No policies started");
832 syslog(LOG_ERR
, "%s", strerror(errno
));
838 static int32_t count_records(FILE *fp
, char *end
, uint32_t *countp
)
845 first_record
= ftell(fp
);
847 while ((ret
= fgets(buf
, BUFSZ
, fp
)) != NULL
) {
848 if (strncmp(end
, buf
, strlen(end
)) == 0)
858 (void) fseek(fp
, first_record
, SEEK_SET
);
864 * Find start of a section within the config file,
865 * Returns number of records in the section.
866 * FILE *fd is set to first data record within section.
869 find_file_section(FILE *fd
, char *start
)
876 (void) fseek(fd
, 0, SEEK_SET
);
877 while ((ret
= fgets(buf
, BUFSZ
, fd
)) != NULL
) {
878 if (strncmp(start
, buf
, strlen(start
)) == 0)
887 found
= sscanf(buf
, "%31s", name
);
897 static int32_t name_compare_qsort(picl_psvc_t
*s1
, picl_psvc_t
*s2
)
899 return (strcmp(s1
->name
, s2
->name
));
902 static int32_t name_compare_bsearch(char *s1
, picl_psvc_t
*s2
)
904 return (strcmp(s1
, s2
->name
));
908 * Create a property and add it to the specified node.
909 * PICL will take a segmentation violation if a volatile property
910 * has a non-zero size.
912 static int32_t node_property(picl_nodehdl_t node
,
913 int (*read
)(ptree_rarg_t
*, void *),
914 int (*write
)(ptree_warg_t
*, const void *), picl_prop_type_t type
,
915 unsigned int size
, unsigned int accessmode
, char *name
, void *value
)
917 ptree_propinfo_t propinfo
;
918 picl_prophdl_t prophdl
;
921 propinfo
.version
= PSVC_PLUGIN_VERSION
;
922 if (accessmode
& PICL_VOLATILE
) {
923 propinfo
.read
= read
;
924 propinfo
.write
= write
;
926 propinfo
.read
= NULL
;
927 propinfo
.write
= NULL
;
929 propinfo
.piclinfo
.type
= type
;
930 propinfo
.piclinfo
.accessmode
= accessmode
;
931 propinfo
.piclinfo
.size
= size
;
932 (void) strcpy(propinfo
.piclinfo
.name
, name
);
934 err
= ptree_create_prop(&propinfo
, value
, &prophdl
);
939 err
= ptree_add_prop(node
, prophdl
);
946 static void init_err(const char *fmt
, char *arg1
, char *arg2
)
950 (void) snprintf(msg
, sizeof (msg
), fmt
, arg1
, arg2
);
951 syslog(LOG_ERR
, "%s", msg
);
955 projected_lookup(picl_prophdl_t proph
, struct proj_prop
**dstp
)
959 for (i
= 0; i
< proj_prop_count
; ++i
) {
960 if (prop_list
[i
].handle
== proph
) {
961 *dstp
= &prop_list
[i
];
962 return (PICL_SUCCESS
);
966 return (PICL_INVALIDHANDLE
);
970 projected_read(ptree_rarg_t
*rarg
, void *buf
)
972 ptree_propinfo_t propinfo
;
973 struct proj_prop
*dstinfo
;
976 err
= projected_lookup(rarg
->proph
, &dstinfo
);
978 return (PICL_FAILURE
);
982 err
= ptree_get_propinfo(rarg
->proph
, &propinfo
);
985 err
= ptree_get_propval_by_name(dstinfo
->dst_node
,
986 dstinfo
->name
, buf
, propinfo
.piclinfo
.size
);
989 return (PICL_SUCCESS
);
993 projected_write(ptree_warg_t
*warg
, const void *buf
)
995 ptree_propinfo_t propinfo
;
996 struct proj_prop
*dstinfo
;
999 err
= projected_lookup(warg
->proph
, &dstinfo
);
1001 return (PICL_FAILURE
);
1004 err
= ptree_get_propinfo(warg
->proph
, &propinfo
);
1007 err
= ptree_update_propval_by_name(dstinfo
->dst_node
,
1008 dstinfo
->name
, buf
, propinfo
.piclinfo
.size
);
1011 return (PICL_SUCCESS
);
1015 psvc_read_volatile(ptree_rarg_t
*rarg
, void *buf
)
1017 ptree_propinfo_t propinfo
;
1018 char name
[32], class[32];
1020 int32_t attr_num
= -1;
1021 int32_t use_attr_num
= 0;
1023 err
= ptree_get_propval_by_name(rarg
->nodeh
, "name", name
,
1029 err
= ptree_get_propval_by_name(rarg
->nodeh
, "_class", class,
1035 err
= ptree_get_propinfo(rarg
->proph
, &propinfo
);
1040 for (i
= 0; i
< PICL_PROP_TRANS_COUNT
; i
++) {
1041 if ((strcmp(class, picl_prop_trans
[i
].picl_class
) == 0) &&
1042 (strcmp(propinfo
.piclinfo
.name
,
1043 picl_prop_trans
[i
].picl_prop
) == 0)) {
1050 for (i
= 0; i
< ATTR_STR_TAB_SIZE
; i
++) {
1051 if (strcmp(propinfo
.piclinfo
.name
,
1052 attr_str_tab
[i
]) == 0) {
1060 err
= psvc_get_attr(hdlp
, name
, attr_num
, buf
);
1062 err
= psvc_get_attr(hdlp
, name
,
1063 picl_prop_trans
[attr_num
].psvc_prop
,
1067 return (PICL_FAILURE
);
1069 return (PICL_SUCCESS
);
1073 psvc_write_volatile(ptree_warg_t
*warg
, const void *buf
)
1075 ptree_propinfo_t propinfo
;
1076 char name
[32], class[32];
1078 int32_t attr_num
= -1;
1079 int32_t use_attr_num
= 0;
1081 if (warg
->cred
.dc_euid
!= 0)
1082 return (PICL_PERMDENIED
);
1084 err
= ptree_get_propval_by_name(warg
->nodeh
, "name", name
,
1090 err
= ptree_get_propval_by_name(warg
->nodeh
, "_class", class,
1096 err
= ptree_get_propinfo(warg
->proph
, &propinfo
);
1101 for (i
= 0; i
< PICL_PROP_TRANS_COUNT
; i
++) {
1102 if ((strcmp(class, picl_prop_trans
[i
].picl_class
) == 0) &&
1103 (strcmp(propinfo
.piclinfo
.name
,
1104 picl_prop_trans
[i
].picl_prop
) == 0)) {
1111 for (i
= 0; i
< ATTR_STR_TAB_SIZE
; i
++) {
1112 if (strcmp(propinfo
.piclinfo
.name
,
1113 attr_str_tab
[i
]) == 0) {
1121 err
= psvc_set_attr(hdlp
, name
, attr_num
, (void *)buf
);
1123 err
= psvc_set_attr(hdlp
, name
,
1124 picl_prop_trans
[attr_num
].psvc_prop
,
1128 return (PICL_FAILURE
);
1131 return (PICL_SUCCESS
);
1134 void create_reference_properties(struct assoc_pair
*assoc_tbl
, int32_t count
,
1137 picl_psvc_t
*aobjp
, *dobjp
;
1138 picl_prophdl_t tbl_hdl
;
1139 picl_nodehdl_t
*dep_list
;
1140 ptree_propinfo_t propinfo
;
1141 char *funcname
= "create_reference_properties";
1142 char name
[PICL_PROPNAMELEN_MAX
];
1143 int32_t i
, j
, offset
;
1146 char class[PICL_CLASSNAMELEN_MAX
];
1148 for (i
= 0; i
< count
; ++i
) {
1150 aobjp
= (picl_psvc_t
*)bsearch(assoc_tbl
[i
].antecedent
,
1151 psvc_hdl
.objects
, psvc_hdl
.obj_count
,
1152 sizeof (picl_psvc_t
),
1153 (int (*)(const void *, const void *))
1154 name_compare_bsearch
);
1155 if (aobjp
== NULL
) {
1156 init_err(ID_NOT_FOUND_MSG
,
1157 funcname
, assoc_tbl
[i
].antecedent
);
1161 /* skip if table already created */
1162 if (ptree_get_propval_by_name(aobjp
->node
, assoc_name
,
1163 &tbl_hdl
, sizeof (tbl_hdl
)) == 0) {
1167 /* create a new table */
1168 err
= ptree_create_table(&tbl_hdl
);
1170 init_err(PTREE_CREATE_TABLE_FAILED_MSG
,
1171 funcname
, picl_strerror(err
));
1175 err
= node_property(aobjp
->node
, NULL
, NULL
,
1176 PICL_PTYPE_TABLE
, sizeof (tbl_hdl
), PICL_READ
,
1177 assoc_name
, &tbl_hdl
);
1179 init_err(CREATE_PROP_FAILED_MSG
, funcname
,
1180 picl_strerror(err
));
1184 /* determine number of elements in the table */
1186 for (j
= i
; j
< count
; ++j
) {
1187 if (strcmp(aobjp
->name
, assoc_tbl
[j
].antecedent
) == 0)
1191 dep_list
= (picl_nodehdl_t
*)malloc(sizeof (picl_nodehdl_t
) *
1193 if (dep_list
== NULL
) {
1194 init_err(MALLOC_FAILED_MSG
, funcname
, strerror(errno
));
1197 /* build row of reference properties */
1199 for (j
= i
; j
< count
; ++j
) {
1200 if (strcmp(aobjp
->name
, assoc_tbl
[j
].antecedent
) != 0)
1203 dobjp
= (picl_psvc_t
*)bsearch(assoc_tbl
[j
].dependent
,
1205 psvc_hdl
.obj_count
, sizeof (picl_psvc_t
),
1206 (int (*)(const void *, const void *))
1207 name_compare_bsearch
);
1208 if (dobjp
== NULL
) {
1209 init_err(ID_NOT_FOUND_MSG
,
1210 funcname
, assoc_tbl
[j
].dependent
);
1215 * Reference property name must be
1216 * _classname_propertyname
1218 err
= ptree_get_propval_by_name(dobjp
->node
,
1219 "_class", class, sizeof (class));
1221 init_err(CLASS_NOT_FOUND_MSG
, funcname
,
1222 assoc_tbl
[j
].dependent
);
1225 (void) snprintf(name
, sizeof (name
), "_%s_subclass",
1228 propinfo
.version
= PSVC_PLUGIN_VERSION
;
1229 propinfo
.read
= NULL
;
1230 propinfo
.write
= NULL
;
1231 propinfo
.piclinfo
.type
= PICL_PTYPE_REFERENCE
;
1232 propinfo
.piclinfo
.accessmode
= PICL_READ
;
1233 propinfo
.piclinfo
.size
= sizeof (picl_nodehdl_t
);
1234 (void) strcpy(propinfo
.piclinfo
.name
, name
);
1236 err
= ptree_create_prop(&propinfo
, &dobjp
->node
,
1239 init_err(PTREE_CREATE_PROP_FAILED_MSG
,
1240 name
, picl_strerror(err
));
1247 /* add row to table */
1248 err
= ptree_add_row_to_table(tbl_hdl
, dependents
, dep_list
);
1250 init_err(PTREE_ADD_ROW_FAILED_MSG
, funcname
,
1251 picl_strerror(err
));
1260 /* Load projected properties */
1262 load_projected_properties(FILE *fp
)
1265 ptree_propinfo_t propinfo
;
1266 ptree_propinfo_t dstinfo
;
1267 picl_prophdl_t src_prophdl
, dst_prophdl
;
1268 picl_nodehdl_t src_node
, dst_node
;
1270 picl_psvc_t
*srcobjp
, *dstobjp
;
1271 char src
[32], dst
[256];
1272 char src_prop
[32], dst_prop
[32];
1274 char *funcname
= "load_projected_properties";
1276 if (find_file_section(fp
, "PROJECTED_PROPERTIES") != 0)
1279 if (count_records(fp
, "PROJECTED_PROPERTIES_END", &proj_prop_count
) !=
1281 init_err(INVALID_FILE_FORMAT_MSG
, funcname
, 0);
1285 prop_list
= (struct proj_prop
*)malloc(sizeof (struct proj_prop
)
1287 if (prop_list
== NULL
) {
1288 init_err(MALLOC_FAILED_MSG
, funcname
, strerror(errno
));
1292 for (i
= 0; i
< proj_prop_count
; ++i
) {
1294 (void) fgets(buf
, BUFSZ
, fp
);
1295 found
= sscanf(buf
, "%31s %31s %255s %31s", src
, src_prop
, dst
,
1298 init_err(INVALID_FILE_FORMAT_MSG
, funcname
, 0);
1303 if (src
[0] == '/') {
1304 /* picl node name, outside psvc subtree */
1305 err
= ptree_get_node_by_path(src
, &src_node
);
1307 init_err(NODE_NOT_FOUND_MSG
, funcname
, src
);
1311 srcobjp
= (picl_psvc_t
*)bsearch(src
, psvc_hdl
.objects
,
1312 psvc_hdl
.obj_count
, sizeof (picl_psvc_t
),
1313 (int (*)(const void *, const void *))
1314 name_compare_bsearch
);
1315 if (srcobjp
== NULL
) {
1316 init_err(ID_NOT_FOUND_MSG
, funcname
, src
);
1319 src_node
= srcobjp
->node
;
1322 /* find dest node */
1323 if (dst
[0] == '/') {
1324 /* picl node name, outside psvc subtree */
1325 err
= ptree_get_node_by_path(dst
, &dst_node
);
1327 init_err(NODE_NOT_FOUND_MSG
, funcname
, dst
);
1330 prop_list
[i
].dst_node
= dst_node
;
1332 dstobjp
= (picl_psvc_t
*)bsearch(dst
, psvc_hdl
.objects
,
1333 psvc_hdl
.obj_count
, sizeof (picl_psvc_t
),
1334 (int (*)(const void *, const void *))
1335 name_compare_bsearch
);
1336 if (dstobjp
== NULL
) {
1337 init_err(ID_NOT_FOUND_MSG
, funcname
, dst
);
1340 dst_node
= dstobjp
->node
;
1341 prop_list
[i
].dst_node
= dst_node
;
1344 /* determine destination property size */
1345 err
= ptree_get_first_prop(dst_node
, &dst_prophdl
);
1347 err
= ptree_get_propinfo(dst_prophdl
, &dstinfo
);
1350 if (strcmp(dst_prop
, dstinfo
.piclinfo
.name
) == 0)
1352 err
= ptree_get_next_prop(dst_prophdl
, &dst_prophdl
);
1355 init_err(SIZE_NOT_FOUND_MSG
, funcname
, dst_prop
);
1359 propinfo
.version
= PSVC_PLUGIN_VERSION
;
1360 propinfo
.read
= projected_read
;
1361 propinfo
.write
= projected_write
;
1362 propinfo
.piclinfo
.type
= dstinfo
.piclinfo
.type
;
1363 propinfo
.piclinfo
.accessmode
=
1364 PICL_READ
| PICL_WRITE
| PICL_VOLATILE
;
1365 propinfo
.piclinfo
.size
= dstinfo
.piclinfo
.size
;
1366 (void) strcpy(propinfo
.piclinfo
.name
, src_prop
);
1368 err
= ptree_create_prop(&propinfo
, 0, &src_prophdl
);
1370 init_err(PTREE_CREATE_PROP_FAILED_MSG
, funcname
,
1371 picl_strerror(err
));
1375 err
= ptree_add_prop(src_node
, src_prophdl
);
1377 init_err(PTREE_ADD_PROP_FAILED_MSG
, funcname
,
1378 picl_strerror(err
));
1382 prop_list
[i
].handle
= src_prophdl
;
1383 (void) strcpy(prop_list
[i
].name
, dst_prop
);
1388 /* Load the association table */
1389 static void load_associations(FILE *fp
)
1391 char *funcname
= "load_associations";
1395 char assoc_name
[32];
1396 struct assoc_pair
*assoc_tbl
;
1401 * ignore count in the file, correct count is highest
1402 * association id + 1, now figured when loading ASSOC_STR
1405 if (find_file_section(fp
, "ASSOCIATIONS") != 0)
1409 (void) fgets(buf
, BUFSZ
, fp
);
1410 while (strncmp("ASSOCIATIONS_END", buf
, 16) != 0) {
1411 found
= sscanf(buf
, "%31s %31s", name1
, assoc_name
);
1413 init_err(INVALID_FILE_FORMAT_MSG
, funcname
, 0);
1417 if (count_records(fp
, "ASSOCIATION_END", &count
) != 0) {
1418 init_err(INVALID_FILE_FORMAT_MSG
, funcname
, 0);
1422 assoc_tbl
= (struct assoc_pair
*)malloc(
1423 sizeof (struct assoc_pair
) * count
);
1424 if (assoc_tbl
== NULL
) {
1425 init_err(MALLOC_FAILED_MSG
, funcname
, strerror(errno
));
1429 for (j
= 0; j
< count
; ++j
) {
1431 (void) fgets(buf
, BUFSZ
, fp
);
1432 found
= sscanf(buf
, "%31s %31s",
1433 assoc_tbl
[j
].antecedent
, assoc_tbl
[j
].dependent
);
1435 init_err(INVALID_FILE_FORMAT_MSG
, funcname
,
1442 (void) fgets(buf
, BUFSZ
, fp
);
1443 if (strncmp(buf
, "ASSOCIATION_END", 15) != 0) {
1444 init_err(INVALID_FILE_FORMAT_MSG
, funcname
, 0);
1448 /* Create separate list of dependents for each antecedent */
1449 if (strcmp(assoc_name
, "PSVC_TABLE") != 0) {
1450 create_reference_properties(assoc_tbl
, count
,
1456 (void) fgets(buf
, BUFSZ
, fp
);
1461 /* Enviornmental Lock Object's Read and Write routine */
1464 env_lock_read(ptree_rarg_t
*rarg
, void *buf
)
1466 (void) strlcpy((char *)buf
, env_lock_state
, LOCK_STRING_MAX
);
1467 return (PSVC_SUCCESS
);
1472 env_lock_write(ptree_warg_t
*warg
, const void *buf
)
1474 int32_t status
= PSVC_SUCCESS
;
1475 char *var
= (char *)buf
;
1478 * Check to make sure that the value is either Disabled or Enabled
1479 * as these are the only 2 states that this object can be set to.
1481 if ((strcmp(var
, PSVC_LOCK_DISABLED
) != 0) &&
1482 (strcmp(var
, PSVC_LOCK_ENABLED
) != 0)) {
1484 return (PSVC_FAILURE
);
1487 (void) pthread_mutex_lock(&env_lock_mutex
);
1490 * If the state is already Enabled we can set the state to Disabled
1491 * to stop the policies.
1493 if (strcmp(env_lock_state
, PSVC_LOCK_ENABLED
) == 0) {
1494 (void) pthread_mutex_unlock(&env_lock_mutex
);
1495 status
= timed_lock_wait(PSVC_LOCK_DISABLED
);
1497 syslog(LOG_ERR
, SEM_WAIT_FAILED_MSG
);
1503 * If the state is Running we must go into timed_lock_wait to aquire
1506 if (strcmp(env_lock_state
, PSVC_LOCK_RUNNING
) == 0) {
1507 (void) pthread_mutex_unlock(&env_lock_mutex
);
1508 status
= timed_lock_wait(PSVC_LOCK_DISABLED
);
1510 syslog(LOG_ERR
, SEM_WAIT_FAILED_MSG
);
1516 * If the state is already Disabled we need to first check to see if
1517 * we are resetting it to Disabled or changing it to Enabled. If we
1518 * are resetting it to Disabled then we need to stop the timer and
1519 * restart it. If we are changing it to Enabled we just set it to
1522 if (strcmp(env_lock_state
, PSVC_LOCK_DISABLED
) == 0) {
1523 if (strcmp(var
, PSVC_LOCK_DISABLED
) == 0) {
1524 (void) pthread_mutex_lock(&timer_mutex
);
1525 if (timer_state
== ACTIVE
) {
1526 timer_state
= NOT_READY
;
1528 (void) pthread_cond_signal(&timer_cond
);
1529 (void) pthread_mutex_unlock(&timer_mutex
);
1530 /* wait for timer to reset */
1531 while (timer_state
!= READY
)
1532 (void) sched_yield();
1533 (void) pthread_mutex_lock(&timer_mutex
);
1534 timer_state
= HAVE_REQUEST
;
1536 (void) pthread_cond_signal(&timer_cond
);
1538 (void) pthread_mutex_unlock(&timer_mutex
);
1540 (void) strlcpy(env_lock_state
, var
, LOCK_STRING_MAX
);
1543 (void) pthread_mutex_unlock(&env_lock_mutex
);
1544 return (PSVC_SUCCESS
);
1548 init_env_lock_node(picl_nodehdl_t root_node
)
1551 ptree_propinfo_t propinfo
;
1552 char *funcname
= "init_env_lock_node";
1554 /* Here we are creating a Enviornmental Lock Node */
1555 err
= ptree_create_node("/plugins/environmental", "picl", &lock_node
);
1556 if (err
!= PICL_SUCCESS
) {
1557 init_err(PTREE_CREATE_NODE_FAILED_MSG
, funcname
,
1558 picl_strerror(err
));
1562 err
= ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION_1
,
1563 PICL_PTYPE_CHARSTRING
, PICL_READ
| PICL_WRITE
| PICL_VOLATILE
,
1564 32, "State", env_lock_read
, env_lock_write
);
1565 if (err
!= PICL_SUCCESS
) {
1566 init_err(NODE_PROP_FAILED_MSG
, funcname
, picl_strerror(err
));
1570 err
= ptree_create_and_add_prop(lock_node
, &propinfo
,
1572 if (err
!= PICL_SUCCESS
) {
1573 init_err(PTREE_ADD_PROP_FAILED_MSG
, funcname
,
1574 picl_strerror(err
));
1578 err
= ptree_add_node(root_node
, lock_node
);
1579 if (err
!= PICL_SUCCESS
) {
1580 init_err(PTREE_ADD_NODE_FAILED_MSG
, funcname
,
1581 picl_strerror(err
));
1585 return (PSVC_SUCCESS
);
1589 psvc_plugin_init(void)
1591 struct classinfo
*cp
;
1592 picl_nodehdl_t root_node
;
1593 picl_nodehdl_t parent_node
;
1594 char *funcname
= "psvc_plugin_init";
1602 psvc_hdl
.obj_count
= 0;
1603 psvc_hdl
.objects
= NULL
;
1605 first_interval
= NULL
;
1608 * So the volatile read/write routines can retrieve data from
1611 err
= psvc_init(&hdlp
);
1613 init_err(PSVC_INIT_ERR_MSG
, funcname
, strerror(errno
));
1616 if (sysinfo(SI_PLATFORM
, platform
, sizeof (platform
)) == -1) {
1617 init_err(SYSINFO_FAILED_MSG
, funcname
, 0);
1621 (void) snprintf(filename
, sizeof (filename
),
1622 "/usr/platform/%s/lib/psvcobj.conf", platform
);
1623 if ((psvc_hdl
.fp
= fopen(filename
, "r")) == NULL
) {
1624 init_err(FILE_OPEN_FAILED_MSG
, funcname
, filename
);
1628 /* Create all PICL nodes */
1629 if (find_file_section(psvc_hdl
.fp
, "OBJECT_INFO") == -1) {
1630 init_err(INVALID_FILE_FORMAT1_MSG
, funcname
, filename
);
1633 if (count_records(psvc_hdl
.fp
, "OBJECT_INFO_END", &psvc_hdl
.obj_count
)
1635 init_err(INVALID_FILE_FORMAT1_MSG
, funcname
, filename
);
1638 if ((psvc_hdl
.objects
= (picl_psvc_t
*)malloc(sizeof (picl_psvc_t
) *
1639 psvc_hdl
.obj_count
)) == NULL
) {
1640 init_err(MALLOC_FAILED_MSG
, funcname
, strerror(errno
));
1643 (void) memset(psvc_hdl
.objects
, 0,
1644 sizeof (picl_psvc_t
) * psvc_hdl
.obj_count
);
1646 err
= ptree_get_root(&root_node
);
1648 init_err(PTREE_GET_ROOT_FAILED_MSG
, funcname
,
1649 picl_strerror(err
));
1653 /* Following array is accessed directly by the psvc policies. */
1654 psvc_paths
= (psvc_name_t
*)malloc(sizeof (psvc_name_t
) *
1655 psvc_hdl
.obj_count
);
1656 psvc_picl_nodes
= psvc_hdl
.obj_count
;
1657 if (psvc_paths
== NULL
) {
1658 init_err(MALLOC_FAILED_MSG
, funcname
, strerror(errno
));
1661 for (i
= 0; i
< psvc_hdl
.obj_count
; ++i
) {
1666 picl_psvc_t
*objp
= &psvc_hdl
.objects
[i
];
1668 (void) fgets(buf
, BUFSZ
, psvc_hdl
.fp
);
1669 if (strncmp(buf
, "OBJECT_INFO_END", 15) == 0)
1672 start
= strrchr(buf
, '/');
1673 if (start
== NULL
) {
1674 init_err(INVALID_FILE_FORMAT1_MSG
, funcname
,
1678 found
= sscanf(start
+ 1, "%31s", objp
->name
);
1680 init_err(INVALID_FILE_FORMAT1_MSG
, funcname
,
1686 err
= psvc_get_attr(hdlp
, objp
->name
, PSVC_CLASS_ATTR
, &class);
1687 if (err
!= PSVC_SUCCESS
) {
1688 init_err(CLASS_NOT_FOUND_MSG
, funcname
, objp
->name
);
1691 if (class > NUM_CLASSES
) {
1692 init_err(UNKNOWN_CLASS_MSG
, funcname
, 0);
1696 err
= psvc_get_attr(hdlp
, objp
->name
, PSVC_SUBCLASS_ATTR
,
1698 if (err
!= PSVC_SUCCESS
) {
1699 init_err(SUBCLASS_NOT_FOUND_MSG
, funcname
, objp
->name
);
1703 err
= ptree_create_node(objp
->name
, class_name
[class],
1706 init_err(PTREE_CREATE_NODE_FAILED_MSG
, funcname
,
1707 picl_strerror(err
));
1710 if (strcmp(objp
->name
, PSVC_CHASSIS
) == 0)
1711 system_node
= objp
->node
;
1713 for (j
= 0; j
< COMMON_COUNT
; ++j
) {
1715 err
= node_property(objp
->node
,
1716 common
[j
].access
& PICL_READ
?
1717 psvc_read_volatile
: 0,
1718 common
[j
].access
& PICL_WRITE
?
1719 psvc_write_volatile
: 0,
1720 common
[j
].type
, common
[j
].size
,
1721 common
[j
].access
, common
[j
].name
, 0);
1722 if (err
!= PSVC_SUCCESS
) {
1723 init_err(NODE_PROP_FAILED_MSG
, funcname
,
1724 picl_strerror(err
));
1728 cp
= &class_properties
[class];
1729 /* Locator LED Support */
1730 if (class == 2 && subclass
== 2) {
1733 cp_count
= cp
->count
;
1736 for (j
= 0; j
< cp_count
; ++j
) {
1737 err
= node_property(objp
->node
, psvc_read_volatile
,
1738 psvc_write_volatile
, cp
->props
[j
].type
,
1740 cp
->props
[j
].access
, cp
->props
[j
].name
, 0);
1741 if (err
!= PSVC_SUCCESS
) {
1742 init_err(NODE_PROP_FAILED_MSG
, funcname
,
1743 picl_strerror(err
));
1748 /* Link the nodes into the PICL tree */
1750 if (start
== buf
) { /* no parent */
1751 parent_node
= root_node
;
1753 err
= ptree_get_node_by_path(buf
, &parent_node
);
1754 if (err
!= PICL_SUCCESS
) {
1755 init_err(NODE_NOT_FOUND_MSG
, funcname
, buf
);
1760 err
= ptree_add_node(parent_node
, objp
->node
);
1761 if (err
!= PICL_SUCCESS
) {
1762 init_err(PTREE_ADD_NODE_FAILED_MSG
, funcname
,
1763 picl_strerror(err
));
1766 (void) strcpy(psvc_paths
[i
].parent_path
, buf
);
1767 (void) strcpy(psvc_paths
[i
].child_name
, objp
->name
);
1768 psvc_paths
[i
].child_node
= objp
->node
;
1771 qsort(psvc_hdl
.objects
, psvc_hdl
.obj_count
, sizeof (picl_psvc_t
),
1772 (int (*)(const void *, const void *))name_compare_qsort
);
1774 load_associations(psvc_hdl
.fp
);
1775 load_projected_properties(psvc_hdl
.fp
);
1777 if (init_env_lock_node(root_node
) != PSVC_SUCCESS
)
1784 psvc_plugin_fini(void)
1787 EInterval_t
*ip
, *next
;
1790 for (ip
= first_interval
; ip
!= 0; ip
= next
) {
1791 for (i
= 0; i
< ip
->num_tasks
; ++i
) {
1792 (void) dlclose(ip
->task_list
[i
].hdl
);
1793 free(ip
->task_list
[i
].obj_list
);
1795 free(ip
->task_list
);
1801 free(psvc_hdl
.objects
);
1802 if (psvc_hdl
.fp
!= NULL
)
1803 (void) fclose(psvc_hdl
.fp
);
1808 psvc_plugin_register(void)
1810 picld_plugin_register(&psvc_reg
);