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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 */ 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 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 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 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 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 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 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 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 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 */ 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 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 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 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 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 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 1811 psvc_plugin_register(void) 1812 { 1813 picld_plugin_register(&psvc_reg); 1814 } 1815