dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / picl / plugins / sun4u / psvc / psvcplugin / psvcplugin.c
blob861ff61e0a6cbabcbfdcf5142b759f943848ff61
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 if (first_interval == 0)
808 first_interval = ip;
809 else
810 prev->next = ip;
811 prev = ip;
813 ++intervals;
814 if (ip->interval == 0) {
815 run_policies(ip);
816 } else {
817 thread_setup(ip);
818 ++threads;
821 if (intervals == 0) {
822 if (debug_flag)
823 syslog(LOG_ERR, "ERROR: No policies started");
824 return;
827 if (status == -1) {
828 if (debug_flag)
829 syslog(LOG_ERR, "%s", strerror(errno));
830 return;
835 static int32_t count_records(FILE *fp, char *end, uint32_t *countp)
837 long first_record;
838 char *ret;
839 char buf[BUFSZ];
840 uint32_t count = 0;
842 first_record = ftell(fp);
844 while ((ret = fgets(buf, BUFSZ, fp)) != NULL) {
845 if (strncmp(end, buf, strlen(end)) == 0)
846 break;
847 ++count;
850 if (ret == NULL) {
851 errno = EINVAL;
852 return (-1);
855 (void) fseek(fp, first_record, SEEK_SET);
856 *countp = count;
857 return (0);
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.
865 static int32_t
866 find_file_section(FILE *fd, char *start)
868 char *ret;
869 char buf[BUFSZ];
870 char name[32];
871 int found;
873 (void) fseek(fd, 0, SEEK_SET);
874 while ((ret = fgets(buf, BUFSZ, fd)) != NULL) {
875 if (strncmp(start, buf, strlen(start)) == 0)
876 break;
879 if (ret == NULL) {
880 errno = EINVAL;
881 return (-1);
884 found = sscanf(buf, "%31s", name);
885 if (found != 1) {
886 errno = EINVAL;
887 return (-1);
888 } else {
889 return (0);
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;
916 int err;
918 propinfo.version = PSVC_PLUGIN_VERSION;
919 if (accessmode & PICL_VOLATILE) {
920 propinfo.read = read;
921 propinfo.write = write;
922 } else {
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);
932 if (err != 0) {
933 return (err);
936 err = ptree_add_prop(node, prophdl);
937 if (err != 0)
938 return (err);
940 return (0);
943 static void init_err(const char *fmt, char *arg1, char *arg2)
945 char msg[256];
947 (void) snprintf(msg, sizeof (msg), fmt, arg1, arg2);
948 syslog(LOG_ERR, "%s", msg);
951 static int
952 projected_lookup(picl_prophdl_t proph, struct proj_prop **dstp)
954 int i;
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;
971 int err;
973 err = projected_lookup(rarg->proph, &dstinfo);
974 if (err != 0) {
975 return (PICL_FAILURE);
979 err = ptree_get_propinfo(rarg->proph, &propinfo);
980 if (err != 0)
981 return (err);
982 err = ptree_get_propval_by_name(dstinfo->dst_node,
983 dstinfo->name, buf, propinfo.piclinfo.size);
984 if (err != 0)
985 return (err);
986 return (PICL_SUCCESS);
990 projected_write(ptree_warg_t *warg, const void *buf)
992 ptree_propinfo_t propinfo;
993 struct proj_prop *dstinfo;
994 int err;
996 err = projected_lookup(warg->proph, &dstinfo);
997 if (err != 0) {
998 return (PICL_FAILURE);
1001 err = ptree_get_propinfo(warg->proph, &propinfo);
1002 if (err != 0)
1003 return (err);
1004 err = ptree_update_propval_by_name(dstinfo->dst_node,
1005 dstinfo->name, buf, propinfo.piclinfo.size);
1006 if (err != 0)
1007 return (err);
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];
1016 int err, i;
1017 int32_t attr_num = -1;
1018 int32_t use_attr_num = 0;
1020 err = ptree_get_propval_by_name(rarg->nodeh, "name", name,
1021 sizeof (name));
1022 if (err != 0) {
1023 return (err);
1026 err = ptree_get_propval_by_name(rarg->nodeh, "_class", class,
1027 sizeof (class));
1028 if (err != 0) {
1029 return (err);
1032 err = ptree_get_propinfo(rarg->proph, &propinfo);
1033 if (err != 0) {
1034 return (err);
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)) {
1041 attr_num = i;
1042 break;
1046 if (attr_num == -1)
1047 for (i = 0; i < ATTR_STR_TAB_SIZE; i++) {
1048 if (strcmp(propinfo.piclinfo.name,
1049 attr_str_tab[i]) == 0) {
1050 attr_num = i;
1051 use_attr_num = 1;
1052 break;
1056 if (use_attr_num)
1057 err = psvc_get_attr(hdlp, name, attr_num, buf);
1058 else
1059 err = psvc_get_attr(hdlp, name,
1060 picl_prop_trans[attr_num].psvc_prop,
1061 buf);
1063 if (err != 0) {
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];
1074 int err, i;
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,
1082 sizeof (name));
1083 if (err != 0) {
1084 return (err);
1087 err = ptree_get_propval_by_name(warg->nodeh, "_class", class,
1088 sizeof (class));
1089 if (err != 0) {
1090 return (err);
1093 err = ptree_get_propinfo(warg->proph, &propinfo);
1094 if (err != 0) {
1095 return (err);
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)) {
1102 attr_num = i;
1103 break;
1107 if (attr_num == -1)
1108 for (i = 0; i < ATTR_STR_TAB_SIZE; i++) {
1109 if (strcmp(propinfo.piclinfo.name,
1110 attr_str_tab[i]) == 0) {
1111 attr_num = i;
1112 use_attr_num = 1;
1113 break;
1117 if (use_attr_num)
1118 err = psvc_set_attr(hdlp, name, attr_num, (void *)buf);
1119 else
1120 err = psvc_set_attr(hdlp, name,
1121 picl_prop_trans[attr_num].psvc_prop,
1122 (void *)buf);
1124 if (err != 0) {
1125 return (PICL_FAILURE);
1128 return (PICL_SUCCESS);
1131 void create_reference_properties(struct assoc_pair *assoc_tbl, int32_t count,
1132 char *assoc_name)
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;
1141 int32_t dependents;
1142 int32_t err;
1143 char class[PICL_CLASSNAMELEN_MAX];
1145 for (i = 0; i < count; ++i) {
1146 /* antecedent */
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);
1155 return;
1158 /* skip if table already created */
1159 if (ptree_get_propval_by_name(aobjp->node, assoc_name,
1160 &tbl_hdl, sizeof (tbl_hdl)) == 0) {
1161 continue;
1164 /* create a new table */
1165 err = ptree_create_table(&tbl_hdl);
1166 if (err != 0) {
1167 init_err(PTREE_CREATE_TABLE_FAILED_MSG,
1168 funcname, picl_strerror(err));
1169 return;
1172 err = node_property(aobjp->node, NULL, NULL,
1173 PICL_PTYPE_TABLE, sizeof (tbl_hdl), PICL_READ,
1174 assoc_name, &tbl_hdl);
1175 if (err != 0) {
1176 init_err(CREATE_PROP_FAILED_MSG, funcname,
1177 picl_strerror(err));
1178 return;
1181 /* determine number of elements in the table */
1182 dependents = 0;
1183 for (j = i; j < count; ++j) {
1184 if (strcmp(aobjp->name, assoc_tbl[j].antecedent) == 0)
1185 ++dependents;
1188 dep_list = (picl_nodehdl_t *)malloc(sizeof (picl_nodehdl_t) *
1189 dependents);
1190 if (dep_list == NULL) {
1191 init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1192 return;
1194 /* build row of reference properties */
1195 offset = 0;
1196 for (j = i; j < count; ++j) {
1197 if (strcmp(aobjp->name, assoc_tbl[j].antecedent) != 0)
1198 continue;
1200 dobjp = (picl_psvc_t *)bsearch(assoc_tbl[j].dependent,
1201 psvc_hdl.objects,
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);
1208 return;
1212 * Reference property name must be
1213 * _classname_propertyname
1215 err = ptree_get_propval_by_name(dobjp->node,
1216 "_class", class, sizeof (class));
1217 if (err != 0) {
1218 init_err(CLASS_NOT_FOUND_MSG, funcname,
1219 assoc_tbl[j].dependent);
1220 return;
1222 (void) snprintf(name, sizeof (name), "_%s_subclass",
1223 class);
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,
1234 dep_list + offset);
1235 if (err != 0) {
1236 init_err(PTREE_CREATE_PROP_FAILED_MSG,
1237 name, picl_strerror(err));
1238 return;
1241 ++offset;
1244 /* add row to table */
1245 err = ptree_add_row_to_table(tbl_hdl, dependents, dep_list);
1246 if (err != 0) {
1247 init_err(PTREE_ADD_ROW_FAILED_MSG, funcname,
1248 picl_strerror(err));
1249 return;
1257 /* Load projected properties */
1258 static void
1259 load_projected_properties(FILE *fp)
1261 int32_t found;
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;
1266 int err, i;
1267 picl_psvc_t *srcobjp, *dstobjp;
1268 char src[32], dst[256];
1269 char src_prop[32], dst_prop[32];
1270 char buf[BUFSZ];
1271 char *funcname = "load_projected_properties";
1273 if (find_file_section(fp, "PROJECTED_PROPERTIES") != 0)
1274 return;
1276 if (count_records(fp, "PROJECTED_PROPERTIES_END", &proj_prop_count) !=
1277 0) {
1278 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1279 return;
1282 prop_list = (struct proj_prop *)malloc(sizeof (struct proj_prop)
1283 * proj_prop_count);
1284 if (prop_list == NULL) {
1285 init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1286 return;
1289 for (i = 0; i < proj_prop_count; ++i) {
1290 buf[0] = '\0';
1291 (void) fgets(buf, BUFSZ, fp);
1292 found = sscanf(buf, "%31s %31s %255s %31s", src, src_prop, dst,
1293 dst_prop);
1294 if (found != 4) {
1295 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1296 return;
1299 /* find src node */
1300 if (src[0] == '/') {
1301 /* picl node name, outside psvc subtree */
1302 err = ptree_get_node_by_path(src, &src_node);
1303 if (err != 0) {
1304 init_err(NODE_NOT_FOUND_MSG, funcname, src);
1305 return;
1307 } else {
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);
1314 return;
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);
1323 if (err != 0) {
1324 init_err(NODE_NOT_FOUND_MSG, funcname, dst);
1325 return;
1327 prop_list[i].dst_node = dst_node;
1328 } else {
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);
1335 return;
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);
1343 while (err == 0) {
1344 err = ptree_get_propinfo(dst_prophdl, &dstinfo);
1345 if (err != 0)
1346 break;
1347 if (strcmp(dst_prop, dstinfo.piclinfo.name) == 0)
1348 break;
1349 err = ptree_get_next_prop(dst_prophdl, &dst_prophdl);
1351 if (err != 0) {
1352 init_err(SIZE_NOT_FOUND_MSG, funcname, dst_prop);
1353 return;
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);
1366 if (err != 0) {
1367 init_err(PTREE_CREATE_PROP_FAILED_MSG, funcname,
1368 picl_strerror(err));
1369 return;
1372 err = ptree_add_prop(src_node, src_prophdl);
1373 if (err != 0) {
1374 init_err(PTREE_ADD_PROP_FAILED_MSG, funcname,
1375 picl_strerror(err));
1376 return;
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";
1389 uint32_t count;
1390 int found;
1391 int j;
1392 char assoc_name[32];
1393 struct assoc_pair *assoc_tbl;
1394 char name1[32];
1395 char buf[BUFSZ];
1398 * ignore count in the file, correct count is highest
1399 * association id + 1, now figured when loading ASSOC_STR
1400 * section.
1402 if (find_file_section(fp, "ASSOCIATIONS") != 0)
1403 return;
1405 buf[0] = '\0';
1406 (void) fgets(buf, BUFSZ, fp);
1407 while (strncmp("ASSOCIATIONS_END", buf, 16) != 0) {
1408 found = sscanf(buf, "%31s %31s", name1, assoc_name);
1409 if (found != 2) {
1410 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1411 return;
1414 if (count_records(fp, "ASSOCIATION_END", &count) != 0) {
1415 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1416 return;
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));
1423 return;
1426 for (j = 0; j < count; ++j) {
1427 buf[0] = '\0';
1428 (void) fgets(buf, BUFSZ, fp);
1429 found = sscanf(buf, "%31s %31s",
1430 assoc_tbl[j].antecedent, assoc_tbl[j].dependent);
1431 if (found != 2) {
1432 init_err(INVALID_FILE_FORMAT_MSG, funcname,
1434 return;
1438 buf[0] = '\0';
1439 (void) fgets(buf, BUFSZ, fp);
1440 if (strncmp(buf, "ASSOCIATION_END", 15) != 0) {
1441 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1442 return;
1445 /* Create separate list of dependents for each antecedent */
1446 if (strcmp(assoc_name, "PSVC_TABLE") != 0) {
1447 create_reference_properties(assoc_tbl, count,
1448 assoc_name);
1451 free(assoc_tbl);
1452 buf[0] = '\0';
1453 (void) fgets(buf, BUFSZ, fp);
1458 /* Enviornmental Lock Object's Read and Write routine */
1459 /* ARGSUSED */
1460 static int
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);
1467 /* ARGSUSED */
1468 static int
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)) {
1480 errno = EINVAL;
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);
1493 if (status == -1) {
1494 syslog(LOG_ERR, SEM_WAIT_FAILED_MSG);
1496 return (status);
1500 * If the state is Running we must go into timed_lock_wait to aquire
1501 * the env_lock.
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);
1506 if (status == -1) {
1507 syslog(LOG_ERR, SEM_WAIT_FAILED_MSG);
1509 return (status);
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
1517 * enabled.
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;
1524 /* stop timer */
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;
1532 /* restart timer */
1533 (void) pthread_cond_signal(&timer_cond);
1535 (void) pthread_mutex_unlock(&timer_mutex);
1536 } else {
1537 (void) strlcpy(env_lock_state, var, LOCK_STRING_MAX);
1540 (void) pthread_mutex_unlock(&env_lock_mutex);
1541 return (PSVC_SUCCESS);
1544 static int
1545 init_env_lock_node(picl_nodehdl_t root_node)
1547 int err;
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));
1556 return (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));
1564 return (err);
1567 err = ptree_create_and_add_prop(lock_node, &propinfo,
1568 NULL, NULL);
1569 if (err != PICL_SUCCESS) {
1570 init_err(PTREE_ADD_PROP_FAILED_MSG, funcname,
1571 picl_strerror(err));
1572 return (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));
1579 return (err);
1582 return (PSVC_SUCCESS);
1585 void
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";
1592 char platform[32];
1593 char filename[256];
1594 char buf[BUFSZ];
1595 int32_t i, j;
1596 int err, found;
1598 psvc_paths = NULL;
1599 psvc_hdl.obj_count = 0;
1600 psvc_hdl.objects = NULL;
1601 psvc_hdl.fp = NULL;
1602 first_interval = NULL;
1605 * So the volatile read/write routines can retrieve data from
1606 * psvc or picl
1608 err = psvc_init(&hdlp);
1609 if (err != 0) {
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);
1615 return;
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);
1622 return;
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);
1628 return;
1630 if (count_records(psvc_hdl.fp, "OBJECT_INFO_END", &psvc_hdl.obj_count)
1631 == -1) {
1632 init_err(INVALID_FILE_FORMAT1_MSG, funcname, filename);
1633 return;
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));
1638 return;
1640 (void) memset(psvc_hdl.objects, 0,
1641 sizeof (picl_psvc_t) * psvc_hdl.obj_count);
1643 err = ptree_get_root(&root_node);
1644 if (err != 0) {
1645 init_err(PTREE_GET_ROOT_FAILED_MSG, funcname,
1646 picl_strerror(err));
1647 return;
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));
1656 return;
1658 for (i = 0; i < psvc_hdl.obj_count; ++i) {
1659 char *start;
1660 int32_t class;
1661 int32_t subclass;
1662 int32_t cp_count;
1663 picl_psvc_t *objp = &psvc_hdl.objects[i];
1664 buf[0] = '\0';
1665 (void) fgets(buf, BUFSZ, psvc_hdl.fp);
1666 if (strncmp(buf, "OBJECT_INFO_END", 15) == 0)
1667 break;
1669 start = strrchr(buf, '/');
1670 if (start == NULL) {
1671 init_err(INVALID_FILE_FORMAT1_MSG, funcname,
1672 filename);
1673 return;
1675 found = sscanf(start + 1, "%31s", objp->name);
1676 if (found != 1) {
1677 init_err(INVALID_FILE_FORMAT1_MSG, funcname,
1678 filename);
1679 return;
1682 /* get class */
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);
1686 return;
1688 if (class > NUM_CLASSES) {
1689 init_err(UNKNOWN_CLASS_MSG, funcname, 0);
1690 return;
1693 err = psvc_get_attr(hdlp, objp->name, PSVC_SUBCLASS_ATTR,
1694 &subclass);
1695 if (err != PSVC_SUCCESS) {
1696 init_err(SUBCLASS_NOT_FOUND_MSG, funcname, objp->name);
1697 return;
1700 err = ptree_create_node(objp->name, class_name[class],
1701 &objp->node);
1702 if (err != 0) {
1703 init_err(PTREE_CREATE_NODE_FAILED_MSG, funcname,
1704 picl_strerror(err));
1705 return;
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));
1722 return;
1725 cp = &class_properties[class];
1726 /* Locator LED Support */
1727 if (class == 2 && subclass == 2) {
1728 cp_count = 3;
1729 } else {
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,
1736 cp->props[j].size,
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));
1741 return;
1745 /* Link the nodes into the PICL tree */
1746 *start = 0;
1747 if (start == buf) { /* no parent */
1748 parent_node = root_node;
1749 } else {
1750 err = ptree_get_node_by_path(buf, &parent_node);
1751 if (err != PICL_SUCCESS) {
1752 init_err(NODE_NOT_FOUND_MSG, funcname, buf);
1753 return;
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));
1761 return;
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)
1775 return;
1777 init_daemon();
1780 void
1781 psvc_plugin_fini(void)
1783 int32_t i;
1784 EInterval_t *ip, *next;
1786 fini_daemon();
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);
1793 next = ip->next;
1794 free(ip);
1796 free(prop_list);
1797 free(psvc_paths);
1798 free(psvc_hdl.objects);
1799 if (psvc_hdl.fp != NULL)
1800 (void) fclose(psvc_hdl.fp);
1801 psvc_fini(hdlp);
1804 void
1805 psvc_plugin_register(void)
1807 picld_plugin_register(&psvc_reg);