1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
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,<>.
30 */
31
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>
54
55 #define BUFSZ 512
56
57 typedef struct {
58 char name[32];
59 } EName_t;
60
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;
68
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;
77
78 static EInterval_t *first_interval;
79
80 static psvc_opaque_t hdlp;
81
82 sem_t timer_sem;
83 pthread_mutex_t timer_mutex;
84 pthread_cond_t timer_cond;
85 pthread_t timer_thread_id;
86
87 extern int ptree_get_node_by_path(const char *, picl_nodehdl_t *);
88
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
95
96 int timer_state = NOT_READY;
97
98 int app_timeout;
99
100 /* Lock State Loop State Definitions */
101 #define STATE_CHANGED 1
102 #define STATE_NOT_CHANGED 0
103
104 #ifdef DEBUG
105 static int32_t debug_flag = 1;
106 #else
107 static int32_t debug_flag = 0;
108 #endif
109
110 static char library[PATH_MAX];
111
112 #define PSVC_PLUGIN_VERSION PICLD_PLUGIN_VERSION_1
113
114 #pragma init(psvc_plugin_register) /* place in .init section */
115
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;
122
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")
153
154 #define LOCK_STRING_MAX 32
155
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;
160
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"
174 };
175 #define NUM_CLASSES (sizeof (class_name) / sizeof (char *))
176
177 struct proj_prop { /* projected property */
178 picl_prophdl_t handle;
179 picl_nodehdl_t dst_node;
180 char name[32];
181 };
182
183 struct propinfo {
184 char *name;
185 uint32_t type;
186 uint32_t size;
187 uint32_t access;
188 };
189
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}
195 };
196 #define COMMON_COUNT (sizeof (common) / sizeof (struct propinfo))
197
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}
202 };
203 /*
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.
207 */
208 #define LED_COUNT 1
209
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}
216 };
217 #define TEMP_SENSOR_COUNT \
218 (sizeof (temperature_sensor_properties) / sizeof (struct propinfo))
219
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}
226 };
227 #define DIGI_SENSOR_COUNT \
228 (sizeof (digi_sensor_properties) / sizeof (struct propinfo))
229
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}
234 };
235 #define BOOLGPIO_COUNT (sizeof (boolgpio_properties) / sizeof (struct propinfo))
236
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}
241 };
242 #define GPIO8_COUNT (sizeof (gpio8_properties) / sizeof (struct propinfo))
243
244 struct propinfo digictrl_properties[] = {
245 {"DtoAControlValue", PICL_PTYPE_INT, 4,
246 PICL_READ | PICL_WRITE | PICL_VOLATILE},
247 };
248 #define DIGICTRL_COUNT (sizeof (digictrl_properties) / sizeof (struct propinfo))
249
250 struct classinfo {
251 struct propinfo *props;
252 int32_t count;
253 } class_properties[] =
254 {
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},
267 };
268
269 struct prop_trans {
270 char *picl_class;
271 char *picl_prop;
272 int32_t psvc_prop;
273 } picl_prop_trans[] =
274 {
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}
296 };
297
298 #define PICL_PROP_TRANS_COUNT \
299 (sizeof (picl_prop_trans) / sizeof (struct prop_trans))
300
301
302 typedef struct {
303 char name[32];
304 picl_nodehdl_t node;
305 } picl_psvc_t;
306
307 struct assoc_pair {
308 char antecedent[32];
309 char dependent[32];
310 };
311
312 struct handle {
313 uint32_t obj_count;
314 picl_psvc_t *objects;
315 FILE *fp;
316 } psvc_hdl;
317
318 struct proj_prop *prop_list;
319 uint32_t proj_prop_count;
320
321 int psvc_picl_nodes;
322
323 void psvc_plugin_init(void);
324 void psvc_plugin_fini(void);
325
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
332 };
333
334 /*
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.
340 */
341 void
psvcplugin_add_children(char * parent_path)342 psvcplugin_add_children(char *parent_path)
343 {
344 int i;
345 picl_nodehdl_t parent_node;
346 char next_path[256];
347
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);
355 }
356 }
357 }
358
359 void
psvcplugin_lookup(char * name,char * parent,picl_nodehdl_t * node)360 psvcplugin_lookup(char *name, char *parent, picl_nodehdl_t *node)
361 {
362 int i;
363
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;
368 }
369 }
370 }
371
372 void
timer_thread(void)373 timer_thread(void)
374 {
375 struct timespec timeout;
376 int status;
377
378
379 status = pthread_mutex_lock(&timer_mutex);
380 if (status != 0) {
381 syslog(LOG_ERR, MUTEX_LOCK_FAILED_MSG, strerror(status));
382 }
383
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);
390
391 if (timer_state == TIMER_SHUTDOWN) {
392 pthread_exit(NULL);
393 /* not reached */
394 }
395
396 if (status != 0) {
397 syslog(LOG_ERR, CV_WAIT_FAILED_MSG, strerror(status));
398 }
399
400 /*
401 * Will get signalled after semaphore acquired,
402 * or when timeout occurs.
403 */
404 (void) clock_gettime(CLOCK_REALTIME, &timeout);
405 timeout.tv_sec += app_timeout;
406
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);
413 }
414
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));
425 }
426 }
427 }
428 }
429
430 static int
lock_state_loop(char * set_lock_state)431 lock_state_loop(char *set_lock_state)
432 {
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);
438 }
439 (void) pthread_mutex_unlock(&env_lock_mutex);
440 return (STATE_CHANGED);
441 }
442
timed_lock_wait(char * set_lock_state)443 static int timed_lock_wait(char *set_lock_state)
444 {
445 int32_t status;
446
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);
453
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);
460
461 /*
462 * We now spin checking the state env_lock_state for it to change to
463 * enabled.
464 */
465 while (lock_state_loop(set_lock_state))
466 (void) sleep(1);
467
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 */
472 }
473 if (timer_state == HAVE_REQUEST) { /* cancel request */
474 timer_state = NOT_READY;
475 }
476 (void) pthread_mutex_unlock(&timer_mutex);
477 (void) sem_post(&timer_sem);
478 return (0);
479 }
480
lock_and_run(ETask_t * tp,int32_t obj_num)481 static void lock_and_run(ETask_t *tp, int32_t obj_num)
482 {
483 int32_t status;
484
485 /* Grab mutex to stop the env_lock from being changed. */
486 (void) pthread_mutex_lock(&env_lock_mutex);
487 /*
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.
491 */
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);
498 }
499 } else {
500 (void) strlcpy(env_lock_state, PSVC_LOCK_RUNNING,
501 LOCK_STRING_MAX);
502 (void) pthread_mutex_unlock(&env_lock_mutex);
503 }
504 status = (*tp->funcp)(hdlp, (tp->obj_list + obj_num)->name);
505 if (status == PSVC_FAILURE && errno != ENODEV) {
506 char dev_name[32];
507
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));
513 }
514
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);
519 }
520
521 static void *
run_policies(void * ptr)522 run_policies(void *ptr)
523 {
524 EInterval_t *ip = ptr;
525 ETask_t *tp;
526 int32_t i, j;
527
528 do {
529 if (ip->interval) {
530 int remaining = ip->interval;
531 do {
532 /* check to see if we've been told to exit */
533 if (ip->has_thread && (ip->interval == 0))
534 break;
535 remaining = sleep(remaining);
536 } while (remaining > 0);
537 }
538 for (i = 0; i < ip->num_tasks; ++i) {
539 tp = &ip->task_list[i];
540 for (j = 0; j < tp->num_objects; ++j) {
541 /* check to see if we've been told to exit */
542 if (ip->has_thread && (ip->interval == 0))
543 break;
544 lock_and_run(tp, j);
545 }
546 if (ip->has_thread && (ip->interval == 0))
547 break;
548 }
549 } while (ip->interval);
550
551 return (NULL);
552 }
553
thread_setup(EInterval_t * ip)554 static void thread_setup(EInterval_t *ip)
555 {
556 int32_t status;
557
558 status = pthread_create(&ip->thread, NULL, run_policies, ip);
559 if (status != 0) {
560 if (debug_flag)
561 syslog(LOG_ERR, "%s", strerror(errno));
562 exit(-1);
563 }
564 ip->has_thread = 1;
565 }
566
load_policy(const char * library,ETask_t * tp)567 static int32_t load_policy(const char *library, ETask_t *tp)
568 {
569 tp->hdl = dlopen(library, RTLD_NOW | RTLD_GLOBAL);
570 if (tp->hdl == NULL) {
571 if (debug_flag) {
572 char *errstr = dlerror();
573 syslog(LOG_ERR, "%s", errstr);
574 }
575 exit(1);
576 }
577 tp->funcp = (int32_t (*)(void *, char *))dlsym(tp->hdl, tp->routine);
578 if (tp->funcp == NULL) {
579 if (debug_flag) {
580 char *errstr = dlerror();
581 syslog(LOG_ERR, "%s", errstr);
582 }
583 exit(1);
584 }
585 return (0);
586 }
587
get_timeout(FILE * fp,int * timeout)588 static int32_t get_timeout(FILE *fp, int *timeout)
589 {
590 char buf[BUFSZ];
591 char name[32];
592 char *cp;
593
594 /* skip blank lines */
595 do {
596 cp = fgets(buf, BUFSZ, fp);
597 if (cp == NULL)
598 return (1);
599 while (isspace(*cp))
600 ++cp;
601 (void) sscanf(buf, "%31s %d", name, timeout);
602 } while (*cp == 0 || *cp == '\n' || strcmp(name, "TIMEOUT") != 0);
603
604 if (strcmp(name, "TIMEOUT") != 0) {
605 errno = EINVAL;
606 return (-1);
607 }
608 return (0);
609
610 }
611
load_interval(FILE * fp,EInterval_t ** ipp)612 static int32_t load_interval(FILE *fp, EInterval_t **ipp)
613 {
614 char buf[BUFSZ];
615 int32_t found;
616 EInterval_t *ip;
617 ETask_t *tp;
618 int32_t tasks;
619 int32_t status, i, j;
620 int32_t interval;
621 char name[32];
622 char *cp;
623
624 /* skip blank lines */
625 do {
626 cp = fgets(buf, BUFSZ, fp);
627 if (cp == NULL)
628 return (1);
629 while (isspace(*cp))
630 ++cp;
631 } while (*cp == 0 || *cp == '\n');
632 found = sscanf(buf, "%31s %d %d", name, &interval, &tasks);
633 if (found != 3) {
634 errno = EINVAL;
635 return (-1);
636 }
637
638 if (strcmp(name, "INTERVAL") != 0) {
639 errno = EINVAL;
640 return (-1);
641 }
642
643 ip = (EInterval_t *)malloc(sizeof (EInterval_t));
644 if (ip == NULL)
645 return (-1);
646 ip->num_tasks = tasks;
647 ip->interval = interval;
648 ip->next = NULL;
649 ip->has_thread = 0;
650
651 /* allocate and load table */
652 ip->task_list = (ETask_t *)malloc(ip->num_tasks * sizeof (ETask_t));
653 if (ip->task_list == NULL)
654 return (-1);
655 for (i = 0; i < ip->num_tasks; ++i) {
656 tp = &ip->task_list[i];
657
658 (void) fgets(buf, BUFSZ, fp);
659 found = sscanf(buf, "%31s %1023s %63s",
660 name, library, tp->routine);
661 if (found != 3) {
662 errno = EINVAL;
663 return (-1);
664 }
665
666 status = load_policy(library, tp);
667 if (status == -1)
668 return (-1);
669 found = fscanf(fp, "%d", &tp->num_objects);
670 if (found != 1) {
671 if (debug_flag)
672 syslog(LOG_ERR, "No list of objects for task");
673 errno = EINVAL;
674 return (-1);
675 }
676 tp->obj_list =
677 (EName_t *)malloc(tp->num_objects * sizeof (EName_t));
678 if (tp->obj_list == NULL)
679 return (-1);
680
681 for (j = 0; j < tp->num_objects; ++j) {
682 found = fscanf(fp, "%31s", (char *)(tp->obj_list + j));
683 if (found != 1) {
684 if (debug_flag)
685 syslog(LOG_ERR,
686 "Wrong number of objects for task");
687 errno = EINVAL;
688 return (-1);
689 }
690 }
691 (void) fgets(buf, BUFSZ, fp); /* reads newline on data line */
692 (void) fgets(buf, BUFSZ, fp);
693 if (strncmp(buf, "TASK_END", 8) != 0) {
694 if (debug_flag)
695 syslog(LOG_ERR, "Expected TASK_END, task %s",
696 tp->routine);
697 errno = EINVAL;
698 return (-1);
699 }
700 }
701
702 (void) fgets(buf, BUFSZ, fp);
703 if (strncmp(buf, "INTERVAL_END", 12) != 0) {
704 if (debug_flag)
705 syslog(LOG_ERR, "Expected INTERVAL_END");
706 errno = EINVAL;
707 return (-1);
708 }
709
710 *ipp = ip;
711 return (0);
712 }
713
714 void
fini_daemon(void)715 fini_daemon(void)
716 {
717 EInterval_t *ip;
718
719 /* shut down the threads running the policies */
720 for (ip = first_interval; ip != NULL; ip = ip->next) {
721 if (ip->has_thread) {
722 /*
723 * there is a thread for this interval; tell it to stop
724 * by clearing the interval
725 */
726 ip->interval = 0;
727 }
728 }
729 for (ip = first_interval; ip != NULL; ip = ip->next) {
730 if (ip->has_thread) {
731 (void) pthread_join(ip->thread, NULL);
732 }
733 }
734 /* shut down the timer thread */
735 while (timer_state != READY)
736 (void) sched_yield();
737 (void) pthread_mutex_lock(&timer_mutex);
738 timer_state = TIMER_SHUTDOWN;
739 (void) pthread_cond_signal(&timer_cond);
740 (void) pthread_mutex_unlock(&timer_mutex);
741 (void) pthread_join(timer_thread_id, NULL);
742 (void) pthread_mutex_destroy(&env_lock_mutex);
743 (void) pthread_mutex_destroy(&timer_mutex);
744 (void) pthread_cond_destroy(&timer_cond);
745 (void) sem_destroy(&timer_sem);
746 }
747
748 void
init_daemon(void)749 init_daemon(void)
750 {
751 int32_t intervals = 0;
752 int32_t threads = 0;
753 int32_t status;
754 FILE *fp;
755 char filename[PATH_MAX];
756 char platform[64];
757 EInterval_t *ip, *prev;
758
759 if (sysinfo(SI_PLATFORM, platform, sizeof (platform)) == -1) {
760 if (debug_flag)
761 syslog(LOG_ERR, "%s", strerror(errno));
762 return;
763 }
764
765 (void) snprintf(filename, sizeof (filename),
766 "/usr/platform/%s/lib/platsvcd.conf", platform);
767 if ((fp = fopen(filename, "r")) == NULL) {
768 if (debug_flag)
769 syslog(LOG_ERR, "%s", strerror(errno));
770 return;
771 }
772
773 status = get_timeout(fp, &app_timeout);
774 if (status != 0) {
775 if (debug_flag)
776 syslog(LOG_ERR, "%s", strerror(errno));
777 return;
778 }
779
780 status = sem_init(&timer_sem, 0, 1);
781 if (status == -1) {
782 if (debug_flag)
783 syslog(LOG_ERR, "%s", strerror(errno));
784 return;
785 }
786
787 (void) strlcpy(env_lock_state, PSVC_LOCK_ENABLED, LOCK_STRING_MAX);
788 (void) pthread_mutex_init(&env_lock_mutex, NULL);
789 (void) pthread_mutex_init(&timer_mutex, NULL);
790 (void) pthread_cond_init(&timer_cond, NULL);
791
792 timer_state = NOT_READY;
793 status = pthread_create(&timer_thread_id, NULL,
794 (void *(*)())timer_thread, 0);
795 if (status != 0) {
796 if (debug_flag)
797 syslog(LOG_ERR, "%s", strerror(errno));
798 return;
799 }
800
801 /* get timer thread running */
802 while (timer_state != READY)
803 (void) sched_yield();
804
805 for (;;) {
806 status = load_interval(fp, &ip);
807 if (status != 0)
808 break;
809
810 #ifdef lint
811 prev = NULL;
812 #endif
813 if (first_interval == 0)
814 first_interval = ip;
815 else
816 prev->next = ip;
817 prev = ip;
818
819 ++intervals;
820 if (ip->interval == 0) {
821 run_policies(ip);
822 } else {
823 thread_setup(ip);
824 ++threads;
825 }
826 }
827 if (intervals == 0) {
828 if (debug_flag)
829 syslog(LOG_ERR, "ERROR: No policies started");
830 return;
831 }
832
833 if (status == -1) {
834 if (debug_flag)
835 syslog(LOG_ERR, "%s", strerror(errno));
836 return;
837 }
838 }
839
840
count_records(FILE * fp,char * end,uint32_t * countp)841 static int32_t count_records(FILE *fp, char *end, uint32_t *countp)
842 {
843 long first_record;
844 char *ret;
845 char buf[BUFSZ];
846 uint32_t count = 0;
847
848 first_record = ftell(fp);
849
850 while ((ret = fgets(buf, BUFSZ, fp)) != NULL) {
851 if (strncmp(end, buf, strlen(end)) == 0)
852 break;
853 ++count;
854 }
855
856 if (ret == NULL) {
857 errno = EINVAL;
858 return (-1);
859 }
860
861 (void) fseek(fp, first_record, SEEK_SET);
862 *countp = count;
863 return (0);
864 }
865
866 /*
867 * Find start of a section within the config file,
868 * Returns number of records in the section.
869 * FILE *fd is set to first data record within section.
870 */
871 static int32_t
find_file_section(FILE * fd,char * start)872 find_file_section(FILE *fd, char *start)
873 {
874 char *ret;
875 char buf[BUFSZ];
876 char name[32];
877 int found;
878
879 (void) fseek(fd, 0, SEEK_SET);
880 while ((ret = fgets(buf, BUFSZ, fd)) != NULL) {
881 if (strncmp(start, buf, strlen(start)) == 0)
882 break;
883 }
884
885 if (ret == NULL) {
886 errno = EINVAL;
887 return (-1);
888 }
889
890 found = sscanf(buf, "%31s", name);
891 if (found != 1) {
892 errno = EINVAL;
893 return (-1);
894 } else {
895 return (0);
896 }
897
898 }
899
name_compare_qsort(picl_psvc_t * s1,picl_psvc_t * s2)900 static int32_t name_compare_qsort(picl_psvc_t *s1, picl_psvc_t *s2)
901 {
902 return (strcmp(s1->name, s2->name));
903 }
904
name_compare_bsearch(char * s1,picl_psvc_t * s2)905 static int32_t name_compare_bsearch(char *s1, picl_psvc_t *s2)
906 {
907 return (strcmp(s1, s2->name));
908 }
909
910 /*
911 * Create a property and add it to the specified node.
912 * PICL will take a segmentation violation if a volatile property
913 * has a non-zero size.
914 */
node_property(picl_nodehdl_t node,int (* read)(ptree_rarg_t *,void *),int (* write)(ptree_warg_t *,const void *),picl_prop_type_t type,unsigned int size,unsigned int accessmode,char * name,void * value)915 static int32_t node_property(picl_nodehdl_t node,
916 int (*read)(ptree_rarg_t *, void *),
917 int (*write)(ptree_warg_t *, const void *), picl_prop_type_t type,
918 unsigned int size, unsigned int accessmode, char *name, void *value)
919 {
920 ptree_propinfo_t propinfo;
921 picl_prophdl_t prophdl;
922 int err;
923
924 propinfo.version = PSVC_PLUGIN_VERSION;
925 if (accessmode & PICL_VOLATILE) {
926 propinfo.read = read;
927 propinfo.write = write;
928 } else {
929 propinfo.read = NULL;
930 propinfo.write = NULL;
931 }
932 propinfo.piclinfo.type = type;
933 propinfo.piclinfo.accessmode = accessmode;
934 propinfo.piclinfo.size = size;
935 (void) strcpy(propinfo.piclinfo.name, name);
936
937 err = ptree_create_prop(&propinfo, value, &prophdl);
938 if (err != 0) {
939 return (err);
940 }
941
942 err = ptree_add_prop(node, prophdl);
943 if (err != 0)
944 return (err);
945
946 return (0);
947 }
948
init_err(const char * fmt,char * arg1,char * arg2)949 static void init_err(const char *fmt, char *arg1, char *arg2)
950 {
951 char msg[256];
952
953 (void) snprintf(msg, sizeof (msg), fmt, arg1, arg2);
954 syslog(LOG_ERR, "%s", msg);
955 }
956
957 static int
projected_lookup(picl_prophdl_t proph,struct proj_prop ** dstp)958 projected_lookup(picl_prophdl_t proph, struct proj_prop **dstp)
959 {
960 int i;
961
962 for (i = 0; i < proj_prop_count; ++i) {
963 if (prop_list[i].handle == proph) {
964 *dstp = &prop_list[i];
965 return (PICL_SUCCESS);
966 }
967 }
968
969 return (PICL_INVALIDHANDLE);
970 }
971
972 int
projected_read(ptree_rarg_t * rarg,void * buf)973 projected_read(ptree_rarg_t *rarg, void *buf)
974 {
975 ptree_propinfo_t propinfo;
976 struct proj_prop *dstinfo;
977 int err;
978
979 err = projected_lookup(rarg->proph, &dstinfo);
980 if (err != 0) {
981 return (PICL_FAILURE);
982 }
983
984
985 err = ptree_get_propinfo(rarg->proph, &propinfo);
986 if (err != 0)
987 return (err);
988 err = ptree_get_propval_by_name(dstinfo->dst_node,
989 dstinfo->name, buf, propinfo.piclinfo.size);
990 if (err != 0)
991 return (err);
992 return (PICL_SUCCESS);
993 }
994
995 int
projected_write(ptree_warg_t * warg,const void * buf)996 projected_write(ptree_warg_t *warg, const void *buf)
997 {
998 ptree_propinfo_t propinfo;
999 struct proj_prop *dstinfo;
1000 int err;
1001
1002 err = projected_lookup(warg->proph, &dstinfo);
1003 if (err != 0) {
1004 return (PICL_FAILURE);
1005 }
1006
1007 err = ptree_get_propinfo(warg->proph, &propinfo);
1008 if (err != 0)
1009 return (err);
1010 err = ptree_update_propval_by_name(dstinfo->dst_node,
1011 dstinfo->name, buf, propinfo.piclinfo.size);
1012 if (err != 0)
1013 return (err);
1014 return (PICL_SUCCESS);
1015 }
1016
1017 int
psvc_read_volatile(ptree_rarg_t * rarg,void * buf)1018 psvc_read_volatile(ptree_rarg_t *rarg, void *buf)
1019 {
1020 ptree_propinfo_t propinfo;
1021 char name[32], class[32];
1022 int err, i;
1023 int32_t attr_num = -1;
1024 int32_t use_attr_num = 0;
1025
1026 err = ptree_get_propval_by_name(rarg->nodeh, "name", name,
1027 sizeof (name));
1028 if (err != 0) {
1029 return (err);
1030 }
1031
1032 err = ptree_get_propval_by_name(rarg->nodeh, "_class", class,
1033 sizeof (class));
1034 if (err != 0) {
1035 return (err);
1036 }
1037
1038 err = ptree_get_propinfo(rarg->proph, &propinfo);
1039 if (err != 0) {
1040 return (err);
1041 }
1042
1043 for (i = 0; i < PICL_PROP_TRANS_COUNT; i++) {
1044 if ((strcmp(class, picl_prop_trans[i].picl_class) == 0) &&
1045 (strcmp(propinfo.piclinfo.name,
1046 picl_prop_trans[i].picl_prop) == 0)) {
1047 attr_num = i;
1048 break;
1049 }
1050 }
1051
1052 if (attr_num == -1)
1053 for (i = 0; i < ATTR_STR_TAB_SIZE; i++) {
1054 if (strcmp(propinfo.piclinfo.name,
1055 attr_str_tab[i]) == 0) {
1056 attr_num = i;
1057 use_attr_num = 1;
1058 break;
1059 }
1060 }
1061
1062 if (use_attr_num)
1063 err = psvc_get_attr(hdlp, name, attr_num, buf);
1064 else
1065 err = psvc_get_attr(hdlp, name,
1066 picl_prop_trans[attr_num].psvc_prop,
1067 buf);
1068
1069 if (err != 0) {
1070 return (PICL_FAILURE);
1071 }
1072 return (PICL_SUCCESS);
1073 }
1074
1075 int
psvc_write_volatile(ptree_warg_t * warg,const void * buf)1076 psvc_write_volatile(ptree_warg_t *warg, const void *buf)
1077 {
1078 ptree_propinfo_t propinfo;
1079 char name[32], class[32];
1080 int err, i;
1081 int32_t attr_num = -1;
1082 int32_t use_attr_num = 0;
1083
1084 if (warg->cred.dc_euid != 0)
1085 return (PICL_PERMDENIED);
1086
1087 err = ptree_get_propval_by_name(warg->nodeh, "name", name,
1088 sizeof (name));
1089 if (err != 0) {
1090 return (err);
1091 }
1092
1093 err = ptree_get_propval_by_name(warg->nodeh, "_class", class,
1094 sizeof (class));
1095 if (err != 0) {
1096 return (err);
1097 }
1098
1099 err = ptree_get_propinfo(warg->proph, &propinfo);
1100 if (err != 0) {
1101 return (err);
1102 }
1103
1104 for (i = 0; i < PICL_PROP_TRANS_COUNT; i++) {
1105 if ((strcmp(class, picl_prop_trans[i].picl_class) == 0) &&
1106 (strcmp(propinfo.piclinfo.name,
1107 picl_prop_trans[i].picl_prop) == 0)) {
1108 attr_num = i;
1109 break;
1110 }
1111 }
1112
1113 if (attr_num == -1)
1114 for (i = 0; i < ATTR_STR_TAB_SIZE; i++) {
1115 if (strcmp(propinfo.piclinfo.name,
1116 attr_str_tab[i]) == 0) {
1117 attr_num = i;
1118 use_attr_num = 1;
1119 break;
1120 }
1121 }
1122
1123 if (use_attr_num)
1124 err = psvc_set_attr(hdlp, name, attr_num, (void *)buf);
1125 else
1126 err = psvc_set_attr(hdlp, name,
1127 picl_prop_trans[attr_num].psvc_prop,
1128 (void *)buf);
1129
1130 if (err != 0) {
1131 return (PICL_FAILURE);
1132 }
1133
1134 return (PICL_SUCCESS);
1135 }
1136
create_reference_properties(struct assoc_pair * assoc_tbl,int32_t count,char * assoc_name)1137 void create_reference_properties(struct assoc_pair *assoc_tbl, int32_t count,
1138 char *assoc_name)
1139 {
1140 picl_psvc_t *aobjp, *dobjp;
1141 picl_prophdl_t tbl_hdl;
1142 picl_nodehdl_t *dep_list;
1143 ptree_propinfo_t propinfo;
1144 char *funcname = "create_reference_properties";
1145 char name[PICL_PROPNAMELEN_MAX];
1146 int32_t i, j, offset;
1147 int32_t dependents;
1148 int32_t err;
1149 char class[PICL_CLASSNAMELEN_MAX];
1150
1151 for (i = 0; i < count; ++i) {
1152 /* antecedent */
1153 aobjp = (picl_psvc_t *)bsearch(assoc_tbl[i].antecedent,
1154 psvc_hdl.objects, psvc_hdl.obj_count,
1155 sizeof (picl_psvc_t),
1156 (int (*)(const void *, const void *))
1157 name_compare_bsearch);
1158 if (aobjp == NULL) {
1159 init_err(ID_NOT_FOUND_MSG,
1160 funcname, assoc_tbl[i].antecedent);
1161 return;
1162 }
1163
1164 /* skip if table already created */
1165 if (ptree_get_propval_by_name(aobjp->node, assoc_name,
1166 &tbl_hdl, sizeof (tbl_hdl)) == 0) {
1167 continue;
1168 }
1169
1170 /* create a new table */
1171 err = ptree_create_table(&tbl_hdl);
1172 if (err != 0) {
1173 init_err(PTREE_CREATE_TABLE_FAILED_MSG,
1174 funcname, picl_strerror(err));
1175 return;
1176 }
1177
1178 err = node_property(aobjp->node, NULL, NULL,
1179 PICL_PTYPE_TABLE, sizeof (tbl_hdl), PICL_READ,
1180 assoc_name, &tbl_hdl);
1181 if (err != 0) {
1182 init_err(CREATE_PROP_FAILED_MSG, funcname,
1183 picl_strerror(err));
1184 return;
1185 }
1186
1187 /* determine number of elements in the table */
1188 dependents = 0;
1189 for (j = i; j < count; ++j) {
1190 if (strcmp(aobjp->name, assoc_tbl[j].antecedent) == 0)
1191 ++dependents;
1192 }
1193
1194 dep_list = (picl_nodehdl_t *)malloc(sizeof (picl_nodehdl_t) *
1195 dependents);
1196 if (dep_list == NULL) {
1197 init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1198 return;
1199 }
1200 /* build row of reference properties */
1201 offset = 0;
1202 for (j = i; j < count; ++j) {
1203 if (strcmp(aobjp->name, assoc_tbl[j].antecedent) != 0)
1204 continue;
1205
1206 dobjp = (picl_psvc_t *)bsearch(assoc_tbl[j].dependent,
1207 psvc_hdl.objects,
1208 psvc_hdl.obj_count, sizeof (picl_psvc_t),
1209 (int (*)(const void *, const void *))
1210 name_compare_bsearch);
1211 if (dobjp == NULL) {
1212 init_err(ID_NOT_FOUND_MSG,
1213 funcname, assoc_tbl[j].dependent);
1214 return;
1215 }
1216
1217 /*
1218 * Reference property name must be
1219 * _classname_propertyname
1220 */
1221 err = ptree_get_propval_by_name(dobjp->node,
1222 "_class", class, sizeof (class));
1223 if (err != 0) {
1224 init_err(CLASS_NOT_FOUND_MSG, funcname,
1225 assoc_tbl[j].dependent);
1226 return;
1227 }
1228 (void) snprintf(name, sizeof (name), "_%s_subclass",
1229 class);
1230
1231 propinfo.version = PSVC_PLUGIN_VERSION;
1232 propinfo.read = NULL;
1233 propinfo.write = NULL;
1234 propinfo.piclinfo.type = PICL_PTYPE_REFERENCE;
1235 propinfo.piclinfo.accessmode = PICL_READ;
1236 propinfo.piclinfo.size = sizeof (picl_nodehdl_t);
1237 (void) strcpy(propinfo.piclinfo.name, name);
1238
1239 err = ptree_create_prop(&propinfo, &dobjp->node,
1240 dep_list + offset);
1241 if (err != 0) {
1242 init_err(PTREE_CREATE_PROP_FAILED_MSG,
1243 name, picl_strerror(err));
1244 return;
1245 }
1246
1247 ++offset;
1248 }
1249
1250 /* add row to table */
1251 err = ptree_add_row_to_table(tbl_hdl, dependents, dep_list);
1252 if (err != 0) {
1253 init_err(PTREE_ADD_ROW_FAILED_MSG, funcname,
1254 picl_strerror(err));
1255 return;
1256 }
1257
1258 }
1259
1260
1261 }
1262
1263 /* Load projected properties */
1264 static void
load_projected_properties(FILE * fp)1265 load_projected_properties(FILE *fp)
1266 {
1267 int32_t found;
1268 ptree_propinfo_t propinfo;
1269 ptree_propinfo_t dstinfo;
1270 picl_prophdl_t src_prophdl, dst_prophdl;
1271 picl_nodehdl_t src_node, dst_node;
1272 int err, i;
1273 picl_psvc_t *srcobjp, *dstobjp;
1274 char src[32], dst[256];
1275 char src_prop[32], dst_prop[32];
1276 char buf[BUFSZ];
1277 char *funcname = "load_projected_properties";
1278
1279 if (find_file_section(fp, "PROJECTED_PROPERTIES") != 0)
1280 return;
1281
1282 if (count_records(fp, "PROJECTED_PROPERTIES_END", &proj_prop_count) !=
1283 0) {
1284 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1285 return;
1286 }
1287
1288 prop_list = (struct proj_prop *)malloc(sizeof (struct proj_prop)
1289 * proj_prop_count);
1290 if (prop_list == NULL) {
1291 init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1292 return;
1293 }
1294
1295 for (i = 0; i < proj_prop_count; ++i) {
1296 buf[0] = '\0';
1297 (void) fgets(buf, BUFSZ, fp);
1298 found = sscanf(buf, "%31s %31s %255s %31s", src, src_prop, dst,
1299 dst_prop);
1300 if (found != 4) {
1301 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1302 return;
1303 }
1304
1305 /* find src node */
1306 if (src[0] == '/') {
1307 /* picl node name, outside psvc subtree */
1308 err = ptree_get_node_by_path(src, &src_node);
1309 if (err != 0) {
1310 init_err(NODE_NOT_FOUND_MSG, funcname, src);
1311 return;
1312 }
1313 } else {
1314 srcobjp = (picl_psvc_t *)bsearch(src, psvc_hdl.objects,
1315 psvc_hdl.obj_count, sizeof (picl_psvc_t),
1316 (int (*)(const void *, const void *))
1317 name_compare_bsearch);
1318 if (srcobjp == NULL) {
1319 init_err(ID_NOT_FOUND_MSG, funcname, src);
1320 return;
1321 }
1322 src_node = srcobjp->node;
1323 }
1324
1325 /* find dest node */
1326 if (dst[0] == '/') {
1327 /* picl node name, outside psvc subtree */
1328 err = ptree_get_node_by_path(dst, &dst_node);
1329 if (err != 0) {
1330 init_err(NODE_NOT_FOUND_MSG, funcname, dst);
1331 return;
1332 }
1333 prop_list[i].dst_node = dst_node;
1334 } else {
1335 dstobjp = (picl_psvc_t *)bsearch(dst, psvc_hdl.objects,
1336 psvc_hdl.obj_count, sizeof (picl_psvc_t),
1337 (int (*)(const void *, const void *))
1338 name_compare_bsearch);
1339 if (dstobjp == NULL) {
1340 init_err(ID_NOT_FOUND_MSG, funcname, dst);
1341 return;
1342 }
1343 dst_node = dstobjp->node;
1344 prop_list[i].dst_node = dst_node;
1345 }
1346
1347 /* determine destination property size */
1348 err = ptree_get_first_prop(dst_node, &dst_prophdl);
1349 while (err == 0) {
1350 err = ptree_get_propinfo(dst_prophdl, &dstinfo);
1351 if (err != 0)
1352 break;
1353 if (strcmp(dst_prop, dstinfo.piclinfo.name) == 0)
1354 break;
1355 err = ptree_get_next_prop(dst_prophdl, &dst_prophdl);
1356 }
1357 if (err != 0) {
1358 init_err(SIZE_NOT_FOUND_MSG, funcname, dst_prop);
1359 return;
1360 }
1361
1362 propinfo.version = PSVC_PLUGIN_VERSION;
1363 propinfo.read = projected_read;
1364 propinfo.write = projected_write;
1365 propinfo.piclinfo.type = dstinfo.piclinfo.type;
1366 propinfo.piclinfo.accessmode =
1367 PICL_READ | PICL_WRITE | PICL_VOLATILE;
1368 propinfo.piclinfo.size = dstinfo.piclinfo.size;
1369 (void) strcpy(propinfo.piclinfo.name, src_prop);
1370
1371 err = ptree_create_prop(&propinfo, 0, &src_prophdl);
1372 if (err != 0) {
1373 init_err(PTREE_CREATE_PROP_FAILED_MSG, funcname,
1374 picl_strerror(err));
1375 return;
1376 }
1377
1378 err = ptree_add_prop(src_node, src_prophdl);
1379 if (err != 0) {
1380 init_err(PTREE_ADD_PROP_FAILED_MSG, funcname,
1381 picl_strerror(err));
1382 return;
1383 }
1384
1385 prop_list[i].handle = src_prophdl;
1386 (void) strcpy(prop_list[i].name, dst_prop);
1387
1388 }
1389 }
1390
1391 /* Load the association table */
load_associations(FILE * fp)1392 static void load_associations(FILE *fp)
1393 {
1394 char *funcname = "load_associations";
1395 uint32_t count;
1396 int found;
1397 int j;
1398 char assoc_name[32];
1399 struct assoc_pair *assoc_tbl;
1400 char name1[32];
1401 char buf[BUFSZ];
1402
1403 /*
1404 * ignore count in the file, correct count is highest
1405 * association id + 1, now figured when loading ASSOC_STR
1406 * section.
1407 */
1408 if (find_file_section(fp, "ASSOCIATIONS") != 0)
1409 return;
1410
1411 buf[0] = '\0';
1412 (void) fgets(buf, BUFSZ, fp);
1413 while (strncmp("ASSOCIATIONS_END", buf, 16) != 0) {
1414 found = sscanf(buf, "%31s %31s", name1, assoc_name);
1415 if (found != 2) {
1416 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1417 return;
1418 }
1419
1420 if (count_records(fp, "ASSOCIATION_END", &count) != 0) {
1421 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1422 return;
1423 }
1424
1425 assoc_tbl = (struct assoc_pair *)malloc(
1426 sizeof (struct assoc_pair) * count);
1427 if (assoc_tbl == NULL) {
1428 init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1429 return;
1430 }
1431
1432 for (j = 0; j < count; ++j) {
1433 buf[0] = '\0';
1434 (void) fgets(buf, BUFSZ, fp);
1435 found = sscanf(buf, "%31s %31s",
1436 assoc_tbl[j].antecedent, assoc_tbl[j].dependent);
1437 if (found != 2) {
1438 init_err(INVALID_FILE_FORMAT_MSG, funcname,
1439 0);
1440 return;
1441 }
1442
1443 }
1444 buf[0] = '\0';
1445 (void) fgets(buf, BUFSZ, fp);
1446 if (strncmp(buf, "ASSOCIATION_END", 15) != 0) {
1447 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1448 return;
1449 }
1450
1451 /* Create separate list of dependents for each antecedent */
1452 if (strcmp(assoc_name, "PSVC_TABLE") != 0) {
1453 create_reference_properties(assoc_tbl, count,
1454 assoc_name);
1455 }
1456
1457 free(assoc_tbl);
1458 buf[0] = '\0';
1459 (void) fgets(buf, BUFSZ, fp);
1460 }
1461
1462 }
1463
1464 /* Enviornmental Lock Object's Read and Write routine */
1465 /* ARGSUSED */
1466 static int
env_lock_read(ptree_rarg_t * rarg,void * buf)1467 env_lock_read(ptree_rarg_t *rarg, void *buf)
1468 {
1469 (void) strlcpy((char *)buf, env_lock_state, LOCK_STRING_MAX);
1470 return (PSVC_SUCCESS);
1471 }
1472
1473 /* ARGSUSED */
1474 static int
env_lock_write(ptree_warg_t * warg,const void * buf)1475 env_lock_write(ptree_warg_t *warg, const void *buf)
1476 {
1477 int32_t status = PSVC_SUCCESS;
1478 char *var = (char *)buf;
1479
1480 /*
1481 * Check to make sure that the value is either Disabled or Enabled
1482 * as these are the only 2 states that this object can be set to.
1483 */
1484 if ((strcmp(var, PSVC_LOCK_DISABLED) != 0) &&
1485 (strcmp(var, PSVC_LOCK_ENABLED) != 0)) {
1486 errno = EINVAL;
1487 return (PSVC_FAILURE);
1488 }
1489
1490 (void) pthread_mutex_lock(&env_lock_mutex);
1491
1492 /*
1493 * If the state is already Enabled we can set the state to Disabled
1494 * to stop the policies.
1495 */
1496 if (strcmp(env_lock_state, PSVC_LOCK_ENABLED) == 0) {
1497 (void) pthread_mutex_unlock(&env_lock_mutex);
1498 status = timed_lock_wait(PSVC_LOCK_DISABLED);
1499 if (status == -1) {
1500 syslog(LOG_ERR, SEM_WAIT_FAILED_MSG);
1501 }
1502 return (status);
1503 }
1504
1505 /*
1506 * If the state is Running we must go into timed_lock_wait to aquire
1507 * the env_lock.
1508 */
1509 if (strcmp(env_lock_state, PSVC_LOCK_RUNNING) == 0) {
1510 (void) pthread_mutex_unlock(&env_lock_mutex);
1511 status = timed_lock_wait(PSVC_LOCK_DISABLED);
1512 if (status == -1) {
1513 syslog(LOG_ERR, SEM_WAIT_FAILED_MSG);
1514 }
1515 return (status);
1516 }
1517
1518 /*
1519 * If the state is already Disabled we need to first check to see if
1520 * we are resetting it to Disabled or changing it to Enabled. If we
1521 * are resetting it to Disabled then we need to stop the timer and
1522 * restart it. If we are changing it to Enabled we just set it to
1523 * enabled.
1524 */
1525 if (strcmp(env_lock_state, PSVC_LOCK_DISABLED) == 0) {
1526 if (strcmp(var, PSVC_LOCK_DISABLED) == 0) {
1527 (void) pthread_mutex_lock(&timer_mutex);
1528 if (timer_state == ACTIVE) {
1529 timer_state = NOT_READY;
1530 /* stop timer */
1531 (void) pthread_cond_signal(&timer_cond);
1532 (void) pthread_mutex_unlock(&timer_mutex);
1533 /* wait for timer to reset */
1534 while (timer_state != READY)
1535 (void) sched_yield();
1536 (void) pthread_mutex_lock(&timer_mutex);
1537 timer_state = HAVE_REQUEST;
1538 /* restart timer */
1539 (void) pthread_cond_signal(&timer_cond);
1540 }
1541 (void) pthread_mutex_unlock(&timer_mutex);
1542 } else {
1543 (void) strlcpy(env_lock_state, var, LOCK_STRING_MAX);
1544 }
1545 }
1546 (void) pthread_mutex_unlock(&env_lock_mutex);
1547 return (PSVC_SUCCESS);
1548 }
1549
1550 static int
init_env_lock_node(picl_nodehdl_t root_node)1551 init_env_lock_node(picl_nodehdl_t root_node)
1552 {
1553 int err;
1554 ptree_propinfo_t propinfo;
1555 char *funcname = "init_env_lock_node";
1556
1557 /* Here we are creating a Enviornmental Lock Node */
1558 err = ptree_create_node("/plugins/environmental", "picl", &lock_node);
1559 if (err != PICL_SUCCESS) {
1560 init_err(PTREE_CREATE_NODE_FAILED_MSG, funcname,
1561 picl_strerror(err));
1562 return (err);
1563 }
1564
1565 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION_1,
1566 PICL_PTYPE_CHARSTRING, PICL_READ | PICL_WRITE | PICL_VOLATILE,
1567 32, "State", env_lock_read, env_lock_write);
1568 if (err != PICL_SUCCESS) {
1569 init_err(NODE_PROP_FAILED_MSG, funcname, picl_strerror(err));
1570 return (err);
1571 }
1572
1573 err = ptree_create_and_add_prop(lock_node, &propinfo,
1574 NULL, NULL);
1575 if (err != PICL_SUCCESS) {
1576 init_err(PTREE_ADD_PROP_FAILED_MSG, funcname,
1577 picl_strerror(err));
1578 return (err);
1579 }
1580
1581 err = ptree_add_node(root_node, lock_node);
1582 if (err != PICL_SUCCESS) {
1583 init_err(PTREE_ADD_NODE_FAILED_MSG, funcname,
1584 picl_strerror(err));
1585 return (err);
1586 }
1587
1588 return (PSVC_SUCCESS);
1589 }
1590
1591 void
psvc_plugin_init(void)1592 psvc_plugin_init(void)
1593 {
1594 struct classinfo *cp;
1595 picl_nodehdl_t root_node;
1596 picl_nodehdl_t parent_node;
1597 char *funcname = "psvc_plugin_init";
1598 char platform[32];
1599 char filename[256];
1600 char buf[BUFSZ];
1601 int32_t i, j;
1602 int err, found;
1603
1604 psvc_paths = NULL;
1605 psvc_hdl.obj_count = 0;
1606 psvc_hdl.objects = NULL;
1607 psvc_hdl.fp = NULL;
1608 first_interval = NULL;
1609
1610 /*
1611 * So the volatile read/write routines can retrieve data from
1612 * psvc or picl
1613 */
1614 err = psvc_init(&hdlp);
1615 if (err != 0) {
1616 init_err(PSVC_INIT_ERR_MSG, funcname, strerror(errno));
1617 }
1618
1619 if (sysinfo(SI_PLATFORM, platform, sizeof (platform)) == -1) {
1620 init_err(SYSINFO_FAILED_MSG, funcname, 0);
1621 return;
1622 }
1623
1624 (void) snprintf(filename, sizeof (filename),
1625 "/usr/platform/%s/lib/psvcobj.conf", platform);
1626 if ((psvc_hdl.fp = fopen(filename, "r")) == NULL) {
1627 init_err(FILE_OPEN_FAILED_MSG, funcname, filename);
1628 return;
1629 }
1630
1631 /* Create all PICL nodes */
1632 if (find_file_section(psvc_hdl.fp, "OBJECT_INFO") == -1) {
1633 init_err(INVALID_FILE_FORMAT1_MSG, funcname, filename);
1634 return;
1635 }
1636 if (count_records(psvc_hdl.fp, "OBJECT_INFO_END", &psvc_hdl.obj_count)
1637 == -1) {
1638 init_err(INVALID_FILE_FORMAT1_MSG, funcname, filename);
1639 return;
1640 }
1641 if ((psvc_hdl.objects = (picl_psvc_t *)malloc(sizeof (picl_psvc_t) *
1642 psvc_hdl.obj_count)) == NULL) {
1643 init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1644 return;
1645 }
1646 (void) memset(psvc_hdl.objects, 0,
1647 sizeof (picl_psvc_t) * psvc_hdl.obj_count);
1648
1649 err = ptree_get_root(&root_node);
1650 if (err != 0) {
1651 init_err(PTREE_GET_ROOT_FAILED_MSG, funcname,
1652 picl_strerror(err));
1653 return;
1654 }
1655
1656 /* Following array is accessed directly by the psvc policies. */
1657 psvc_paths = (psvc_name_t *)malloc(sizeof (psvc_name_t) *
1658 psvc_hdl.obj_count);
1659 psvc_picl_nodes = psvc_hdl.obj_count;
1660 if (psvc_paths == NULL) {
1661 init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1662 return;
1663 }
1664 for (i = 0; i < psvc_hdl.obj_count; ++i) {
1665 char *start;
1666 int32_t class;
1667 int32_t subclass;
1668 int32_t cp_count;
1669 picl_psvc_t *objp = &psvc_hdl.objects[i];
1670 buf[0] = '\0';
1671 (void) fgets(buf, BUFSZ, psvc_hdl.fp);
1672 if (strncmp(buf, "OBJECT_INFO_END", 15) == 0)
1673 break;
1674
1675 start = strrchr(buf, '/');
1676 if (start == NULL) {
1677 init_err(INVALID_FILE_FORMAT1_MSG, funcname,
1678 filename);
1679 return;
1680 }
1681 found = sscanf(start + 1, "%31s", objp->name);
1682 if (found != 1) {
1683 init_err(INVALID_FILE_FORMAT1_MSG, funcname,
1684 filename);
1685 return;
1686 }
1687
1688 /* get class */
1689 err = psvc_get_attr(hdlp, objp->name, PSVC_CLASS_ATTR, &class);
1690 if (err != PSVC_SUCCESS) {
1691 init_err(CLASS_NOT_FOUND_MSG, funcname, objp->name);
1692 return;
1693 }
1694 if (class > NUM_CLASSES) {
1695 init_err(UNKNOWN_CLASS_MSG, funcname, 0);
1696 return;
1697 }
1698
1699 err = psvc_get_attr(hdlp, objp->name, PSVC_SUBCLASS_ATTR,
1700 &subclass);
1701 if (err != PSVC_SUCCESS) {
1702 init_err(SUBCLASS_NOT_FOUND_MSG, funcname, objp->name);
1703 return;
1704 }
1705
1706 err = ptree_create_node(objp->name, class_name[class],
1707 &objp->node);
1708 if (err != 0) {
1709 init_err(PTREE_CREATE_NODE_FAILED_MSG, funcname,
1710 picl_strerror(err));
1711 return;
1712 }
1713 if (strcmp(objp->name, PSVC_CHASSIS) == 0)
1714 system_node = objp->node;
1715
1716 for (j = 0; j < COMMON_COUNT; ++j) {
1717
1718 err = node_property(objp->node,
1719 common[j].access & PICL_READ ?
1720 psvc_read_volatile : 0,
1721 common[j].access & PICL_WRITE ?
1722 psvc_write_volatile : 0,
1723 common[j].type, common[j].size,
1724 common[j].access, common[j].name, 0);
1725 if (err != PSVC_SUCCESS) {
1726 init_err(NODE_PROP_FAILED_MSG, funcname,
1727 picl_strerror(err));
1728 return;
1729 }
1730 }
1731 cp = &class_properties[class];
1732 /* Locator LED Support */
1733 if (class == 2 && subclass == 2) {
1734 cp_count = 3;
1735 } else {
1736 cp_count = cp->count;
1737 }
1738
1739 for (j = 0; j < cp_count; ++j) {
1740 err = node_property(objp->node, psvc_read_volatile,
1741 psvc_write_volatile, cp->props[j].type,
1742 cp->props[j].size,
1743 cp->props[j].access, cp->props[j].name, 0);
1744 if (err != PSVC_SUCCESS) {
1745 init_err(NODE_PROP_FAILED_MSG, funcname,
1746 picl_strerror(err));
1747 return;
1748 }
1749 }
1750
1751 /* Link the nodes into the PICL tree */
1752 *start = 0;
1753 if (start == buf) { /* no parent */
1754 parent_node = root_node;
1755 } else {
1756 err = ptree_get_node_by_path(buf, &parent_node);
1757 if (err != PICL_SUCCESS) {
1758 init_err(NODE_NOT_FOUND_MSG, funcname, buf);
1759 return;
1760 }
1761 }
1762
1763 err = ptree_add_node(parent_node, objp->node);
1764 if (err != PICL_SUCCESS) {
1765 init_err(PTREE_ADD_NODE_FAILED_MSG, funcname,
1766 picl_strerror(err));
1767 return;
1768 }
1769 (void) strcpy(psvc_paths[i].parent_path, buf);
1770 (void) strcpy(psvc_paths[i].child_name, objp->name);
1771 psvc_paths[i].child_node = objp->node;
1772 }
1773
1774 qsort(psvc_hdl.objects, psvc_hdl.obj_count, sizeof (picl_psvc_t),
1775 (int (*)(const void *, const void *))name_compare_qsort);
1776
1777 load_associations(psvc_hdl.fp);
1778 load_projected_properties(psvc_hdl.fp);
1779
1780 if (init_env_lock_node(root_node) != PSVC_SUCCESS)
1781 return;
1782
1783 init_daemon();
1784 }
1785
1786 void
psvc_plugin_fini(void)1787 psvc_plugin_fini(void)
1788 {
1789 int32_t i;
1790 EInterval_t *ip, *next;
1791
1792 fini_daemon();
1793 for (ip = first_interval; ip != 0; ip = next) {
1794 for (i = 0; i < ip->num_tasks; ++i) {
1795 (void) dlclose(ip->task_list[i].hdl);
1796 free(ip->task_list[i].obj_list);
1797 }
1798 free(ip->task_list);
1799 next = ip->next;
1800 free(ip);
1801 }
1802 free(prop_list);
1803 free(psvc_paths);
1804 free(psvc_hdl.objects);
1805 if (psvc_hdl.fp != NULL)
1806 (void) fclose(psvc_hdl.fp);
1807 psvc_fini(hdlp);
1808 }
1809
1810 void
psvc_plugin_register(void)1811 psvc_plugin_register(void)
1812 {
1813 picld_plugin_register(&psvc_reg);
1814 }
1815