8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / picl / plugins / sun4u / psvc / psvcplugin / psvcplugin.c
blobd40a90b2112a7664739e382b72266f913065ebe2
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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,<>.
32 #include <picl.h>
33 #include <picltree.h>
34 #include <stdio.h>
35 #include <time.h>
36 #include <dlfcn.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <stdlib.h>
40 #include <limits.h>
41 #include <ctype.h>
42 #include <pthread.h>
43 #include <libintl.h>
44 #include <errno.h>
45 #include <semaphore.h>
46 #include <sched.h>
47 #include <syslog.h>
48 #include <string.h>
49 #include <signal.h>
50 #include <sys/types.h>
51 #include <sys/systeminfo.h>
52 #include <psvc_objects.h>
53 #include <psvc_objects_class.h>
55 #define BUFSZ 512
57 typedef struct {
58 char name[32];
59 } EName_t;
61 typedef struct {
62 void *hdl;
63 int32_t (*funcp)(void *, char *);
64 int32_t num_objects;
65 EName_t *obj_list;
66 char routine[64];
67 } ETask_t;
69 typedef struct interval_info {
70 volatile int32_t interval;
71 int32_t num_tasks;
72 ETask_t *task_list;
73 pthread_t thread;
74 int32_t has_thread;
75 struct interval_info *next;
76 } EInterval_t;
78 static EInterval_t *first_interval;
80 static psvc_opaque_t hdlp;
82 sem_t timer_sem;
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 *);
89 /* Timer states */
90 #define NOT_READY 0
91 #define READY 1
92 #define HAVE_REQUEST 2
93 #define ACTIVE 3
94 #define TIMER_SHUTDOWN 4
96 int timer_state = NOT_READY;
98 int app_timeout;
100 /* Lock State Loop State Definitions */
101 #define STATE_CHANGED 1
102 #define STATE_NOT_CHANGED 0
104 #ifdef DEBUG
105 static int32_t debug_flag = 1;
106 #else
107 static int32_t debug_flag = 0;
108 #endif
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 */
116 typedef struct {
117 char parent_path[256];
118 char child_name[32];
119 picl_nodehdl_t child_node;
120 } psvc_name_t;
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",
163 "fan",
164 "led",
165 "picl",
166 "digital-sensor",
167 "digital-control",
168 "gpio",
169 "fan-tachometer",
170 "switch",
171 "keyswitch",
172 "gpio",
173 "i2c"
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;
180 char name[32];
183 struct propinfo {
184 char *name;
185 uint32_t type;
186 uint32_t size;
187 uint32_t access;
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.
208 #define LED_COUNT 1
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))
250 struct classinfo {
251 struct propinfo *props;
252 int32_t count;
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 */
263 {0, 0},
264 {0, 0},
265 {gpio8_properties, GPIO8_COUNT},
266 {0, 0},
269 struct prop_trans {
270 char *picl_class;
271 char *picl_prop;
272 int32_t psvc_prop;
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))
302 typedef struct {
303 char name[32];
304 picl_nodehdl_t node;
305 } picl_psvc_t;
307 struct assoc_pair {
308 char antecedent[32];
309 char dependent[32];
312 struct handle {
313 uint32_t obj_count;
314 picl_psvc_t *objects;
315 FILE *fp;
316 } psvc_hdl;
318 struct proj_prop *prop_list;
319 uint32_t proj_prop_count;
321 int psvc_picl_nodes;
323 void psvc_plugin_init(void);
324 void psvc_plugin_fini(void);
326 picld_plugin_reg_t psvc_reg = {
327 PSVC_PLUGIN_VERSION,
328 PICLD_PLUGIN_CRITICAL,
329 "PSVC",
330 psvc_plugin_init,
331 psvc_plugin_fini
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.
341 void
342 psvcplugin_add_children(char *parent_path)
344 int i;
345 picl_nodehdl_t parent_node;
346 char next_path[256];
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);
359 void
360 psvcplugin_lookup(char *name, char *parent, picl_nodehdl_t *node)
362 int i;
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;
372 void
373 timer_thread(void)
375 struct timespec timeout;
376 int status;
379 status = pthread_mutex_lock(&timer_mutex);
380 if (status != 0) {
381 syslog(LOG_ERR, MUTEX_LOCK_FAILED_MSG, strerror(status));
384 for (;;) {
385 /* wait for thread to tell us to start timer */
386 timer_state = READY;
387 do {
388 status = pthread_cond_wait(&timer_cond, &timer_mutex);
389 } while (timer_state == READY && status == 0);
391 if (timer_state == TIMER_SHUTDOWN) {
392 pthread_exit(NULL);
393 /* not reached */
396 if (status != 0) {
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;
409 do {
410 status = pthread_cond_timedwait(&timer_cond,
411 &timer_mutex, &timeout);
412 } while (timer_state == ACTIVE && status == 0);
415 if (status != 0) {
416 if (status == ETIMEDOUT) {
417 syslog(LOG_ERR, PSVC_APP_DEATH_MSG);
418 (void) pthread_mutex_lock(&env_lock_mutex);
419 (void) strlcpy(env_lock_state,
420 PSVC_LOCK_ENABLED, LOCK_STRING_MAX);
421 (void) pthread_mutex_unlock(&env_lock_mutex);
422 } else {
423 syslog(LOG_ERR, CV_TWAIT_FAILED_MSG,
424 strerror(status));
430 static int
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)
445 int32_t status;
447 /* Only want one timer active at a time */
448 do {
449 status = sem_wait(&timer_sem);
450 } while (status == -1 && errno == EINTR);
451 if (status == -1)
452 return (status);
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
463 * enabled.
465 while (lock_state_loop(set_lock_state))
466 (void) sleep(1);
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);
478 return (0);
481 static void lock_and_run(ETask_t *tp, int32_t obj_num)
483 int32_t status;
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);
496 if (status == -1) {
497 syslog(LOG_ERR, SEM_WAIT_FAILED_MSG);
499 } else {
500 (void) strlcpy(env_lock_state, PSVC_LOCK_RUNNING,
501 LOCK_STRING_MAX);
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) {
506 char dev_name[32];
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)
523 ETask_t *tp;
524 int32_t i, j;
526 do {
527 if (ip->interval) {
528 int remaining = ip->interval;
529 do {
530 /* check to see if we've been told to exit */
531 if (ip->has_thread && (ip->interval == 0))
532 break;
533 remaining = sleep(remaining);
534 } while (remaining > 0);
536 for (i = 0; i < ip->num_tasks; ++i) {
537 tp = &ip->task_list[i];
538 for (j = 0; j < tp->num_objects; ++j) {
539 /* check to see if we've been told to exit */
540 if (ip->has_thread && (ip->interval == 0))
541 break;
542 lock_and_run(tp, j);
544 if (ip->has_thread && (ip->interval == 0))
545 break;
547 } while (ip->interval);
550 static void thread_setup(EInterval_t *ip)
552 int32_t status;
554 status = pthread_create(&ip->thread, NULL, (void *(*)())run_policies,
555 ip);
556 if (status != 0) {
557 if (debug_flag)
558 syslog(LOG_ERR, "%s", strerror(errno));
559 exit(-1);
561 ip->has_thread = 1;
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) {
568 if (debug_flag) {
569 char *errstr = dlerror();
570 syslog(LOG_ERR, "%s", errstr);
572 exit(1);
574 tp->funcp = (int32_t (*)(void *, char *))dlsym(tp->hdl, tp->routine);
575 if (tp->funcp == NULL) {
576 if (debug_flag) {
577 char *errstr = dlerror();
578 syslog(LOG_ERR, "%s", errstr);
580 exit(1);
582 return (0);
585 static int32_t get_timeout(FILE *fp, int *timeout)
587 char buf[BUFSZ];
588 char name[32];
589 char *cp;
591 /* skip blank lines */
592 do {
593 cp = fgets(buf, BUFSZ, fp);
594 if (cp == NULL)
595 return (1);
596 while (isspace(*cp))
597 ++cp;
598 (void) sscanf(buf, "%31s %d", name, timeout);
599 } while (*cp == 0 || *cp == '\n' || strcmp(name, "TIMEOUT") != 0);
601 if (strcmp(name, "TIMEOUT") != 0) {
602 errno = EINVAL;
603 return (-1);
605 return (0);
609 static int32_t load_interval(FILE *fp, EInterval_t **ipp)
611 char buf[BUFSZ];
612 int32_t found;
613 EInterval_t *ip;
614 ETask_t *tp;
615 int32_t tasks;
616 int32_t status, i, j;
617 int32_t interval;
618 char name[32];
619 char *cp;
621 /* skip blank lines */
622 do {
623 cp = fgets(buf, BUFSZ, fp);
624 if (cp == NULL)
625 return (1);
626 while (isspace(*cp))
627 ++cp;
628 } while (*cp == 0 || *cp == '\n');
629 found = sscanf(buf, "%31s %d %d", name, &interval, &tasks);
630 if (found != 3) {
631 errno = EINVAL;
632 return (-1);
635 if (strcmp(name, "INTERVAL") != 0) {
636 errno = EINVAL;
637 return (-1);
640 ip = (EInterval_t *)malloc(sizeof (EInterval_t));
641 if (ip == NULL)
642 return (-1);
643 ip->num_tasks = tasks;
644 ip->interval = interval;
645 ip->next = NULL;
646 ip->has_thread = 0;
648 /* allocate and load table */
649 ip->task_list = (ETask_t *)malloc(ip->num_tasks * sizeof (ETask_t));
650 if (ip->task_list == NULL)
651 return (-1);
652 for (i = 0; i < ip->num_tasks; ++i) {
653 tp = &ip->task_list[i];
655 (void) fgets(buf, BUFSZ, fp);
656 found = sscanf(buf, "%31s %1023s %63s",
657 name, library, tp->routine);
658 if (found != 3) {
659 errno = EINVAL;
660 return (-1);
663 status = load_policy(library, tp);
664 if (status == -1)
665 return (-1);
666 found = fscanf(fp, "%d", &tp->num_objects);
667 if (found != 1) {
668 if (debug_flag)
669 syslog(LOG_ERR, "No list of objects for task");
670 errno = EINVAL;
671 return (-1);
673 tp->obj_list =
674 (EName_t *)malloc(tp->num_objects * sizeof (EName_t));
675 if (tp->obj_list == NULL)
676 return (-1);
678 for (j = 0; j < tp->num_objects; ++j) {
679 found = fscanf(fp, "%31s", (char *)(tp->obj_list + j));
680 if (found != 1) {
681 if (debug_flag)
682 syslog(LOG_ERR,
683 "Wrong number of objects for task");
684 errno = EINVAL;
685 return (-1);
688 (void) fgets(buf, BUFSZ, fp); /* reads newline on data line */
689 (void) fgets(buf, BUFSZ, fp);
690 if (strncmp(buf, "TASK_END", 8) != 0) {
691 if (debug_flag)
692 syslog(LOG_ERR, "Expected TASK_END, task %s",
693 tp->routine);
694 errno = EINVAL;
695 return (-1);
699 (void) fgets(buf, BUFSZ, fp);
700 if (strncmp(buf, "INTERVAL_END", 12) != 0) {
701 if (debug_flag)
702 syslog(LOG_ERR, "Expected INTERVAL_END");
703 errno = EINVAL;
704 return (-1);
707 *ipp = ip;
708 return (0);
711 void
712 fini_daemon(void)
714 EInterval_t *ip;
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
723 ip->interval = 0;
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);
745 void
746 init_daemon(void)
748 int32_t intervals = 0;
749 int32_t threads = 0;
750 int32_t status;
751 FILE *fp;
752 char filename[PATH_MAX];
753 char platform[64];
754 EInterval_t *ip, *prev;
756 if (sysinfo(SI_PLATFORM, platform, sizeof (platform)) == -1) {
757 if (debug_flag)
758 syslog(LOG_ERR, "%s", strerror(errno));
759 return;
762 (void) snprintf(filename, sizeof (filename),
763 "/usr/platform/%s/lib/platsvcd.conf", platform);
764 if ((fp = fopen(filename, "r")) == NULL) {
765 if (debug_flag)
766 syslog(LOG_ERR, "%s", strerror(errno));
767 return;
770 status = get_timeout(fp, &app_timeout);
771 if (status != 0) {
772 if (debug_flag)
773 syslog(LOG_ERR, "%s", strerror(errno));
774 return;
777 status = sem_init(&timer_sem, 0, 1);
778 if (status == -1) {
779 if (debug_flag)
780 syslog(LOG_ERR, "%s", strerror(errno));
781 return;
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);
792 if (status != 0) {
793 if (debug_flag)
794 syslog(LOG_ERR, "%s", strerror(errno));
795 return;
798 /* get timer thread running */
799 while (timer_state != READY)
800 (void) sched_yield();
802 for (;;) {
803 status = load_interval(fp, &ip);
804 if (status != 0)
805 break;
807 #ifdef lint
808 prev = NULL;
809 #endif
810 if (first_interval == 0)
811 first_interval = ip;
812 else
813 prev->next = ip;
814 prev = ip;
816 ++intervals;
817 if (ip->interval == 0) {
818 run_policies(ip);
819 } else {
820 thread_setup(ip);
821 ++threads;
824 if (intervals == 0) {
825 if (debug_flag)
826 syslog(LOG_ERR, "ERROR: No policies started");
827 return;
830 if (status == -1) {
831 if (debug_flag)
832 syslog(LOG_ERR, "%s", strerror(errno));
833 return;
838 static int32_t count_records(FILE *fp, char *end, uint32_t *countp)
840 long first_record;
841 char *ret;
842 char buf[BUFSZ];
843 uint32_t count = 0;
845 first_record = ftell(fp);
847 while ((ret = fgets(buf, BUFSZ, fp)) != NULL) {
848 if (strncmp(end, buf, strlen(end)) == 0)
849 break;
850 ++count;
853 if (ret == NULL) {
854 errno = EINVAL;
855 return (-1);
858 (void) fseek(fp, first_record, SEEK_SET);
859 *countp = count;
860 return (0);
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.
868 static int32_t
869 find_file_section(FILE *fd, char *start)
871 char *ret;
872 char buf[BUFSZ];
873 char name[32];
874 int found;
876 (void) fseek(fd, 0, SEEK_SET);
877 while ((ret = fgets(buf, BUFSZ, fd)) != NULL) {
878 if (strncmp(start, buf, strlen(start)) == 0)
879 break;
882 if (ret == NULL) {
883 errno = EINVAL;
884 return (-1);
887 found = sscanf(buf, "%31s", name);
888 if (found != 1) {
889 errno = EINVAL;
890 return (-1);
891 } else {
892 return (0);
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;
919 int err;
921 propinfo.version = PSVC_PLUGIN_VERSION;
922 if (accessmode & PICL_VOLATILE) {
923 propinfo.read = read;
924 propinfo.write = write;
925 } else {
926 propinfo.read = NULL;
927 propinfo.write = NULL;
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);
935 if (err != 0) {
936 return (err);
939 err = ptree_add_prop(node, prophdl);
940 if (err != 0)
941 return (err);
943 return (0);
946 static void init_err(const char *fmt, char *arg1, char *arg2)
948 char msg[256];
950 (void) snprintf(msg, sizeof (msg), fmt, arg1, arg2);
951 syslog(LOG_ERR, "%s", msg);
954 static int
955 projected_lookup(picl_prophdl_t proph, struct proj_prop **dstp)
957 int i;
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;
974 int err;
976 err = projected_lookup(rarg->proph, &dstinfo);
977 if (err != 0) {
978 return (PICL_FAILURE);
982 err = ptree_get_propinfo(rarg->proph, &propinfo);
983 if (err != 0)
984 return (err);
985 err = ptree_get_propval_by_name(dstinfo->dst_node,
986 dstinfo->name, buf, propinfo.piclinfo.size);
987 if (err != 0)
988 return (err);
989 return (PICL_SUCCESS);
993 projected_write(ptree_warg_t *warg, const void *buf)
995 ptree_propinfo_t propinfo;
996 struct proj_prop *dstinfo;
997 int err;
999 err = projected_lookup(warg->proph, &dstinfo);
1000 if (err != 0) {
1001 return (PICL_FAILURE);
1004 err = ptree_get_propinfo(warg->proph, &propinfo);
1005 if (err != 0)
1006 return (err);
1007 err = ptree_update_propval_by_name(dstinfo->dst_node,
1008 dstinfo->name, buf, propinfo.piclinfo.size);
1009 if (err != 0)
1010 return (err);
1011 return (PICL_SUCCESS);
1015 psvc_read_volatile(ptree_rarg_t *rarg, void *buf)
1017 ptree_propinfo_t propinfo;
1018 char name[32], class[32];
1019 int err, i;
1020 int32_t attr_num = -1;
1021 int32_t use_attr_num = 0;
1023 err = ptree_get_propval_by_name(rarg->nodeh, "name", name,
1024 sizeof (name));
1025 if (err != 0) {
1026 return (err);
1029 err = ptree_get_propval_by_name(rarg->nodeh, "_class", class,
1030 sizeof (class));
1031 if (err != 0) {
1032 return (err);
1035 err = ptree_get_propinfo(rarg->proph, &propinfo);
1036 if (err != 0) {
1037 return (err);
1040 for (i = 0; i < PICL_PROP_TRANS_COUNT; i++) {
1041 if ((strcmp(class, picl_prop_trans[i].picl_class) == 0) &&
1042 (strcmp(propinfo.piclinfo.name,
1043 picl_prop_trans[i].picl_prop) == 0)) {
1044 attr_num = i;
1045 break;
1049 if (attr_num == -1)
1050 for (i = 0; i < ATTR_STR_TAB_SIZE; i++) {
1051 if (strcmp(propinfo.piclinfo.name,
1052 attr_str_tab[i]) == 0) {
1053 attr_num = i;
1054 use_attr_num = 1;
1055 break;
1059 if (use_attr_num)
1060 err = psvc_get_attr(hdlp, name, attr_num, buf);
1061 else
1062 err = psvc_get_attr(hdlp, name,
1063 picl_prop_trans[attr_num].psvc_prop,
1064 buf);
1066 if (err != 0) {
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];
1077 int err, i;
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,
1085 sizeof (name));
1086 if (err != 0) {
1087 return (err);
1090 err = ptree_get_propval_by_name(warg->nodeh, "_class", class,
1091 sizeof (class));
1092 if (err != 0) {
1093 return (err);
1096 err = ptree_get_propinfo(warg->proph, &propinfo);
1097 if (err != 0) {
1098 return (err);
1101 for (i = 0; i < PICL_PROP_TRANS_COUNT; i++) {
1102 if ((strcmp(class, picl_prop_trans[i].picl_class) == 0) &&
1103 (strcmp(propinfo.piclinfo.name,
1104 picl_prop_trans[i].picl_prop) == 0)) {
1105 attr_num = i;
1106 break;
1110 if (attr_num == -1)
1111 for (i = 0; i < ATTR_STR_TAB_SIZE; i++) {
1112 if (strcmp(propinfo.piclinfo.name,
1113 attr_str_tab[i]) == 0) {
1114 attr_num = i;
1115 use_attr_num = 1;
1116 break;
1120 if (use_attr_num)
1121 err = psvc_set_attr(hdlp, name, attr_num, (void *)buf);
1122 else
1123 err = psvc_set_attr(hdlp, name,
1124 picl_prop_trans[attr_num].psvc_prop,
1125 (void *)buf);
1127 if (err != 0) {
1128 return (PICL_FAILURE);
1131 return (PICL_SUCCESS);
1134 void create_reference_properties(struct assoc_pair *assoc_tbl, int32_t count,
1135 char *assoc_name)
1137 picl_psvc_t *aobjp, *dobjp;
1138 picl_prophdl_t tbl_hdl;
1139 picl_nodehdl_t *dep_list;
1140 ptree_propinfo_t propinfo;
1141 char *funcname = "create_reference_properties";
1142 char name[PICL_PROPNAMELEN_MAX];
1143 int32_t i, j, offset;
1144 int32_t dependents;
1145 int32_t err;
1146 char class[PICL_CLASSNAMELEN_MAX];
1148 for (i = 0; i < count; ++i) {
1149 /* antecedent */
1150 aobjp = (picl_psvc_t *)bsearch(assoc_tbl[i].antecedent,
1151 psvc_hdl.objects, psvc_hdl.obj_count,
1152 sizeof (picl_psvc_t),
1153 (int (*)(const void *, const void *))
1154 name_compare_bsearch);
1155 if (aobjp == NULL) {
1156 init_err(ID_NOT_FOUND_MSG,
1157 funcname, assoc_tbl[i].antecedent);
1158 return;
1161 /* skip if table already created */
1162 if (ptree_get_propval_by_name(aobjp->node, assoc_name,
1163 &tbl_hdl, sizeof (tbl_hdl)) == 0) {
1164 continue;
1167 /* create a new table */
1168 err = ptree_create_table(&tbl_hdl);
1169 if (err != 0) {
1170 init_err(PTREE_CREATE_TABLE_FAILED_MSG,
1171 funcname, picl_strerror(err));
1172 return;
1175 err = node_property(aobjp->node, NULL, NULL,
1176 PICL_PTYPE_TABLE, sizeof (tbl_hdl), PICL_READ,
1177 assoc_name, &tbl_hdl);
1178 if (err != 0) {
1179 init_err(CREATE_PROP_FAILED_MSG, funcname,
1180 picl_strerror(err));
1181 return;
1184 /* determine number of elements in the table */
1185 dependents = 0;
1186 for (j = i; j < count; ++j) {
1187 if (strcmp(aobjp->name, assoc_tbl[j].antecedent) == 0)
1188 ++dependents;
1191 dep_list = (picl_nodehdl_t *)malloc(sizeof (picl_nodehdl_t) *
1192 dependents);
1193 if (dep_list == NULL) {
1194 init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1195 return;
1197 /* build row of reference properties */
1198 offset = 0;
1199 for (j = i; j < count; ++j) {
1200 if (strcmp(aobjp->name, assoc_tbl[j].antecedent) != 0)
1201 continue;
1203 dobjp = (picl_psvc_t *)bsearch(assoc_tbl[j].dependent,
1204 psvc_hdl.objects,
1205 psvc_hdl.obj_count, sizeof (picl_psvc_t),
1206 (int (*)(const void *, const void *))
1207 name_compare_bsearch);
1208 if (dobjp == NULL) {
1209 init_err(ID_NOT_FOUND_MSG,
1210 funcname, assoc_tbl[j].dependent);
1211 return;
1215 * Reference property name must be
1216 * _classname_propertyname
1218 err = ptree_get_propval_by_name(dobjp->node,
1219 "_class", class, sizeof (class));
1220 if (err != 0) {
1221 init_err(CLASS_NOT_FOUND_MSG, funcname,
1222 assoc_tbl[j].dependent);
1223 return;
1225 (void) snprintf(name, sizeof (name), "_%s_subclass",
1226 class);
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,
1237 dep_list + offset);
1238 if (err != 0) {
1239 init_err(PTREE_CREATE_PROP_FAILED_MSG,
1240 name, picl_strerror(err));
1241 return;
1244 ++offset;
1247 /* add row to table */
1248 err = ptree_add_row_to_table(tbl_hdl, dependents, dep_list);
1249 if (err != 0) {
1250 init_err(PTREE_ADD_ROW_FAILED_MSG, funcname,
1251 picl_strerror(err));
1252 return;
1260 /* Load projected properties */
1261 static void
1262 load_projected_properties(FILE *fp)
1264 int32_t found;
1265 ptree_propinfo_t propinfo;
1266 ptree_propinfo_t dstinfo;
1267 picl_prophdl_t src_prophdl, dst_prophdl;
1268 picl_nodehdl_t src_node, dst_node;
1269 int err, i;
1270 picl_psvc_t *srcobjp, *dstobjp;
1271 char src[32], dst[256];
1272 char src_prop[32], dst_prop[32];
1273 char buf[BUFSZ];
1274 char *funcname = "load_projected_properties";
1276 if (find_file_section(fp, "PROJECTED_PROPERTIES") != 0)
1277 return;
1279 if (count_records(fp, "PROJECTED_PROPERTIES_END", &proj_prop_count) !=
1280 0) {
1281 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1282 return;
1285 prop_list = (struct proj_prop *)malloc(sizeof (struct proj_prop)
1286 * proj_prop_count);
1287 if (prop_list == NULL) {
1288 init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1289 return;
1292 for (i = 0; i < proj_prop_count; ++i) {
1293 buf[0] = '\0';
1294 (void) fgets(buf, BUFSZ, fp);
1295 found = sscanf(buf, "%31s %31s %255s %31s", src, src_prop, dst,
1296 dst_prop);
1297 if (found != 4) {
1298 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1299 return;
1302 /* find src node */
1303 if (src[0] == '/') {
1304 /* picl node name, outside psvc subtree */
1305 err = ptree_get_node_by_path(src, &src_node);
1306 if (err != 0) {
1307 init_err(NODE_NOT_FOUND_MSG, funcname, src);
1308 return;
1310 } else {
1311 srcobjp = (picl_psvc_t *)bsearch(src, psvc_hdl.objects,
1312 psvc_hdl.obj_count, sizeof (picl_psvc_t),
1313 (int (*)(const void *, const void *))
1314 name_compare_bsearch);
1315 if (srcobjp == NULL) {
1316 init_err(ID_NOT_FOUND_MSG, funcname, src);
1317 return;
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);
1326 if (err != 0) {
1327 init_err(NODE_NOT_FOUND_MSG, funcname, dst);
1328 return;
1330 prop_list[i].dst_node = dst_node;
1331 } else {
1332 dstobjp = (picl_psvc_t *)bsearch(dst, psvc_hdl.objects,
1333 psvc_hdl.obj_count, sizeof (picl_psvc_t),
1334 (int (*)(const void *, const void *))
1335 name_compare_bsearch);
1336 if (dstobjp == NULL) {
1337 init_err(ID_NOT_FOUND_MSG, funcname, dst);
1338 return;
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);
1346 while (err == 0) {
1347 err = ptree_get_propinfo(dst_prophdl, &dstinfo);
1348 if (err != 0)
1349 break;
1350 if (strcmp(dst_prop, dstinfo.piclinfo.name) == 0)
1351 break;
1352 err = ptree_get_next_prop(dst_prophdl, &dst_prophdl);
1354 if (err != 0) {
1355 init_err(SIZE_NOT_FOUND_MSG, funcname, dst_prop);
1356 return;
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);
1369 if (err != 0) {
1370 init_err(PTREE_CREATE_PROP_FAILED_MSG, funcname,
1371 picl_strerror(err));
1372 return;
1375 err = ptree_add_prop(src_node, src_prophdl);
1376 if (err != 0) {
1377 init_err(PTREE_ADD_PROP_FAILED_MSG, funcname,
1378 picl_strerror(err));
1379 return;
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";
1392 uint32_t count;
1393 int found;
1394 int j;
1395 char assoc_name[32];
1396 struct assoc_pair *assoc_tbl;
1397 char name1[32];
1398 char buf[BUFSZ];
1401 * ignore count in the file, correct count is highest
1402 * association id + 1, now figured when loading ASSOC_STR
1403 * section.
1405 if (find_file_section(fp, "ASSOCIATIONS") != 0)
1406 return;
1408 buf[0] = '\0';
1409 (void) fgets(buf, BUFSZ, fp);
1410 while (strncmp("ASSOCIATIONS_END", buf, 16) != 0) {
1411 found = sscanf(buf, "%31s %31s", name1, assoc_name);
1412 if (found != 2) {
1413 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1414 return;
1417 if (count_records(fp, "ASSOCIATION_END", &count) != 0) {
1418 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1419 return;
1422 assoc_tbl = (struct assoc_pair *)malloc(
1423 sizeof (struct assoc_pair) * count);
1424 if (assoc_tbl == NULL) {
1425 init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1426 return;
1429 for (j = 0; j < count; ++j) {
1430 buf[0] = '\0';
1431 (void) fgets(buf, BUFSZ, fp);
1432 found = sscanf(buf, "%31s %31s",
1433 assoc_tbl[j].antecedent, assoc_tbl[j].dependent);
1434 if (found != 2) {
1435 init_err(INVALID_FILE_FORMAT_MSG, funcname,
1437 return;
1441 buf[0] = '\0';
1442 (void) fgets(buf, BUFSZ, fp);
1443 if (strncmp(buf, "ASSOCIATION_END", 15) != 0) {
1444 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1445 return;
1448 /* Create separate list of dependents for each antecedent */
1449 if (strcmp(assoc_name, "PSVC_TABLE") != 0) {
1450 create_reference_properties(assoc_tbl, count,
1451 assoc_name);
1454 free(assoc_tbl);
1455 buf[0] = '\0';
1456 (void) fgets(buf, BUFSZ, fp);
1461 /* Enviornmental Lock Object's Read and Write routine */
1462 /* ARGSUSED */
1463 static int
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);
1470 /* ARGSUSED */
1471 static int
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)) {
1483 errno = EINVAL;
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);
1496 if (status == -1) {
1497 syslog(LOG_ERR, SEM_WAIT_FAILED_MSG);
1499 return (status);
1503 * If the state is Running we must go into timed_lock_wait to aquire
1504 * the env_lock.
1506 if (strcmp(env_lock_state, PSVC_LOCK_RUNNING) == 0) {
1507 (void) pthread_mutex_unlock(&env_lock_mutex);
1508 status = timed_lock_wait(PSVC_LOCK_DISABLED);
1509 if (status == -1) {
1510 syslog(LOG_ERR, SEM_WAIT_FAILED_MSG);
1512 return (status);
1516 * If the state is already Disabled we need to first check to see if
1517 * we are resetting it to Disabled or changing it to Enabled. If we
1518 * are resetting it to Disabled then we need to stop the timer and
1519 * restart it. If we are changing it to Enabled we just set it to
1520 * enabled.
1522 if (strcmp(env_lock_state, PSVC_LOCK_DISABLED) == 0) {
1523 if (strcmp(var, PSVC_LOCK_DISABLED) == 0) {
1524 (void) pthread_mutex_lock(&timer_mutex);
1525 if (timer_state == ACTIVE) {
1526 timer_state = NOT_READY;
1527 /* stop timer */
1528 (void) pthread_cond_signal(&timer_cond);
1529 (void) pthread_mutex_unlock(&timer_mutex);
1530 /* wait for timer to reset */
1531 while (timer_state != READY)
1532 (void) sched_yield();
1533 (void) pthread_mutex_lock(&timer_mutex);
1534 timer_state = HAVE_REQUEST;
1535 /* restart timer */
1536 (void) pthread_cond_signal(&timer_cond);
1538 (void) pthread_mutex_unlock(&timer_mutex);
1539 } else {
1540 (void) strlcpy(env_lock_state, var, LOCK_STRING_MAX);
1543 (void) pthread_mutex_unlock(&env_lock_mutex);
1544 return (PSVC_SUCCESS);
1547 static int
1548 init_env_lock_node(picl_nodehdl_t root_node)
1550 int err;
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));
1559 return (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));
1567 return (err);
1570 err = ptree_create_and_add_prop(lock_node, &propinfo,
1571 NULL, NULL);
1572 if (err != PICL_SUCCESS) {
1573 init_err(PTREE_ADD_PROP_FAILED_MSG, funcname,
1574 picl_strerror(err));
1575 return (err);
1578 err = ptree_add_node(root_node, lock_node);
1579 if (err != PICL_SUCCESS) {
1580 init_err(PTREE_ADD_NODE_FAILED_MSG, funcname,
1581 picl_strerror(err));
1582 return (err);
1585 return (PSVC_SUCCESS);
1588 void
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";
1595 char platform[32];
1596 char filename[256];
1597 char buf[BUFSZ];
1598 int32_t i, j;
1599 int err, found;
1601 psvc_paths = NULL;
1602 psvc_hdl.obj_count = 0;
1603 psvc_hdl.objects = NULL;
1604 psvc_hdl.fp = NULL;
1605 first_interval = NULL;
1608 * So the volatile read/write routines can retrieve data from
1609 * psvc or picl
1611 err = psvc_init(&hdlp);
1612 if (err != 0) {
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);
1618 return;
1621 (void) snprintf(filename, sizeof (filename),
1622 "/usr/platform/%s/lib/psvcobj.conf", platform);
1623 if ((psvc_hdl.fp = fopen(filename, "r")) == NULL) {
1624 init_err(FILE_OPEN_FAILED_MSG, funcname, filename);
1625 return;
1628 /* Create all PICL nodes */
1629 if (find_file_section(psvc_hdl.fp, "OBJECT_INFO") == -1) {
1630 init_err(INVALID_FILE_FORMAT1_MSG, funcname, filename);
1631 return;
1633 if (count_records(psvc_hdl.fp, "OBJECT_INFO_END", &psvc_hdl.obj_count)
1634 == -1) {
1635 init_err(INVALID_FILE_FORMAT1_MSG, funcname, filename);
1636 return;
1638 if ((psvc_hdl.objects = (picl_psvc_t *)malloc(sizeof (picl_psvc_t) *
1639 psvc_hdl.obj_count)) == NULL) {
1640 init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1641 return;
1643 (void) memset(psvc_hdl.objects, 0,
1644 sizeof (picl_psvc_t) * psvc_hdl.obj_count);
1646 err = ptree_get_root(&root_node);
1647 if (err != 0) {
1648 init_err(PTREE_GET_ROOT_FAILED_MSG, funcname,
1649 picl_strerror(err));
1650 return;
1653 /* Following array is accessed directly by the psvc policies. */
1654 psvc_paths = (psvc_name_t *)malloc(sizeof (psvc_name_t) *
1655 psvc_hdl.obj_count);
1656 psvc_picl_nodes = psvc_hdl.obj_count;
1657 if (psvc_paths == NULL) {
1658 init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1659 return;
1661 for (i = 0; i < psvc_hdl.obj_count; ++i) {
1662 char *start;
1663 int32_t class;
1664 int32_t subclass;
1665 int32_t cp_count;
1666 picl_psvc_t *objp = &psvc_hdl.objects[i];
1667 buf[0] = '\0';
1668 (void) fgets(buf, BUFSZ, psvc_hdl.fp);
1669 if (strncmp(buf, "OBJECT_INFO_END", 15) == 0)
1670 break;
1672 start = strrchr(buf, '/');
1673 if (start == NULL) {
1674 init_err(INVALID_FILE_FORMAT1_MSG, funcname,
1675 filename);
1676 return;
1678 found = sscanf(start + 1, "%31s", objp->name);
1679 if (found != 1) {
1680 init_err(INVALID_FILE_FORMAT1_MSG, funcname,
1681 filename);
1682 return;
1685 /* get class */
1686 err = psvc_get_attr(hdlp, objp->name, PSVC_CLASS_ATTR, &class);
1687 if (err != PSVC_SUCCESS) {
1688 init_err(CLASS_NOT_FOUND_MSG, funcname, objp->name);
1689 return;
1691 if (class > NUM_CLASSES) {
1692 init_err(UNKNOWN_CLASS_MSG, funcname, 0);
1693 return;
1696 err = psvc_get_attr(hdlp, objp->name, PSVC_SUBCLASS_ATTR,
1697 &subclass);
1698 if (err != PSVC_SUCCESS) {
1699 init_err(SUBCLASS_NOT_FOUND_MSG, funcname, objp->name);
1700 return;
1703 err = ptree_create_node(objp->name, class_name[class],
1704 &objp->node);
1705 if (err != 0) {
1706 init_err(PTREE_CREATE_NODE_FAILED_MSG, funcname,
1707 picl_strerror(err));
1708 return;
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));
1725 return;
1728 cp = &class_properties[class];
1729 /* Locator LED Support */
1730 if (class == 2 && subclass == 2) {
1731 cp_count = 3;
1732 } else {
1733 cp_count = cp->count;
1736 for (j = 0; j < cp_count; ++j) {
1737 err = node_property(objp->node, psvc_read_volatile,
1738 psvc_write_volatile, cp->props[j].type,
1739 cp->props[j].size,
1740 cp->props[j].access, cp->props[j].name, 0);
1741 if (err != PSVC_SUCCESS) {
1742 init_err(NODE_PROP_FAILED_MSG, funcname,
1743 picl_strerror(err));
1744 return;
1748 /* Link the nodes into the PICL tree */
1749 *start = 0;
1750 if (start == buf) { /* no parent */
1751 parent_node = root_node;
1752 } else {
1753 err = ptree_get_node_by_path(buf, &parent_node);
1754 if (err != PICL_SUCCESS) {
1755 init_err(NODE_NOT_FOUND_MSG, funcname, buf);
1756 return;
1760 err = ptree_add_node(parent_node, objp->node);
1761 if (err != PICL_SUCCESS) {
1762 init_err(PTREE_ADD_NODE_FAILED_MSG, funcname,
1763 picl_strerror(err));
1764 return;
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)
1778 return;
1780 init_daemon();
1783 void
1784 psvc_plugin_fini(void)
1786 int32_t i;
1787 EInterval_t *ip, *next;
1789 fini_daemon();
1790 for (ip = first_interval; ip != 0; ip = next) {
1791 for (i = 0; i < ip->num_tasks; ++i) {
1792 (void) dlclose(ip->task_list[i].hdl);
1793 free(ip->task_list[i].obj_list);
1795 free(ip->task_list);
1796 next = ip->next;
1797 free(ip);
1799 free(prop_list);
1800 free(psvc_paths);
1801 free(psvc_hdl.objects);
1802 if (psvc_hdl.fp != NULL)
1803 (void) fclose(psvc_hdl.fp);
1804 psvc_fini(hdlp);
1807 void
1808 psvc_plugin_register(void)
1810 picld_plugin_register(&psvc_reg);