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 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 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 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 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 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 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 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 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 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 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 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 */ 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 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 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 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 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 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 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 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 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 */ 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 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 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 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 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 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 1808 psvc_plugin_register(void) 1809 { 1810 picld_plugin_register(&psvc_reg); 1811 } 1812