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
run_policies(EInterval_t * ip)521 static void run_policies(EInterval_t *ip)
522 {
523 ETask_t *tp;
524 int32_t i, j;
525
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);
535 }
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);
543 }
544 if (ip->has_thread && (ip->interval == 0))
545 break;
546 }
547 } while (ip->interval);
548 }
549
thread_setup(EInterval_t * ip)550 static void thread_setup(EInterval_t *ip)
551 {
552 int32_t status;
553
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);
560 }
561 ip->has_thread = 1;
562 }
563
load_policy(const char * library,ETask_t * tp)564 static int32_t load_policy(const char *library, ETask_t *tp)
565 {
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);
571 }
572 exit(1);
573 }
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);
579 }
580 exit(1);
581 }
582 return (0);
583 }
584
get_timeout(FILE * fp,int * timeout)585 static int32_t get_timeout(FILE *fp, int *timeout)
586 {
587 char buf[BUFSZ];
588 char name[32];
589 char *cp;
590
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);
600
601 if (strcmp(name, "TIMEOUT") != 0) {
602 errno = EINVAL;
603 return (-1);
604 }
605 return (0);
606
607 }
608
load_interval(FILE * fp,EInterval_t ** ipp)609 static int32_t load_interval(FILE *fp, EInterval_t **ipp)
610 {
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;
620
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);
633 }
634
635 if (strcmp(name, "INTERVAL") != 0) {
636 errno = EINVAL;
637 return (-1);
638 }
639
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;
647
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];
654
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);
661 }
662
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);
672 }
673 tp->obj_list =
674 (EName_t *)malloc(tp->num_objects * sizeof (EName_t));
675 if (tp->obj_list == NULL)
676 return (-1);
677
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);
686 }
687 }
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);
696 }
697 }
698
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);
705 }
706
707 *ipp = ip;
708 return (0);
709 }
710
711 void
fini_daemon(void)712 fini_daemon(void)
713 {
714 EInterval_t *ip;
715
716 /* shut down the threads running the policies */
717 for (ip = first_interval; ip != NULL; ip = ip->next) {
718 if (ip->has_thread) {
719 /*
720 * there is a thread for this interval; tell it to stop
721 * by clearing the interval
722 */
723 ip->interval = 0;
724 }
725 }
726 for (ip = first_interval; ip != NULL; ip = ip->next) {
727 if (ip->has_thread) {
728 (void) pthread_join(ip->thread, NULL);
729 }
730 }
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);
743 }
744
745 void
init_daemon(void)746 init_daemon(void)
747 {
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;
755
756 if (sysinfo(SI_PLATFORM, platform, sizeof (platform)) == -1) {
757 if (debug_flag)
758 syslog(LOG_ERR, "%s", strerror(errno));
759 return;
760 }
761
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;
768 }
769
770 status = get_timeout(fp, &app_timeout);
771 if (status != 0) {
772 if (debug_flag)
773 syslog(LOG_ERR, "%s", strerror(errno));
774 return;
775 }
776
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;
782 }
783
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);
788
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;
796 }
797
798 /* get timer thread running */
799 while (timer_state != READY)
800 (void) sched_yield();
801
802 for (;;) {
803 status = load_interval(fp, &ip);
804 if (status != 0)
805 break;
806
807 #ifdef lint
808 prev = NULL;
809 #endif
810 if (first_interval == 0)
811 first_interval = ip;
812 else
813 prev->next = ip;
814 prev = ip;
815
816 ++intervals;
817 if (ip->interval == 0) {
818 run_policies(ip);
819 } else {
820 thread_setup(ip);
821 ++threads;
822 }
823 }
824 if (intervals == 0) {
825 if (debug_flag)
826 syslog(LOG_ERR, "ERROR: No policies started");
827 return;
828 }
829
830 if (status == -1) {
831 if (debug_flag)
832 syslog(LOG_ERR, "%s", strerror(errno));
833 return;
834 }
835 }
836
837
count_records(FILE * fp,char * end,uint32_t * countp)838 static int32_t count_records(FILE *fp, char *end, uint32_t *countp)
839 {
840 long first_record;
841 char *ret;
842 char buf[BUFSZ];
843 uint32_t count = 0;
844
845 first_record = ftell(fp);
846
847 while ((ret = fgets(buf, BUFSZ, fp)) != NULL) {
848 if (strncmp(end, buf, strlen(end)) == 0)
849 break;
850 ++count;
851 }
852
853 if (ret == NULL) {
854 errno = EINVAL;
855 return (-1);
856 }
857
858 (void) fseek(fp, first_record, SEEK_SET);
859 *countp = count;
860 return (0);
861 }
862
863 /*
864 * Find start of a section within the config file,
865 * Returns number of records in the section.
866 * FILE *fd is set to first data record within section.
867 */
868 static int32_t
find_file_section(FILE * fd,char * start)869 find_file_section(FILE *fd, char *start)
870 {
871 char *ret;
872 char buf[BUFSZ];
873 char name[32];
874 int found;
875
876 (void) fseek(fd, 0, SEEK_SET);
877 while ((ret = fgets(buf, BUFSZ, fd)) != NULL) {
878 if (strncmp(start, buf, strlen(start)) == 0)
879 break;
880 }
881
882 if (ret == NULL) {
883 errno = EINVAL;
884 return (-1);
885 }
886
887 found = sscanf(buf, "%31s", name);
888 if (found != 1) {
889 errno = EINVAL;
890 return (-1);
891 } else {
892 return (0);
893 }
894
895 }
896
name_compare_qsort(picl_psvc_t * s1,picl_psvc_t * s2)897 static int32_t name_compare_qsort(picl_psvc_t *s1, picl_psvc_t *s2)
898 {
899 return (strcmp(s1->name, s2->name));
900 }
901
name_compare_bsearch(char * s1,picl_psvc_t * s2)902 static int32_t name_compare_bsearch(char *s1, picl_psvc_t *s2)
903 {
904 return (strcmp(s1, s2->name));
905 }
906
907 /*
908 * Create a property and add it to the specified node.
909 * PICL will take a segmentation violation if a volatile property
910 * has a non-zero size.
911 */
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)912 static int32_t node_property(picl_nodehdl_t node,
913 int (*read)(ptree_rarg_t *, void *),
914 int (*write)(ptree_warg_t *, const void *), picl_prop_type_t type,
915 unsigned int size, unsigned int accessmode, char *name, void *value)
916 {
917 ptree_propinfo_t propinfo;
918 picl_prophdl_t prophdl;
919 int err;
920
921 propinfo.version = PSVC_PLUGIN_VERSION;
922 if (accessmode & PICL_VOLATILE) {
923 propinfo.read = read;
924 propinfo.write = write;
925 } else {
926 propinfo.read = NULL;
927 propinfo.write = NULL;
928 }
929 propinfo.piclinfo.type = type;
930 propinfo.piclinfo.accessmode = accessmode;
931 propinfo.piclinfo.size = size;
932 (void) strcpy(propinfo.piclinfo.name, name);
933
934 err = ptree_create_prop(&propinfo, value, &prophdl);
935 if (err != 0) {
936 return (err);
937 }
938
939 err = ptree_add_prop(node, prophdl);
940 if (err != 0)
941 return (err);
942
943 return (0);
944 }
945
init_err(const char * fmt,char * arg1,char * arg2)946 static void init_err(const char *fmt, char *arg1, char *arg2)
947 {
948 char msg[256];
949
950 (void) snprintf(msg, sizeof (msg), fmt, arg1, arg2);
951 syslog(LOG_ERR, "%s", msg);
952 }
953
954 static int
projected_lookup(picl_prophdl_t proph,struct proj_prop ** dstp)955 projected_lookup(picl_prophdl_t proph, struct proj_prop **dstp)
956 {
957 int i;
958
959 for (i = 0; i < proj_prop_count; ++i) {
960 if (prop_list[i].handle == proph) {
961 *dstp = &prop_list[i];
962 return (PICL_SUCCESS);
963 }
964 }
965
966 return (PICL_INVALIDHANDLE);
967 }
968
969 int
projected_read(ptree_rarg_t * rarg,void * buf)970 projected_read(ptree_rarg_t *rarg, void *buf)
971 {
972 ptree_propinfo_t propinfo;
973 struct proj_prop *dstinfo;
974 int err;
975
976 err = projected_lookup(rarg->proph, &dstinfo);
977 if (err != 0) {
978 return (PICL_FAILURE);
979 }
980
981
982 err = ptree_get_propinfo(rarg->proph, &propinfo);
983 if (err != 0)
984 return (err);
985 err = ptree_get_propval_by_name(dstinfo->dst_node,
986 dstinfo->name, buf, propinfo.piclinfo.size);
987 if (err != 0)
988 return (err);
989 return (PICL_SUCCESS);
990 }
991
992 int
projected_write(ptree_warg_t * warg,const void * buf)993 projected_write(ptree_warg_t *warg, const void *buf)
994 {
995 ptree_propinfo_t propinfo;
996 struct proj_prop *dstinfo;
997 int err;
998
999 err = projected_lookup(warg->proph, &dstinfo);
1000 if (err != 0) {
1001 return (PICL_FAILURE);
1002 }
1003
1004 err = ptree_get_propinfo(warg->proph, &propinfo);
1005 if (err != 0)
1006 return (err);
1007 err = ptree_update_propval_by_name(dstinfo->dst_node,
1008 dstinfo->name, buf, propinfo.piclinfo.size);
1009 if (err != 0)
1010 return (err);
1011 return (PICL_SUCCESS);
1012 }
1013
1014 int
psvc_read_volatile(ptree_rarg_t * rarg,void * buf)1015 psvc_read_volatile(ptree_rarg_t *rarg, void *buf)
1016 {
1017 ptree_propinfo_t propinfo;
1018 char name[32], class[32];
1019 int err, i;
1020 int32_t attr_num = -1;
1021 int32_t use_attr_num = 0;
1022
1023 err = ptree_get_propval_by_name(rarg->nodeh, "name", name,
1024 sizeof (name));
1025 if (err != 0) {
1026 return (err);
1027 }
1028
1029 err = ptree_get_propval_by_name(rarg->nodeh, "_class", class,
1030 sizeof (class));
1031 if (err != 0) {
1032 return (err);
1033 }
1034
1035 err = ptree_get_propinfo(rarg->proph, &propinfo);
1036 if (err != 0) {
1037 return (err);
1038 }
1039
1040 for (i = 0; i < PICL_PROP_TRANS_COUNT; i++) {
1041 if ((strcmp(class, picl_prop_trans[i].picl_class) == 0) &&
1042 (strcmp(propinfo.piclinfo.name,
1043 picl_prop_trans[i].picl_prop) == 0)) {
1044 attr_num = i;
1045 break;
1046 }
1047 }
1048
1049 if (attr_num == -1)
1050 for (i = 0; i < ATTR_STR_TAB_SIZE; i++) {
1051 if (strcmp(propinfo.piclinfo.name,
1052 attr_str_tab[i]) == 0) {
1053 attr_num = i;
1054 use_attr_num = 1;
1055 break;
1056 }
1057 }
1058
1059 if (use_attr_num)
1060 err = psvc_get_attr(hdlp, name, attr_num, buf);
1061 else
1062 err = psvc_get_attr(hdlp, name,
1063 picl_prop_trans[attr_num].psvc_prop,
1064 buf);
1065
1066 if (err != 0) {
1067 return (PICL_FAILURE);
1068 }
1069 return (PICL_SUCCESS);
1070 }
1071
1072 int
psvc_write_volatile(ptree_warg_t * warg,const void * buf)1073 psvc_write_volatile(ptree_warg_t *warg, const void *buf)
1074 {
1075 ptree_propinfo_t propinfo;
1076 char name[32], class[32];
1077 int err, i;
1078 int32_t attr_num = -1;
1079 int32_t use_attr_num = 0;
1080
1081 if (warg->cred.dc_euid != 0)
1082 return (PICL_PERMDENIED);
1083
1084 err = ptree_get_propval_by_name(warg->nodeh, "name", name,
1085 sizeof (name));
1086 if (err != 0) {
1087 return (err);
1088 }
1089
1090 err = ptree_get_propval_by_name(warg->nodeh, "_class", class,
1091 sizeof (class));
1092 if (err != 0) {
1093 return (err);
1094 }
1095
1096 err = ptree_get_propinfo(warg->proph, &propinfo);
1097 if (err != 0) {
1098 return (err);
1099 }
1100
1101 for (i = 0; i < PICL_PROP_TRANS_COUNT; i++) {
1102 if ((strcmp(class, picl_prop_trans[i].picl_class) == 0) &&
1103 (strcmp(propinfo.piclinfo.name,
1104 picl_prop_trans[i].picl_prop) == 0)) {
1105 attr_num = i;
1106 break;
1107 }
1108 }
1109
1110 if (attr_num == -1)
1111 for (i = 0; i < ATTR_STR_TAB_SIZE; i++) {
1112 if (strcmp(propinfo.piclinfo.name,
1113 attr_str_tab[i]) == 0) {
1114 attr_num = i;
1115 use_attr_num = 1;
1116 break;
1117 }
1118 }
1119
1120 if (use_attr_num)
1121 err = psvc_set_attr(hdlp, name, attr_num, (void *)buf);
1122 else
1123 err = psvc_set_attr(hdlp, name,
1124 picl_prop_trans[attr_num].psvc_prop,
1125 (void *)buf);
1126
1127 if (err != 0) {
1128 return (PICL_FAILURE);
1129 }
1130
1131 return (PICL_SUCCESS);
1132 }
1133
create_reference_properties(struct assoc_pair * assoc_tbl,int32_t count,char * assoc_name)1134 void create_reference_properties(struct assoc_pair *assoc_tbl, int32_t count,
1135 char *assoc_name)
1136 {
1137 picl_psvc_t *aobjp, *dobjp;
1138 picl_prophdl_t tbl_hdl;
1139 picl_nodehdl_t *dep_list;
1140 ptree_propinfo_t propinfo;
1141 char *funcname = "create_reference_properties";
1142 char name[PICL_PROPNAMELEN_MAX];
1143 int32_t i, j, offset;
1144 int32_t dependents;
1145 int32_t err;
1146 char class[PICL_CLASSNAMELEN_MAX];
1147
1148 for (i = 0; i < count; ++i) {
1149 /* antecedent */
1150 aobjp = (picl_psvc_t *)bsearch(assoc_tbl[i].antecedent,
1151 psvc_hdl.objects, psvc_hdl.obj_count,
1152 sizeof (picl_psvc_t),
1153 (int (*)(const void *, const void *))
1154 name_compare_bsearch);
1155 if (aobjp == NULL) {
1156 init_err(ID_NOT_FOUND_MSG,
1157 funcname, assoc_tbl[i].antecedent);
1158 return;
1159 }
1160
1161 /* skip if table already created */
1162 if (ptree_get_propval_by_name(aobjp->node, assoc_name,
1163 &tbl_hdl, sizeof (tbl_hdl)) == 0) {
1164 continue;
1165 }
1166
1167 /* create a new table */
1168 err = ptree_create_table(&tbl_hdl);
1169 if (err != 0) {
1170 init_err(PTREE_CREATE_TABLE_FAILED_MSG,
1171 funcname, picl_strerror(err));
1172 return;
1173 }
1174
1175 err = node_property(aobjp->node, NULL, NULL,
1176 PICL_PTYPE_TABLE, sizeof (tbl_hdl), PICL_READ,
1177 assoc_name, &tbl_hdl);
1178 if (err != 0) {
1179 init_err(CREATE_PROP_FAILED_MSG, funcname,
1180 picl_strerror(err));
1181 return;
1182 }
1183
1184 /* determine number of elements in the table */
1185 dependents = 0;
1186 for (j = i; j < count; ++j) {
1187 if (strcmp(aobjp->name, assoc_tbl[j].antecedent) == 0)
1188 ++dependents;
1189 }
1190
1191 dep_list = (picl_nodehdl_t *)malloc(sizeof (picl_nodehdl_t) *
1192 dependents);
1193 if (dep_list == NULL) {
1194 init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1195 return;
1196 }
1197 /* build row of reference properties */
1198 offset = 0;
1199 for (j = i; j < count; ++j) {
1200 if (strcmp(aobjp->name, assoc_tbl[j].antecedent) != 0)
1201 continue;
1202
1203 dobjp = (picl_psvc_t *)bsearch(assoc_tbl[j].dependent,
1204 psvc_hdl.objects,
1205 psvc_hdl.obj_count, sizeof (picl_psvc_t),
1206 (int (*)(const void *, const void *))
1207 name_compare_bsearch);
1208 if (dobjp == NULL) {
1209 init_err(ID_NOT_FOUND_MSG,
1210 funcname, assoc_tbl[j].dependent);
1211 return;
1212 }
1213
1214 /*
1215 * Reference property name must be
1216 * _classname_propertyname
1217 */
1218 err = ptree_get_propval_by_name(dobjp->node,
1219 "_class", class, sizeof (class));
1220 if (err != 0) {
1221 init_err(CLASS_NOT_FOUND_MSG, funcname,
1222 assoc_tbl[j].dependent);
1223 return;
1224 }
1225 (void) snprintf(name, sizeof (name), "_%s_subclass",
1226 class);
1227
1228 propinfo.version = PSVC_PLUGIN_VERSION;
1229 propinfo.read = NULL;
1230 propinfo.write = NULL;
1231 propinfo.piclinfo.type = PICL_PTYPE_REFERENCE;
1232 propinfo.piclinfo.accessmode = PICL_READ;
1233 propinfo.piclinfo.size = sizeof (picl_nodehdl_t);
1234 (void) strcpy(propinfo.piclinfo.name, name);
1235
1236 err = ptree_create_prop(&propinfo, &dobjp->node,
1237 dep_list + offset);
1238 if (err != 0) {
1239 init_err(PTREE_CREATE_PROP_FAILED_MSG,
1240 name, picl_strerror(err));
1241 return;
1242 }
1243
1244 ++offset;
1245 }
1246
1247 /* add row to table */
1248 err = ptree_add_row_to_table(tbl_hdl, dependents, dep_list);
1249 if (err != 0) {
1250 init_err(PTREE_ADD_ROW_FAILED_MSG, funcname,
1251 picl_strerror(err));
1252 return;
1253 }
1254
1255 }
1256
1257
1258 }
1259
1260 /* Load projected properties */
1261 static void
load_projected_properties(FILE * fp)1262 load_projected_properties(FILE *fp)
1263 {
1264 int32_t found;
1265 ptree_propinfo_t propinfo;
1266 ptree_propinfo_t dstinfo;
1267 picl_prophdl_t src_prophdl, dst_prophdl;
1268 picl_nodehdl_t src_node, dst_node;
1269 int err, i;
1270 picl_psvc_t *srcobjp, *dstobjp;
1271 char src[32], dst[256];
1272 char src_prop[32], dst_prop[32];
1273 char buf[BUFSZ];
1274 char *funcname = "load_projected_properties";
1275
1276 if (find_file_section(fp, "PROJECTED_PROPERTIES") != 0)
1277 return;
1278
1279 if (count_records(fp, "PROJECTED_PROPERTIES_END", &proj_prop_count) !=
1280 0) {
1281 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1282 return;
1283 }
1284
1285 prop_list = (struct proj_prop *)malloc(sizeof (struct proj_prop)
1286 * proj_prop_count);
1287 if (prop_list == NULL) {
1288 init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1289 return;
1290 }
1291
1292 for (i = 0; i < proj_prop_count; ++i) {
1293 buf[0] = '\0';
1294 (void) fgets(buf, BUFSZ, fp);
1295 found = sscanf(buf, "%31s %31s %255s %31s", src, src_prop, dst,
1296 dst_prop);
1297 if (found != 4) {
1298 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1299 return;
1300 }
1301
1302 /* find src node */
1303 if (src[0] == '/') {
1304 /* picl node name, outside psvc subtree */
1305 err = ptree_get_node_by_path(src, &src_node);
1306 if (err != 0) {
1307 init_err(NODE_NOT_FOUND_MSG, funcname, src);
1308 return;
1309 }
1310 } else {
1311 srcobjp = (picl_psvc_t *)bsearch(src, psvc_hdl.objects,
1312 psvc_hdl.obj_count, sizeof (picl_psvc_t),
1313 (int (*)(const void *, const void *))
1314 name_compare_bsearch);
1315 if (srcobjp == NULL) {
1316 init_err(ID_NOT_FOUND_MSG, funcname, src);
1317 return;
1318 }
1319 src_node = srcobjp->node;
1320 }
1321
1322 /* find dest node */
1323 if (dst[0] == '/') {
1324 /* picl node name, outside psvc subtree */
1325 err = ptree_get_node_by_path(dst, &dst_node);
1326 if (err != 0) {
1327 init_err(NODE_NOT_FOUND_MSG, funcname, dst);
1328 return;
1329 }
1330 prop_list[i].dst_node = dst_node;
1331 } else {
1332 dstobjp = (picl_psvc_t *)bsearch(dst, psvc_hdl.objects,
1333 psvc_hdl.obj_count, sizeof (picl_psvc_t),
1334 (int (*)(const void *, const void *))
1335 name_compare_bsearch);
1336 if (dstobjp == NULL) {
1337 init_err(ID_NOT_FOUND_MSG, funcname, dst);
1338 return;
1339 }
1340 dst_node = dstobjp->node;
1341 prop_list[i].dst_node = dst_node;
1342 }
1343
1344 /* determine destination property size */
1345 err = ptree_get_first_prop(dst_node, &dst_prophdl);
1346 while (err == 0) {
1347 err = ptree_get_propinfo(dst_prophdl, &dstinfo);
1348 if (err != 0)
1349 break;
1350 if (strcmp(dst_prop, dstinfo.piclinfo.name) == 0)
1351 break;
1352 err = ptree_get_next_prop(dst_prophdl, &dst_prophdl);
1353 }
1354 if (err != 0) {
1355 init_err(SIZE_NOT_FOUND_MSG, funcname, dst_prop);
1356 return;
1357 }
1358
1359 propinfo.version = PSVC_PLUGIN_VERSION;
1360 propinfo.read = projected_read;
1361 propinfo.write = projected_write;
1362 propinfo.piclinfo.type = dstinfo.piclinfo.type;
1363 propinfo.piclinfo.accessmode =
1364 PICL_READ | PICL_WRITE | PICL_VOLATILE;
1365 propinfo.piclinfo.size = dstinfo.piclinfo.size;
1366 (void) strcpy(propinfo.piclinfo.name, src_prop);
1367
1368 err = ptree_create_prop(&propinfo, 0, &src_prophdl);
1369 if (err != 0) {
1370 init_err(PTREE_CREATE_PROP_FAILED_MSG, funcname,
1371 picl_strerror(err));
1372 return;
1373 }
1374
1375 err = ptree_add_prop(src_node, src_prophdl);
1376 if (err != 0) {
1377 init_err(PTREE_ADD_PROP_FAILED_MSG, funcname,
1378 picl_strerror(err));
1379 return;
1380 }
1381
1382 prop_list[i].handle = src_prophdl;
1383 (void) strcpy(prop_list[i].name, dst_prop);
1384
1385 }
1386 }
1387
1388 /* Load the association table */
load_associations(FILE * fp)1389 static void load_associations(FILE *fp)
1390 {
1391 char *funcname = "load_associations";
1392 uint32_t count;
1393 int found;
1394 int j;
1395 char assoc_name[32];
1396 struct assoc_pair *assoc_tbl;
1397 char name1[32];
1398 char buf[BUFSZ];
1399
1400 /*
1401 * ignore count in the file, correct count is highest
1402 * association id + 1, now figured when loading ASSOC_STR
1403 * section.
1404 */
1405 if (find_file_section(fp, "ASSOCIATIONS") != 0)
1406 return;
1407
1408 buf[0] = '\0';
1409 (void) fgets(buf, BUFSZ, fp);
1410 while (strncmp("ASSOCIATIONS_END", buf, 16) != 0) {
1411 found = sscanf(buf, "%31s %31s", name1, assoc_name);
1412 if (found != 2) {
1413 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1414 return;
1415 }
1416
1417 if (count_records(fp, "ASSOCIATION_END", &count) != 0) {
1418 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1419 return;
1420 }
1421
1422 assoc_tbl = (struct assoc_pair *)malloc(
1423 sizeof (struct assoc_pair) * count);
1424 if (assoc_tbl == NULL) {
1425 init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1426 return;
1427 }
1428
1429 for (j = 0; j < count; ++j) {
1430 buf[0] = '\0';
1431 (void) fgets(buf, BUFSZ, fp);
1432 found = sscanf(buf, "%31s %31s",
1433 assoc_tbl[j].antecedent, assoc_tbl[j].dependent);
1434 if (found != 2) {
1435 init_err(INVALID_FILE_FORMAT_MSG, funcname,
1436 0);
1437 return;
1438 }
1439
1440 }
1441 buf[0] = '\0';
1442 (void) fgets(buf, BUFSZ, fp);
1443 if (strncmp(buf, "ASSOCIATION_END", 15) != 0) {
1444 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
1445 return;
1446 }
1447
1448 /* Create separate list of dependents for each antecedent */
1449 if (strcmp(assoc_name, "PSVC_TABLE") != 0) {
1450 create_reference_properties(assoc_tbl, count,
1451 assoc_name);
1452 }
1453
1454 free(assoc_tbl);
1455 buf[0] = '\0';
1456 (void) fgets(buf, BUFSZ, fp);
1457 }
1458
1459 }
1460
1461 /* Enviornmental Lock Object's Read and Write routine */
1462 /* ARGSUSED */
1463 static int
env_lock_read(ptree_rarg_t * rarg,void * buf)1464 env_lock_read(ptree_rarg_t *rarg, void *buf)
1465 {
1466 (void) strlcpy((char *)buf, env_lock_state, LOCK_STRING_MAX);
1467 return (PSVC_SUCCESS);
1468 }
1469
1470 /* ARGSUSED */
1471 static int
env_lock_write(ptree_warg_t * warg,const void * buf)1472 env_lock_write(ptree_warg_t *warg, const void *buf)
1473 {
1474 int32_t status = PSVC_SUCCESS;
1475 char *var = (char *)buf;
1476
1477 /*
1478 * Check to make sure that the value is either Disabled or Enabled
1479 * as these are the only 2 states that this object can be set to.
1480 */
1481 if ((strcmp(var, PSVC_LOCK_DISABLED) != 0) &&
1482 (strcmp(var, PSVC_LOCK_ENABLED) != 0)) {
1483 errno = EINVAL;
1484 return (PSVC_FAILURE);
1485 }
1486
1487 (void) pthread_mutex_lock(&env_lock_mutex);
1488
1489 /*
1490 * If the state is already Enabled we can set the state to Disabled
1491 * to stop the policies.
1492 */
1493 if (strcmp(env_lock_state, PSVC_LOCK_ENABLED) == 0) {
1494 (void) pthread_mutex_unlock(&env_lock_mutex);
1495 status = timed_lock_wait(PSVC_LOCK_DISABLED);
1496 if (status == -1) {
1497 syslog(LOG_ERR, SEM_WAIT_FAILED_MSG);
1498 }
1499 return (status);
1500 }
1501
1502 /*
1503 * If the state is Running we must go into timed_lock_wait to aquire
1504 * the env_lock.
1505 */
1506 if (strcmp(env_lock_state, PSVC_LOCK_RUNNING) == 0) {
1507 (void) pthread_mutex_unlock(&env_lock_mutex);
1508 status = timed_lock_wait(PSVC_LOCK_DISABLED);
1509 if (status == -1) {
1510 syslog(LOG_ERR, SEM_WAIT_FAILED_MSG);
1511 }
1512 return (status);
1513 }
1514
1515 /*
1516 * If the state is already Disabled we need to first check to see if
1517 * we are resetting it to Disabled or changing it to Enabled. If we
1518 * are resetting it to Disabled then we need to stop the timer and
1519 * restart it. If we are changing it to Enabled we just set it to
1520 * enabled.
1521 */
1522 if (strcmp(env_lock_state, PSVC_LOCK_DISABLED) == 0) {
1523 if (strcmp(var, PSVC_LOCK_DISABLED) == 0) {
1524 (void) pthread_mutex_lock(&timer_mutex);
1525 if (timer_state == ACTIVE) {
1526 timer_state = NOT_READY;
1527 /* stop timer */
1528 (void) pthread_cond_signal(&timer_cond);
1529 (void) pthread_mutex_unlock(&timer_mutex);
1530 /* wait for timer to reset */
1531 while (timer_state != READY)
1532 (void) sched_yield();
1533 (void) pthread_mutex_lock(&timer_mutex);
1534 timer_state = HAVE_REQUEST;
1535 /* restart timer */
1536 (void) pthread_cond_signal(&timer_cond);
1537 }
1538 (void) pthread_mutex_unlock(&timer_mutex);
1539 } else {
1540 (void) strlcpy(env_lock_state, var, LOCK_STRING_MAX);
1541 }
1542 }
1543 (void) pthread_mutex_unlock(&env_lock_mutex);
1544 return (PSVC_SUCCESS);
1545 }
1546
1547 static int
init_env_lock_node(picl_nodehdl_t root_node)1548 init_env_lock_node(picl_nodehdl_t root_node)
1549 {
1550 int err;
1551 ptree_propinfo_t propinfo;
1552 char *funcname = "init_env_lock_node";
1553
1554 /* Here we are creating a Enviornmental Lock Node */
1555 err = ptree_create_node("/plugins/environmental", "picl", &lock_node);
1556 if (err != PICL_SUCCESS) {
1557 init_err(PTREE_CREATE_NODE_FAILED_MSG, funcname,
1558 picl_strerror(err));
1559 return (err);
1560 }
1561
1562 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION_1,
1563 PICL_PTYPE_CHARSTRING, PICL_READ | PICL_WRITE | PICL_VOLATILE,
1564 32, "State", env_lock_read, env_lock_write);
1565 if (err != PICL_SUCCESS) {
1566 init_err(NODE_PROP_FAILED_MSG, funcname, picl_strerror(err));
1567 return (err);
1568 }
1569
1570 err = ptree_create_and_add_prop(lock_node, &propinfo,
1571 NULL, NULL);
1572 if (err != PICL_SUCCESS) {
1573 init_err(PTREE_ADD_PROP_FAILED_MSG, funcname,
1574 picl_strerror(err));
1575 return (err);
1576 }
1577
1578 err = ptree_add_node(root_node, lock_node);
1579 if (err != PICL_SUCCESS) {
1580 init_err(PTREE_ADD_NODE_FAILED_MSG, funcname,
1581 picl_strerror(err));
1582 return (err);
1583 }
1584
1585 return (PSVC_SUCCESS);
1586 }
1587
1588 void
psvc_plugin_init(void)1589 psvc_plugin_init(void)
1590 {
1591 struct classinfo *cp;
1592 picl_nodehdl_t root_node;
1593 picl_nodehdl_t parent_node;
1594 char *funcname = "psvc_plugin_init";
1595 char platform[32];
1596 char filename[256];
1597 char buf[BUFSZ];
1598 int32_t i, j;
1599 int err, found;
1600
1601 psvc_paths = NULL;
1602 psvc_hdl.obj_count = 0;
1603 psvc_hdl.objects = NULL;
1604 psvc_hdl.fp = NULL;
1605 first_interval = NULL;
1606
1607 /*
1608 * So the volatile read/write routines can retrieve data from
1609 * psvc or picl
1610 */
1611 err = psvc_init(&hdlp);
1612 if (err != 0) {
1613 init_err(PSVC_INIT_ERR_MSG, funcname, strerror(errno));
1614 }
1615
1616 if (sysinfo(SI_PLATFORM, platform, sizeof (platform)) == -1) {
1617 init_err(SYSINFO_FAILED_MSG, funcname, 0);
1618 return;
1619 }
1620
1621 (void) snprintf(filename, sizeof (filename),
1622 "/usr/platform/%s/lib/psvcobj.conf", platform);
1623 if ((psvc_hdl.fp = fopen(filename, "r")) == NULL) {
1624 init_err(FILE_OPEN_FAILED_MSG, funcname, filename);
1625 return;
1626 }
1627
1628 /* Create all PICL nodes */
1629 if (find_file_section(psvc_hdl.fp, "OBJECT_INFO") == -1) {
1630 init_err(INVALID_FILE_FORMAT1_MSG, funcname, filename);
1631 return;
1632 }
1633 if (count_records(psvc_hdl.fp, "OBJECT_INFO_END", &psvc_hdl.obj_count)
1634 == -1) {
1635 init_err(INVALID_FILE_FORMAT1_MSG, funcname, filename);
1636 return;
1637 }
1638 if ((psvc_hdl.objects = (picl_psvc_t *)malloc(sizeof (picl_psvc_t) *
1639 psvc_hdl.obj_count)) == NULL) {
1640 init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1641 return;
1642 }
1643 (void) memset(psvc_hdl.objects, 0,
1644 sizeof (picl_psvc_t) * psvc_hdl.obj_count);
1645
1646 err = ptree_get_root(&root_node);
1647 if (err != 0) {
1648 init_err(PTREE_GET_ROOT_FAILED_MSG, funcname,
1649 picl_strerror(err));
1650 return;
1651 }
1652
1653 /* Following array is accessed directly by the psvc policies. */
1654 psvc_paths = (psvc_name_t *)malloc(sizeof (psvc_name_t) *
1655 psvc_hdl.obj_count);
1656 psvc_picl_nodes = psvc_hdl.obj_count;
1657 if (psvc_paths == NULL) {
1658 init_err(MALLOC_FAILED_MSG, funcname, strerror(errno));
1659 return;
1660 }
1661 for (i = 0; i < psvc_hdl.obj_count; ++i) {
1662 char *start;
1663 int32_t class;
1664 int32_t subclass;
1665 int32_t cp_count;
1666 picl_psvc_t *objp = &psvc_hdl.objects[i];
1667 buf[0] = '\0';
1668 (void) fgets(buf, BUFSZ, psvc_hdl.fp);
1669 if (strncmp(buf, "OBJECT_INFO_END", 15) == 0)
1670 break;
1671
1672 start = strrchr(buf, '/');
1673 if (start == NULL) {
1674 init_err(INVALID_FILE_FORMAT1_MSG, funcname,
1675 filename);
1676 return;
1677 }
1678 found = sscanf(start + 1, "%31s", objp->name);
1679 if (found != 1) {
1680 init_err(INVALID_FILE_FORMAT1_MSG, funcname,
1681 filename);
1682 return;
1683 }
1684
1685 /* get class */
1686 err = psvc_get_attr(hdlp, objp->name, PSVC_CLASS_ATTR, &class);
1687 if (err != PSVC_SUCCESS) {
1688 init_err(CLASS_NOT_FOUND_MSG, funcname, objp->name);
1689 return;
1690 }
1691 if (class > NUM_CLASSES) {
1692 init_err(UNKNOWN_CLASS_MSG, funcname, 0);
1693 return;
1694 }
1695
1696 err = psvc_get_attr(hdlp, objp->name, PSVC_SUBCLASS_ATTR,
1697 &subclass);
1698 if (err != PSVC_SUCCESS) {
1699 init_err(SUBCLASS_NOT_FOUND_MSG, funcname, objp->name);
1700 return;
1701 }
1702
1703 err = ptree_create_node(objp->name, class_name[class],
1704 &objp->node);
1705 if (err != 0) {
1706 init_err(PTREE_CREATE_NODE_FAILED_MSG, funcname,
1707 picl_strerror(err));
1708 return;
1709 }
1710 if (strcmp(objp->name, PSVC_CHASSIS) == 0)
1711 system_node = objp->node;
1712
1713 for (j = 0; j < COMMON_COUNT; ++j) {
1714
1715 err = node_property(objp->node,
1716 common[j].access & PICL_READ ?
1717 psvc_read_volatile : 0,
1718 common[j].access & PICL_WRITE ?
1719 psvc_write_volatile : 0,
1720 common[j].type, common[j].size,
1721 common[j].access, common[j].name, 0);
1722 if (err != PSVC_SUCCESS) {
1723 init_err(NODE_PROP_FAILED_MSG, funcname,
1724 picl_strerror(err));
1725 return;
1726 }
1727 }
1728 cp = &class_properties[class];
1729 /* Locator LED Support */
1730 if (class == 2 && subclass == 2) {
1731 cp_count = 3;
1732 } else {
1733 cp_count = cp->count;
1734 }
1735
1736 for (j = 0; j < cp_count; ++j) {
1737 err = node_property(objp->node, psvc_read_volatile,
1738 psvc_write_volatile, cp->props[j].type,
1739 cp->props[j].size,
1740 cp->props[j].access, cp->props[j].name, 0);
1741 if (err != PSVC_SUCCESS) {
1742 init_err(NODE_PROP_FAILED_MSG, funcname,
1743 picl_strerror(err));
1744 return;
1745 }
1746 }
1747
1748 /* Link the nodes into the PICL tree */
1749 *start = 0;
1750 if (start == buf) { /* no parent */
1751 parent_node = root_node;
1752 } else {
1753 err = ptree_get_node_by_path(buf, &parent_node);
1754 if (err != PICL_SUCCESS) {
1755 init_err(NODE_NOT_FOUND_MSG, funcname, buf);
1756 return;
1757 }
1758 }
1759
1760 err = ptree_add_node(parent_node, objp->node);
1761 if (err != PICL_SUCCESS) {
1762 init_err(PTREE_ADD_NODE_FAILED_MSG, funcname,
1763 picl_strerror(err));
1764 return;
1765 }
1766 (void) strcpy(psvc_paths[i].parent_path, buf);
1767 (void) strcpy(psvc_paths[i].child_name, objp->name);
1768 psvc_paths[i].child_node = objp->node;
1769 }
1770
1771 qsort(psvc_hdl.objects, psvc_hdl.obj_count, sizeof (picl_psvc_t),
1772 (int (*)(const void *, const void *))name_compare_qsort);
1773
1774 load_associations(psvc_hdl.fp);
1775 load_projected_properties(psvc_hdl.fp);
1776
1777 if (init_env_lock_node(root_node) != PSVC_SUCCESS)
1778 return;
1779
1780 init_daemon();
1781 }
1782
1783 void
psvc_plugin_fini(void)1784 psvc_plugin_fini(void)
1785 {
1786 int32_t i;
1787 EInterval_t *ip, *next;
1788
1789 fini_daemon();
1790 for (ip = first_interval; ip != 0; ip = next) {
1791 for (i = 0; i < ip->num_tasks; ++i) {
1792 (void) dlclose(ip->task_list[i].hdl);
1793 free(ip->task_list[i].obj_list);
1794 }
1795 free(ip->task_list);
1796 next = ip->next;
1797 free(ip);
1798 }
1799 free(prop_list);
1800 free(psvc_paths);
1801 free(psvc_hdl.objects);
1802 if (psvc_hdl.fp != NULL)
1803 (void) fclose(psvc_hdl.fp);
1804 psvc_fini(hdlp);
1805 }
1806
1807 void
psvc_plugin_register(void)1808 psvc_plugin_register(void)
1809 {
1810 picld_plugin_register(&psvc_reg);
1811 }
1812