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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * PICL plug-in to create environment tree nodes. 31 * This plugin should only be installed in the platform directories 32 * of supported systems, such as /usr/platform/picl/plugins/SUNW,<>. 33 */ 34 35 #include <picl.h> 36 #include <picltree.h> 37 #include <stdio.h> 38 #include <time.h> 39 #include <dlfcn.h> 40 #include <fcntl.h> 41 #include <unistd.h> 42 #include <stdlib.h> 43 #include <limits.h> 44 #include <ctype.h> 45 #include <pthread.h> 46 #include <libintl.h> 47 #include <errno.h> 48 #include <semaphore.h> 49 #include <sched.h> 50 #include <syslog.h> 51 #include <string.h> 52 #include <signal.h> 53 #include <sys/types.h> 54 #include <sys/systeminfo.h> 55 #include <psvc_objects.h> 56 #include <psvc_objects_class.h> 57 58 int init_done; 59 60 #define BUFSZ 512 61 62 typedef struct { 63 char name[32]; 64 } EName_t; 65 66 typedef struct { 67 int32_t (*funcp)(void *, char *); 68 int32_t num_objects; 69 EName_t *obj_list; 70 char routine[64]; 71 } ETask_t; 72 73 typedef struct interval_info { 74 int32_t interval; 75 int32_t num_tasks; 76 ETask_t *task_list; 77 pthread_t thread; 78 struct interval_info *next; 79 } EInterval_t; 80 81 static EInterval_t *first_interval; 82 83 static psvc_opaque_t hdlp; 84 85 sem_t timer_sem; 86 pthread_mutex_t timer_mutex = PTHREAD_MUTEX_INITIALIZER; 87 pthread_cond_t timer_cond = PTHREAD_COND_INITIALIZER; 88 pthread_t timer_thread_id; 89 90 extern int ptree_get_node_by_path(const char *, picl_nodehdl_t *); 91 92 /* Timer states */ 93 #define NOT_READY 0 94 #define READY 1 95 #define HAVE_REQUEST 2 96 #define ACTIVE 3 97 98 int timer_state = NOT_READY; 99 100 int app_timeout; 101 102 /* Lock State Loop State Definitions */ 103 #define STATE_CHANGED 1 104 #define STATE_NOT_CHANGED 0 105 106 #ifdef DEBUG 107 static int32_t debug_flag = 1; 108 #else 109 static int32_t debug_flag = 0; 110 #endif 111 112 static char library[PATH_MAX]; 113 114 #define PSVC_PLUGIN_VERSION PICLD_PLUGIN_VERSION_1 115 116 #pragma init(psvc_plugin_register) /* place in .init section */ 117 118 typedef struct { 119 char parent_path[256]; 120 char child_name[32]; 121 picl_nodehdl_t child_node; 122 } psvc_name_t; 123 psvc_name_t *psvc_paths; 124 125 #define MUTEX_LOCK_FAILED_MSG gettext("platsvcd: pthread_mutex_lock %s\n") 126 #define CV_WAIT_FAILED_MSG gettext("platsvcd: pthread_cond_wait %s\n") 127 #define CV_TWAIT_FAILED_MSG gettext("platsvcd: pthread_cond_timed_wait %s\n") 128 #define SEM_WAIT_FAILED_MSG gettext("platsvcd: sem_wait failed %s\n") 129 #define PSVC_APP_DEATH_MSG gettext("PSVC application death detected\n") 130 #define POLICY_FAILED_MSG gettext("ERROR running %s on %s (%d)") 131 #define ID_NOT_FOUND_MSG gettext("%s: Can't determine id of %s\n") 132 #define CLASS_NOT_FOUND_MSG gettext("%s: Can't determine class of %s\n") 133 #define SUBCLASS_NOT_FOUND_MSG gettext("%s: Can't determine subclass of %s\n") 134 #define NODE_NOT_FOUND_MSG gettext("%s: Can't determine node of %s\n") 135 #define SIZE_NOT_FOUND_MSG gettext("%s: Couldn't determine size of %s\n") 136 #define PTREE_CREATE_TABLE_FAILED_MSG \ 137 gettext("%s: ptree_create_table failed, %s\n") 138 #define PTREE_CREATE_PROP_FAILED_MSG \ 139 gettext("%s: ptree_create_prop failed, %s\n") 140 #define PTREE_CREATE_NODE_FAILED_MSG \ 141 gettext("%s: ptree_create_node failed, %s\n") 142 #define PTREE_ADD_ROW_FAILED_MSG gettext("%s: ptree_add_row_to_table: %s\n") 143 #define PTREE_ADD_NODE_FAILED_MSG gettext("%s: ptree_add_node: %s\n") 144 #define PTREE_ADD_PROP_FAILED_MSG gettext("%s: ptree_add_prop: %s\n") 145 #define PTREE_GET_ROOT_FAILED_MSG gettext("%s: ptree_get_root: %s\n") 146 #define CREATE_PROP_FAILED_MSG gettext("%s: Error creating property %s\n") 147 #define INVALID_FILE_FORMAT_MSG gettext("%s: Invalid file format\n") 148 #define INVALID_FILE_FORMAT1_MSG gettext("%s: Invalid file format %s\n") 149 #define PSVC_INIT_ERR_MSG gettext("%s: Error in psvc_init(): %s\n") 150 #define SYSINFO_FAILED_MSG gettext("%s: Can't determine platform type\n") 151 #define FILE_OPEN_FAILED_MSG gettext("%s: Can't open file %s\n") 152 #define MALLOC_FAILED_MSG gettext("%s: malloc failed, %s\n") 153 #define UNKNOWN_CLASS_MSG gettext("%s: Unknown class\n") 154 #define NODE_PROP_FAILED_MSG gettext("%s: node_property: %s\n") 155 156 #define LOCK_STRING_MAX 32 157 158 picl_nodehdl_t system_node; 159 static picl_nodehdl_t lock_node; 160 static char env_lock_state[LOCK_STRING_MAX] = PSVC_LOCK_ENABLED; 161 static pthread_mutex_t env_lock_mutex = PTHREAD_MUTEX_INITIALIZER; 162 163 static char *class_name[] = { 164 "temperature-sensor", 165 "fan", 166 "led", 167 "picl", 168 "digital-sensor", 169 "digital-control", 170 "gpio", 171 "fan-tachometer", 172 "switch", 173 "keyswitch", 174 "gpio", 175 "i2c" 176 }; 177 #define NUM_CLASSES (sizeof (class_name) / sizeof (char *)) 178 179 struct proj_prop { /* projected property */ 180 picl_prophdl_t handle; 181 picl_nodehdl_t dst_node; 182 char name[32]; 183 }; 184 185 struct propinfo { 186 char *name; 187 uint32_t type; 188 uint32_t size; 189 uint32_t access; 190 }; 191 192 struct propinfo common[] = { 193 {"State", PICL_PTYPE_CHARSTRING, 32, 194 PICL_READ | PICL_WRITE | PICL_VOLATILE}, 195 {"FaultInformation", PICL_PTYPE_CHARSTRING, 32, 196 PICL_READ | PICL_VOLATILE} 197 }; 198 #define COMMON_COUNT (sizeof (common) / sizeof (struct propinfo)) 199 200 struct propinfo led_properties[] = { 201 {"Color", PICL_PTYPE_CHARSTRING, 32, PICL_READ | PICL_VOLATILE}, 202 {"IsLocator", PICL_PTYPE_CHARSTRING, 32, PICL_READ | PICL_VOLATILE}, 203 {"LocatorName", PICL_PTYPE_CHARSTRING, 32, PICL_READ | PICL_VOLATILE} 204 }; 205 /* 206 * We define the amount of LED properties to 1 because not all LED's have 207 * the two remainding properties. This number is augmented in psvc_plugin_init 208 * when it sees an LED of subclass 2. 209 */ 210 #define LED_COUNT 1 211 212 struct propinfo temperature_sensor_properties[] = { 213 {"Temperature", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE}, 214 {"LowWarningThreshold", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE}, 215 {"LowShutdownThreshold", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE}, 216 {"HighWarningThreshold", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE}, 217 {"HighShutdownThreshold", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE} 218 }; 219 #define TEMP_SENSOR_COUNT \ 220 (sizeof (temperature_sensor_properties) / sizeof (struct propinfo)) 221 222 struct propinfo digi_sensor_properties[] = { 223 {"AtoDSensorValue", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE}, 224 {"LowWarningThreshold", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE}, 225 {"LowShutdownThreshold", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE}, 226 {"HighWarningThreshold", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE}, 227 {"HighShutdownThreshold", PICL_PTYPE_INT, 4, PICL_READ | PICL_VOLATILE} 228 }; 229 #define DIGI_SENSOR_COUNT \ 230 (sizeof (digi_sensor_properties) / sizeof (struct propinfo)) 231 232 struct propinfo boolgpio_properties[] = { 233 {"Gpio-value", PICL_PTYPE_UNSIGNED_INT, sizeof (boolean_t), 234 PICL_READ | PICL_WRITE | PICL_VOLATILE}, 235 {"#Bits", PICL_PTYPE_UNSIGNED_INT, 4, PICL_READ |PICL_VOLATILE} 236 }; 237 #define BOOLGPIO_COUNT (sizeof (boolgpio_properties) / sizeof (struct propinfo)) 238 239 struct propinfo gpio8_properties[] = { 240 {"Gpio-value", PICL_PTYPE_UNSIGNED_INT, 1, 241 PICL_READ | PICL_WRITE | PICL_VOLATILE}, 242 {"#Bits", PICL_PTYPE_UNSIGNED_INT, 4, PICL_READ |PICL_VOLATILE} 243 }; 244 #define GPIO8_COUNT (sizeof (gpio8_properties) / sizeof (struct propinfo)) 245 246 struct propinfo digictrl_properties[] = { 247 {"DtoAControlValue", PICL_PTYPE_INT, 4, 248 PICL_READ | PICL_WRITE | PICL_VOLATILE}, 249 }; 250 #define DIGICTRL_COUNT (sizeof (digictrl_properties) / sizeof (struct propinfo)) 251 252 struct classinfo { 253 struct propinfo *props; 254 int32_t count; 255 } class_properties[] = 256 { 257 {temperature_sensor_properties, TEMP_SENSOR_COUNT}, /* temp sensor */ 258 {0, 0}, /* fan, only has projected properties */ 259 {led_properties, LED_COUNT}, 260 {0, 0}, /* system class */ 261 {digi_sensor_properties, DIGI_SENSOR_COUNT}, /* digital sensor */ 262 {digictrl_properties, DIGICTRL_COUNT}, 263 {boolgpio_properties, BOOLGPIO_COUNT}, 264 {digi_sensor_properties, DIGI_SENSOR_COUNT}, /* fan tach */ 265 {0, 0}, 266 {0, 0}, 267 {gpio8_properties, GPIO8_COUNT}, 268 {0, 0}, 269 }; 270 271 struct prop_trans { 272 char *picl_class; 273 char *picl_prop; 274 int32_t psvc_prop; 275 } picl_prop_trans[] = 276 { 277 {"digital-sensor", "AtoDSensorValue", PSVC_SENSOR_VALUE_ATTR}, 278 {"digital-sensor", "LowWarningThreshold", PSVC_LO_WARN_ATTR}, 279 {"digital-sensor", "LowShutdownThreshold", PSVC_LO_SHUT_ATTR}, 280 {"digital-sensor", "HighWarningThreshold", PSVC_HI_WARN_ATTR}, 281 {"digital-sensor", "HighShutdownThreshold", PSVC_HI_SHUT_ATTR}, 282 {"digital-control", "DtoAControlValue", PSVC_CONTROL_VALUE_ATTR}, 283 {"fan-tachometer", "AtoDSensorValue", PSVC_SENSOR_VALUE_ATTR}, 284 {"fan-tachometer", "LowWarningThreshold", PSVC_LO_WARN_ATTR}, 285 {"fan-tachometer", "LowShutdownThreshold", PSVC_LO_SHUT_ATTR}, 286 {"fan-tachometer", "HighWarningThreshold", PSVC_HI_WARN_ATTR}, 287 {"fan-tachometer", "HighShutdownThreshold", PSVC_HI_SHUT_ATTR}, 288 {"temperature-sensor", "Temperature", PSVC_SENSOR_VALUE_ATTR}, 289 {"temperature-sensor", "LowWarningThreshold", PSVC_LO_WARN_ATTR}, 290 {"temperature-sensor", "LowShutdownThreshold", PSVC_LO_SHUT_ATTR}, 291 {"temperature-sensor", "HighWarningThreshold", PSVC_HI_WARN_ATTR}, 292 {"temperature-sensor", "HighShutdownThreshold", PSVC_HI_SHUT_ATTR}, 293 {"led", "State", PSVC_LED_STATE_ATTR}, 294 {"led", "Color", PSVC_LED_COLOR_ATTR}, 295 {"switch", "State", PSVC_SWITCH_STATE_ATTR}, 296 {"keyswitch", "State", PSVC_SWITCH_STATE_ATTR}, 297 {"i2c", "State", PSVC_PROBE_RESULT_ATTR} 298 }; 299 300 #define PICL_PROP_TRANS_COUNT \ 301 (sizeof (picl_prop_trans) / sizeof (struct prop_trans)) 302 303 304 typedef struct { 305 char name[32]; 306 picl_nodehdl_t node; 307 } picl_psvc_t; 308 309 struct assoc_pair { 310 char antecedent[32]; 311 char dependent[32]; 312 }; 313 314 struct handle { 315 uint32_t obj_count; 316 picl_psvc_t *objects; 317 FILE *fp; 318 } psvc_hdl; 319 320 struct proj_prop *prop_list; 321 uint32_t proj_prop_count; 322 323 int psvc_picl_nodes; 324 325 void psvc_plugin_init(void); 326 void psvc_plugin_fini(void); 327 328 picld_plugin_reg_t psvc_reg = { 329 PSVC_PLUGIN_VERSION, 330 PICLD_PLUGIN_CRITICAL, 331 "PSVC", 332 psvc_plugin_init, 333 psvc_plugin_fini 334 }; 335 336 /* 337 * psvcplugin_add_children was written so that devices which are hotplugable 338 * will be able to add in all thier children and children's children. The 339 * routine takes in the path of a parent and then searches the psvc_paths 340 * array to find all of it's children. It in turns adds the child and then 341 * recursively check to see if it had children and add them too. 342 */ 343 void 344 psvcplugin_add_children(char *parent_path) 345 { 346 int i; 347 picl_nodehdl_t parent_node; 348 char next_path[256]; 349 350 for (i = 0; i < psvc_picl_nodes; ++i) { 351 if (strcmp(parent_path, psvc_paths[i].parent_path) == 0) { 352 ptree_get_node_by_path(parent_path, &parent_node); 353 ptree_add_node(parent_node, psvc_paths[i].child_node); 354 snprintf(next_path, sizeof (next_path), "%s/%s", 355 parent_path, psvc_paths[i].child_name); 356 psvcplugin_add_children(next_path); 357 } 358 } 359 } 360 361 void 362 psvcplugin_lookup(char *name, char *parent, picl_nodehdl_t *node) 363 { 364 int i; 365 366 for (i = 0; i < psvc_picl_nodes; ++i) { 367 if (strcmp(name, psvc_paths[i].child_name) == 0) { 368 strcpy(parent, psvc_paths[i].parent_path); 369 *node = psvc_paths[i].child_node; 370 } 371 } 372 } 373 374 void 375 timer_thread() 376 { 377 struct timespec timeout; 378 int status; 379 380 381 status = pthread_mutex_lock(&timer_mutex); 382 if (status != 0) { 383 syslog(LOG_ERR, MUTEX_LOCK_FAILED_MSG, strerror(status)); 384 } 385 386 for (;;) { 387 /* wait for thread to tell us to start timer */ 388 timer_state = READY; 389 do { 390 status = pthread_cond_wait(&timer_cond, &timer_mutex); 391 } while (timer_state == READY && status == 0); 392 393 if (status != 0) { 394 syslog(LOG_ERR, CV_WAIT_FAILED_MSG, strerror(status)); 395 } 396 397 /* 398 * Will get signalled after semaphore acquired, 399 * or when timeout occurs. 400 */ 401 clock_gettime(CLOCK_REALTIME, &timeout); 402 timeout.tv_sec += app_timeout; 403 404 if (timer_state == HAVE_REQUEST) { 405 timer_state = ACTIVE; 406 do { 407 status = pthread_cond_timedwait(&timer_cond, 408 &timer_mutex, &timeout); 409 } while (timer_state == ACTIVE && status == 0); 410 } 411 412 if (status != 0) { 413 if (status == ETIMEDOUT) { 414 syslog(LOG_ERR, PSVC_APP_DEATH_MSG); 415 pthread_mutex_lock(&env_lock_mutex); 416 strlcpy(env_lock_state, PSVC_LOCK_ENABLED, 417 LOCK_STRING_MAX); 418 pthread_mutex_unlock(&env_lock_mutex); 419 } else { 420 syslog(LOG_ERR, CV_TWAIT_FAILED_MSG, 421 strerror(status)); 422 } 423 } 424 } 425 } 426 427 static int 428 lock_state_loop(char *set_lock_state) 429 { 430 pthread_mutex_lock(&env_lock_mutex); 431 if (strcmp(env_lock_state, PSVC_LOCK_ENABLED) == 0) { 432 strlcpy(env_lock_state, set_lock_state, LOCK_STRING_MAX); 433 pthread_mutex_unlock(&env_lock_mutex); 434 return (STATE_NOT_CHANGED); 435 } 436 pthread_mutex_unlock(&env_lock_mutex); 437 return (STATE_CHANGED); 438 } 439 440 static int timed_lock_wait(char *set_lock_state) 441 { 442 int32_t status; 443 444 /* Only want one timer active at a time */ 445 do { 446 status = sem_wait(&timer_sem); 447 } while (status == -1 && errno == EINTR); 448 if (status == -1) 449 return (status); 450 451 while (timer_state != READY) 452 sched_yield(); 453 pthread_mutex_lock(&timer_mutex); 454 timer_state = HAVE_REQUEST; 455 pthread_cond_signal(&timer_cond); /* start timer */ 456 pthread_mutex_unlock(&timer_mutex); 457 458 /* 459 * We now spin checking the state env_lock_state for it to change to 460 * enabled. 461 */ 462 while (lock_state_loop(set_lock_state)) 463 sleep(1); 464 465 pthread_mutex_lock(&timer_mutex); 466 if (timer_state == ACTIVE) { 467 timer_state = NOT_READY; 468 pthread_cond_signal(&timer_cond); /* stop timer */ 469 } 470 if (timer_state == HAVE_REQUEST) { /* cancel request */ 471 timer_state = NOT_READY; 472 } 473 pthread_mutex_unlock(&timer_mutex); 474 sem_post(&timer_sem); 475 return (0); 476 } 477 478 static void lock_and_run(ETask_t *tp, int32_t obj_num) 479 { 480 int32_t status; 481 482 /* Grab mutex to stop the env_lock from being changed. */ 483 pthread_mutex_lock(&env_lock_mutex); 484 /* 485 * Check to see if the lock is anything but Enabled. If so, we then 486 * goto our timer routine to wait for it to become enabled. 487 * If not then set it to RUNNING and run policy. 488 */ 489 if (strcmp(env_lock_state, PSVC_LOCK_ENABLED) != 0) { 490 /* drop mutex and goto timer */ 491 pthread_mutex_unlock(&env_lock_mutex); 492 status = timed_lock_wait(PSVC_LOCK_RUNNING); 493 if (status == -1) { 494 syslog(LOG_ERR, SEM_WAIT_FAILED_MSG); 495 } 496 } else { 497 strlcpy(env_lock_state, PSVC_LOCK_RUNNING, LOCK_STRING_MAX); 498 pthread_mutex_unlock(&env_lock_mutex); 499 } 500 501 status = (*tp->funcp)(hdlp, (tp->obj_list + obj_num)->name); 502 if (status == PSVC_FAILURE && errno != ENODEV) { 503 char dev_name[32]; 504 505 psvc_get_attr(hdlp, (tp->obj_list + obj_num)->name, 506 PSVC_LABEL_ATTR, dev_name); 507 syslog(LOG_ERR, POLICY_FAILED_MSG, tp->routine, dev_name, 508 (tp->obj_list + obj_num)->name); 509 syslog(LOG_ERR, strerror(errno)); 510 } 511 512 /* The policy is done so set the lock back to ENABLED. */ 513 pthread_mutex_lock(&env_lock_mutex); 514 strlcpy(env_lock_state, PSVC_LOCK_ENABLED, LOCK_STRING_MAX); 515 pthread_mutex_unlock(&env_lock_mutex); 516 } 517 518 static void run_policies(EInterval_t *ip) 519 { 520 ETask_t *tp; 521 int32_t i, j; 522 523 do { 524 if (ip->interval) { 525 int remaining = ip->interval; 526 do { 527 remaining = sleep(remaining); 528 } while (remaining > 0); 529 } 530 for (i = 0; i < ip->num_tasks; ++i) { 531 tp = &ip->task_list[i]; 532 for (j = 0; j < tp->num_objects; ++j) { 533 lock_and_run(tp, j); 534 } 535 } 536 } while (ip->interval); 537 } 538 539 static void thread_setup(EInterval_t *ip) 540 { 541 int32_t status; 542 543 status = pthread_create(&ip->thread, NULL, (void *(*)())run_policies, 544 ip); 545 if (status != 0) { 546 if (debug_flag) 547 syslog(LOG_ERR, strerror(errno)); 548 exit(-1); 549 } 550 } 551 552 553 static int32_t load_policy(const char *library, const char *policy, 554 int32_t (**addr)(void *, char *)) 555 { 556 void *hp; 557 558 hp = dlopen(library, RTLD_NODELETE | RTLD_NOW | RTLD_GLOBAL); 559 if (hp == NULL) { 560 if (debug_flag) { 561 char *errstr = dlerror(); 562 syslog(LOG_ERR, errstr); 563 } 564 exit(1); 565 } 566 567 *addr = (int32_t (*)(void *, char *))dlsym(hp, policy); 568 if (*addr == NULL) { 569 if (debug_flag) { 570 char *errstr = dlerror(); 571 syslog(LOG_ERR, errstr); 572 } 573 exit(1); 574 } 575 576 (void) dlclose(hp); 577 return (0); 578 } 579 580 static int32_t get_timeout(FILE *fp, int *timeout) 581 { 582 char buf[BUFSZ]; 583 char name[32]; 584 char *cp; 585 586 /* skip blank lines */ 587 do { 588 cp = fgets(buf, BUFSZ, fp); 589 if (cp == NULL) 590 return (1); 591 while (isspace(*cp)) 592 ++cp; 593 sscanf(buf, "%s %d", name, timeout); 594 } while (*cp == 0 || *cp == '\n' || strcmp(name, "TIMEOUT") != 0); 595 596 if (strcmp(name, "TIMEOUT") != 0) { 597 errno = EINVAL; 598 return (-1); 599 } 600 return (0); 601 602 } 603 604 static int32_t load_interval(FILE *fp, EInterval_t **ipp) 605 { 606 char buf[BUFSZ]; 607 int32_t found; 608 EInterval_t *ip; 609 ETask_t *tp; 610 int32_t tasks; 611 int32_t status, i, j; 612 int32_t interval; 613 char name[32]; 614 char *cp; 615 616 /* skip blank lines */ 617 do { 618 cp = fgets(buf, BUFSZ, fp); 619 if (cp == NULL) 620 return (1); 621 while (isspace(*cp)) 622 ++cp; 623 } while (*cp == 0 || *cp == '\n'); 624 found = sscanf(buf, "%s %d %d", name, &interval, &tasks); 625 if (found != 3) { 626 errno = EINVAL; 627 return (-1); 628 } 629 630 if (strcmp(name, "INTERVAL") != 0) { 631 errno = EINVAL; 632 return (-1); 633 } 634 635 ip = (EInterval_t *)malloc(sizeof (EInterval_t)); 636 if (ip == NULL) 637 return (-1); 638 ip->num_tasks = tasks; 639 ip->interval = interval; 640 ip->next = NULL; 641 642 /* allocate and load table */ 643 ip->task_list = (ETask_t *)malloc(ip->num_tasks * sizeof (ETask_t)); 644 if (ip->task_list == NULL) 645 return (-1); 646 for (i = 0; i < ip->num_tasks; ++i) { 647 tp = &ip->task_list[i]; 648 649 (void) fgets(buf, BUFSZ, fp); 650 found = sscanf(buf, "%s %s %s", name, library, tp->routine); 651 if (found != 3) { 652 errno = EINVAL; 653 return (-1); 654 } 655 656 status = load_policy(library, tp->routine, &tp->funcp); 657 if (status == -1) 658 return (-1); 659 found = fscanf(fp, "%d", &tp->num_objects); 660 if (found != 1) { 661 if (debug_flag) 662 syslog(LOG_ERR, "No list of objects for task"); 663 errno = EINVAL; 664 return (-1); 665 } 666 tp->obj_list = 667 (EName_t *)malloc(tp->num_objects * sizeof (EName_t)); 668 if (tp->obj_list == NULL) 669 return (-1); 670 671 for (j = 0; j < tp->num_objects; ++j) { 672 found = fscanf(fp, "%s", tp->obj_list + j); 673 if (found != 1) { 674 if (debug_flag) 675 syslog(LOG_ERR, 676 "Wrong number of objects for task"); 677 errno = EINVAL; 678 return (-1); 679 } 680 } 681 (void) fgets(buf, BUFSZ, fp); /* reads newline on data line */ 682 (void) fgets(buf, BUFSZ, fp); 683 if (strncmp(buf, "TASK_END", 8) != 0) { 684 if (debug_flag) 685 syslog(LOG_ERR, "Expected TASK_END, task %s", 686 tp->routine); 687 errno = EINVAL; 688 return (-1); 689 } 690 } 691 692 (void) fgets(buf, BUFSZ, fp); 693 if (strncmp(buf, "INTERVAL_END", 12) != 0) { 694 if (debug_flag) 695 syslog(LOG_ERR, "Expected INTERVAL_END"); 696 errno = EINVAL; 697 return (-1); 698 } 699 700 *ipp = ip; 701 return (0); 702 } 703 704 705 void 706 init_daemon(void) 707 { 708 int32_t intervals = 0; 709 int32_t threads = 0; 710 int32_t status; 711 FILE *fp; 712 char filename[PATH_MAX]; 713 char platform[64]; 714 EInterval_t *ip, *prev; 715 716 if (sysinfo(SI_PLATFORM, platform, sizeof (platform)) == -1) { 717 if (debug_flag) 718 syslog(LOG_ERR, strerror(errno)); 719 return; 720 } 721 722 (void) sprintf(filename, "/usr/platform/%s/lib/platsvcd.conf", 723 platform); 724 if ((fp = fopen(filename, "r")) == NULL) { 725 if (debug_flag) 726 syslog(LOG_ERR, strerror(errno)); 727 return; 728 } 729 730 status = get_timeout(fp, &app_timeout); 731 if (status != 0) { 732 if (debug_flag) 733 syslog(LOG_ERR, strerror(errno)); 734 return; 735 } 736 737 status = sem_init(&timer_sem, 0, 1); 738 if (status == -1) { 739 if (debug_flag) 740 syslog(LOG_ERR, strerror(errno)); 741 return; 742 } 743 744 status = pthread_create(&timer_thread_id, NULL, 745 (void *(*)())timer_thread, 0); 746 if (status != 0) { 747 if (debug_flag) 748 syslog(LOG_ERR, strerror(errno)); 749 return; 750 } 751 752 /* get timer thread running */ 753 while (timer_state != READY) 754 sched_yield(); 755 756 for (;;) { 757 status = load_interval(fp, &ip); 758 if (status != 0) 759 break; 760 761 #ifdef lint 762 prev = NULL; 763 #endif 764 if (first_interval == 0) 765 first_interval = ip; 766 else 767 prev->next = ip; 768 prev = ip; 769 770 ++intervals; 771 if (ip->interval == 0) { 772 run_policies(ip); 773 } else { 774 thread_setup(ip); 775 ++threads; 776 } 777 } 778 if (intervals == 0) { 779 if (debug_flag) 780 syslog(LOG_ERR, "ERROR: No policies started"); 781 return; 782 } 783 784 if (status == -1) { 785 if (debug_flag) 786 syslog(LOG_ERR, strerror(errno)); 787 return; 788 } 789 790 return; 791 792 } 793 794 795 static int32_t count_records(FILE *fp, char *end, uint32_t *countp) 796 { 797 long first_record; 798 char *ret; 799 char buf[BUFSZ]; 800 uint32_t count = 0; 801 802 first_record = ftell(fp); 803 804 while ((ret = fgets(buf, BUFSZ, fp)) != NULL) { 805 if (strncmp(end, buf, strlen(end)) == 0) 806 break; 807 ++count; 808 } 809 810 if (ret == NULL) { 811 errno = EINVAL; 812 return (-1); 813 } 814 815 fseek(fp, first_record, SEEK_SET); 816 *countp = count; 817 return (0); 818 } 819 820 /* 821 * Find start of a section within the config file, 822 * Returns number of records in the section. 823 * FILE *fd is set to first data record within section. 824 */ 825 static int32_t 826 find_file_section(FILE *fd, char *start) 827 { 828 char *ret; 829 char buf[BUFSZ]; 830 char name[32]; 831 int found; 832 833 fseek(fd, 0, SEEK_SET); 834 while ((ret = fgets(buf, BUFSZ, fd)) != NULL) { 835 if (strncmp(start, buf, strlen(start)) == 0) 836 break; 837 } 838 839 if (ret == NULL) { 840 errno = EINVAL; 841 return (-1); 842 } 843 844 found = sscanf(buf, "%s", name); 845 if (found != 1) { 846 errno = EINVAL; 847 return (-1); 848 } else { 849 return (0); 850 } 851 852 } 853 854 static int32_t name_compare_qsort(picl_psvc_t *s1, picl_psvc_t *s2) 855 { 856 return (strcmp(s1->name, s2->name)); 857 } 858 859 static int32_t name_compare_bsearch(char *s1, picl_psvc_t *s2) 860 { 861 return (strcmp(s1, s2->name)); 862 } 863 864 /* 865 * Create a property and add it to the specified node. 866 * PICL will take a segmentation violation if a volatile property 867 * has a non-zero size. 868 */ 869 static int32_t node_property(picl_nodehdl_t node, 870 int (*read)(ptree_rarg_t *, void *), 871 int (*write)(ptree_warg_t *, const void *), picl_prop_type_t type, 872 unsigned int size, unsigned int accessmode, char *name, void *value) 873 { 874 ptree_propinfo_t propinfo; 875 picl_prophdl_t prophdl; 876 int err; 877 878 propinfo.version = PSVC_PLUGIN_VERSION; 879 if (accessmode & PICL_VOLATILE) { 880 propinfo.read = read; 881 propinfo.write = write; 882 } else { 883 propinfo.read = NULL; 884 propinfo.write = NULL; 885 } 886 propinfo.piclinfo.type = type; 887 propinfo.piclinfo.accessmode = accessmode; 888 propinfo.piclinfo.size = size; 889 strcpy(propinfo.piclinfo.name, name); 890 891 err = ptree_create_prop(&propinfo, value, &prophdl); 892 if (err != 0) { 893 return (err); 894 } 895 896 err = ptree_add_prop(node, prophdl); 897 if (err != 0) 898 return (err); 899 900 return (0); 901 } 902 903 static void init_err(char *fmt, char *arg1, char *arg2) 904 { 905 char msg[256]; 906 907 sprintf(msg, fmt, arg1, arg2); 908 syslog(LOG_ERR, msg); 909 } 910 911 static int 912 projected_lookup(picl_prophdl_t proph, struct proj_prop **dstp) 913 { 914 int i; 915 916 for (i = 0; i < proj_prop_count; ++i) { 917 if (prop_list[i].handle == proph) { 918 *dstp = &prop_list[i]; 919 return (PICL_SUCCESS); 920 } 921 } 922 923 return (PICL_INVALIDHANDLE); 924 } 925 926 int 927 projected_read(ptree_rarg_t *rarg, void *buf) 928 { 929 ptree_propinfo_t propinfo; 930 struct proj_prop *dstinfo; 931 int err; 932 933 err = projected_lookup(rarg->proph, &dstinfo); 934 if (err != 0) { 935 return (PICL_FAILURE); 936 } 937 938 939 err = ptree_get_propinfo(rarg->proph, &propinfo); 940 if (err != 0) 941 return (err); 942 err = ptree_get_propval_by_name(dstinfo->dst_node, 943 dstinfo->name, buf, propinfo.piclinfo.size); 944 if (err != 0) 945 return (err); 946 return (PICL_SUCCESS); 947 } 948 949 int 950 projected_write(ptree_warg_t *warg, const void *buf) 951 { 952 ptree_propinfo_t propinfo; 953 struct proj_prop *dstinfo; 954 int err; 955 956 err = projected_lookup(warg->proph, &dstinfo); 957 if (err != 0) { 958 return (PICL_FAILURE); 959 } 960 961 err = ptree_get_propinfo(warg->proph, &propinfo); 962 if (err != 0) 963 return (err); 964 err = ptree_update_propval_by_name(dstinfo->dst_node, 965 dstinfo->name, buf, propinfo.piclinfo.size); 966 if (err != 0) 967 return (err); 968 return (PICL_SUCCESS); 969 } 970 971 int 972 psvc_read_volatile(ptree_rarg_t *rarg, void *buf) 973 { 974 ptree_propinfo_t propinfo; 975 char name[32], class[32]; 976 int err, i; 977 int32_t attr_num = -1; 978 int32_t use_attr_num = 0; 979 980 err = ptree_get_propval_by_name(rarg->nodeh, "name", name, 981 sizeof (name)); 982 if (err != 0) { 983 return (err); 984 } 985 986 err = ptree_get_propval_by_name(rarg->nodeh, "_class", class, 987 sizeof (class)); 988 if (err != 0) { 989 return (err); 990 } 991 992 err = ptree_get_propinfo(rarg->proph, &propinfo); 993 if (err != 0) { 994 return (err); 995 } 996 997 for (i = 0; i < PICL_PROP_TRANS_COUNT; i++) { 998 if ((strcmp(class, picl_prop_trans[i].picl_class) == 0) && 999 (strcmp(propinfo.piclinfo.name, 1000 picl_prop_trans[i].picl_prop) == 0)) { 1001 attr_num = i; 1002 break; 1003 } 1004 } 1005 1006 if (attr_num == -1) 1007 for (i = 0; i < ATTR_STR_TAB_SIZE; i++) { 1008 if (strcmp(propinfo.piclinfo.name, 1009 attr_str_tab[i]) == 0) { 1010 attr_num = i; 1011 use_attr_num = 1; 1012 break; 1013 } 1014 } 1015 1016 if (use_attr_num) 1017 err = psvc_get_attr(hdlp, name, attr_num, buf); 1018 else 1019 err = psvc_get_attr(hdlp, name, 1020 picl_prop_trans[attr_num].psvc_prop, 1021 buf); 1022 1023 if (err != 0) { 1024 return (PICL_FAILURE); 1025 } 1026 return (PICL_SUCCESS); 1027 } 1028 1029 int 1030 psvc_write_volatile(ptree_warg_t *warg, const void *buf) 1031 { 1032 ptree_propinfo_t propinfo; 1033 char name[32], class[32]; 1034 int err, i; 1035 int32_t attr_num = -1; 1036 int32_t use_attr_num = 0; 1037 1038 if (warg->cred.dc_euid != 0) 1039 return (PICL_PERMDENIED); 1040 1041 err = ptree_get_propval_by_name(warg->nodeh, "name", name, 1042 sizeof (name)); 1043 if (err != 0) { 1044 return (err); 1045 } 1046 1047 err = ptree_get_propval_by_name(warg->nodeh, "_class", class, 1048 sizeof (class)); 1049 if (err != 0) { 1050 return (err); 1051 } 1052 1053 err = ptree_get_propinfo(warg->proph, &propinfo); 1054 if (err != 0) { 1055 return (err); 1056 } 1057 1058 for (i = 0; i < PICL_PROP_TRANS_COUNT; i++) { 1059 if ((strcmp(class, picl_prop_trans[i].picl_class) == 0) && 1060 (strcmp(propinfo.piclinfo.name, 1061 picl_prop_trans[i].picl_prop) == 0)) { 1062 attr_num = i; 1063 break; 1064 } 1065 } 1066 1067 if (attr_num == -1) 1068 for (i = 0; i < ATTR_STR_TAB_SIZE; i++) { 1069 if (strcmp(propinfo.piclinfo.name, 1070 attr_str_tab[i]) == 0) { 1071 attr_num = i; 1072 use_attr_num = 1; 1073 break; 1074 } 1075 } 1076 1077 if (use_attr_num) 1078 err = psvc_set_attr(hdlp, name, attr_num, (void *)buf); 1079 else 1080 err = psvc_set_attr(hdlp, name, 1081 picl_prop_trans[attr_num].psvc_prop, 1082 (void *)buf); 1083 1084 if (err != 0) { 1085 return (PICL_FAILURE); 1086 } 1087 1088 return (PICL_SUCCESS); 1089 } 1090 1091 void create_reference_properties(struct assoc_pair *assoc_tbl, int32_t count, 1092 char *assoc_name) 1093 { 1094 picl_psvc_t *aobjp, *dobjp; 1095 picl_prophdl_t tbl_hdl; 1096 picl_nodehdl_t *dep_list; 1097 ptree_propinfo_t propinfo; 1098 char *funcname = "create_reference_properties"; 1099 char name[PICL_PROPNAMELEN_MAX]; 1100 int32_t i, j, offset; 1101 int32_t dependents; 1102 int32_t err; 1103 char class[PICL_CLASSNAMELEN_MAX]; 1104 1105 for (i = 0; i < count; ++i) { 1106 /* antecedent */ 1107 aobjp = (picl_psvc_t *)bsearch(assoc_tbl[i].antecedent, 1108 psvc_hdl.objects, psvc_hdl.obj_count, 1109 sizeof (picl_psvc_t), 1110 (int (*)(const void *, const void *)) 1111 name_compare_bsearch); 1112 if (aobjp == NULL) { 1113 init_err(ID_NOT_FOUND_MSG, 1114 funcname, assoc_tbl[i].antecedent); 1115 return; 1116 } 1117 1118 /* skip if table already created */ 1119 if (ptree_get_propval_by_name(aobjp->node, assoc_name, 1120 &tbl_hdl, sizeof (tbl_hdl)) == 0) { 1121 continue; 1122 } 1123 1124 /* create a new table */ 1125 err = ptree_create_table(&tbl_hdl); 1126 if (err != 0) { 1127 init_err(PTREE_CREATE_TABLE_FAILED_MSG, 1128 funcname, picl_strerror(err)); 1129 return; 1130 } 1131 1132 err = node_property(aobjp->node, NULL, NULL, 1133 PICL_PTYPE_TABLE, sizeof (tbl_hdl), PICL_READ, 1134 assoc_name, &tbl_hdl); 1135 if (err != 0) { 1136 init_err(CREATE_PROP_FAILED_MSG, funcname, 1137 picl_strerror(err)); 1138 return; 1139 } 1140 1141 /* determine number of elements in the table */ 1142 dependents = 0; 1143 for (j = i; j < count; ++j) { 1144 if (strcmp(aobjp->name, assoc_tbl[j].antecedent) == 0) 1145 ++dependents; 1146 } 1147 1148 dep_list = (picl_nodehdl_t *)malloc(sizeof (picl_nodehdl_t) * 1149 dependents); 1150 if (dep_list == NULL) { 1151 init_err(MALLOC_FAILED_MSG, funcname, strerror(errno)); 1152 return; 1153 } 1154 /* build row of reference properties */ 1155 offset = 0; 1156 for (j = i; j < count; ++j) { 1157 if (strcmp(aobjp->name, assoc_tbl[j].antecedent) != 0) 1158 continue; 1159 1160 dobjp = (picl_psvc_t *)bsearch(assoc_tbl[j].dependent, 1161 psvc_hdl.objects, 1162 psvc_hdl.obj_count, sizeof (picl_psvc_t), 1163 (int (*)(const void *, const void *)) 1164 name_compare_bsearch); 1165 if (dobjp == NULL) { 1166 init_err(ID_NOT_FOUND_MSG, 1167 funcname, assoc_tbl[j].dependent); 1168 return; 1169 } 1170 1171 /* 1172 * Reference property name must be 1173 * _classname_propertyname 1174 */ 1175 err = ptree_get_propval_by_name(dobjp->node, 1176 "_class", class, sizeof (class)); 1177 if (err != 0) { 1178 init_err(CLASS_NOT_FOUND_MSG, funcname, 1179 assoc_tbl[j].dependent); 1180 return; 1181 } 1182 1183 sprintf(name, "_%s_%s", class, "subclass"); 1184 1185 propinfo.version = PSVC_PLUGIN_VERSION; 1186 propinfo.read = NULL; 1187 propinfo.write = NULL; 1188 propinfo.piclinfo.type = PICL_PTYPE_REFERENCE; 1189 propinfo.piclinfo.accessmode = PICL_READ; 1190 propinfo.piclinfo.size = sizeof (picl_nodehdl_t); 1191 strcpy(propinfo.piclinfo.name, name); 1192 1193 err = ptree_create_prop(&propinfo, &dobjp->node, 1194 dep_list + offset); 1195 if (err != 0) { 1196 init_err(PTREE_CREATE_PROP_FAILED_MSG, 1197 name, picl_strerror(err)); 1198 return; 1199 } 1200 1201 ++offset; 1202 } 1203 1204 /* add row to table */ 1205 err = ptree_add_row_to_table(tbl_hdl, dependents, dep_list); 1206 if (err != 0) { 1207 init_err(PTREE_ADD_ROW_FAILED_MSG, funcname, 1208 picl_strerror(err)); 1209 return; 1210 } 1211 1212 } 1213 1214 1215 } 1216 1217 /* Load projected properties */ 1218 static void 1219 load_projected_properties(FILE *fp) 1220 { 1221 int32_t found; 1222 ptree_propinfo_t propinfo; 1223 ptree_propinfo_t dstinfo; 1224 picl_prophdl_t src_prophdl, dst_prophdl; 1225 picl_nodehdl_t src_node, dst_node; 1226 int err, i; 1227 picl_psvc_t *srcobjp, *dstobjp; 1228 char src[32], dst[256]; 1229 char src_prop[32], dst_prop[32]; 1230 char buf[BUFSZ]; 1231 char *funcname = "load_projected_properties"; 1232 1233 if (find_file_section(fp, "PROJECTED_PROPERTIES") != 0) 1234 return; 1235 1236 if (count_records(fp, "PROJECTED_PROPERTIES_END", &proj_prop_count) != 1237 0) { 1238 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0); 1239 return; 1240 } 1241 1242 prop_list = (struct proj_prop *)malloc(sizeof (struct proj_prop) 1243 * proj_prop_count); 1244 if (prop_list == NULL) { 1245 init_err(MALLOC_FAILED_MSG, funcname, strerror(errno)); 1246 return; 1247 } 1248 1249 for (i = 0; i < proj_prop_count; ++i) { 1250 fgets(buf, BUFSZ, fp); 1251 found = sscanf(buf, "%s %s %s %s", src, src_prop, dst, 1252 dst_prop); 1253 if (found != 4) { 1254 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0); 1255 return; 1256 } 1257 1258 /* find src node */ 1259 if (src[0] == '/') { 1260 /* picl node name, outside psvc subtree */ 1261 err = ptree_get_node_by_path(src, &src_node); 1262 if (err != 0) { 1263 init_err(NODE_NOT_FOUND_MSG, funcname, src); 1264 return; 1265 } 1266 } else { 1267 srcobjp = (picl_psvc_t *)bsearch(src, psvc_hdl.objects, 1268 psvc_hdl.obj_count, sizeof (picl_psvc_t), 1269 (int (*)(const void *, const void *)) 1270 name_compare_bsearch); 1271 if (srcobjp == NULL) { 1272 init_err(ID_NOT_FOUND_MSG, funcname, src); 1273 return; 1274 } 1275 src_node = srcobjp->node; 1276 } 1277 1278 /* find dest node */ 1279 if (dst[0] == '/') { 1280 /* picl node name, outside psvc subtree */ 1281 err = ptree_get_node_by_path(dst, &dst_node); 1282 if (err != 0) { 1283 init_err(NODE_NOT_FOUND_MSG, funcname, dst); 1284 return; 1285 } 1286 prop_list[i].dst_node = dst_node; 1287 } else { 1288 dstobjp = (picl_psvc_t *)bsearch(dst, psvc_hdl.objects, 1289 psvc_hdl.obj_count, sizeof (picl_psvc_t), 1290 (int (*)(const void *, const void *)) 1291 name_compare_bsearch); 1292 if (dstobjp == NULL) { 1293 init_err(ID_NOT_FOUND_MSG, funcname, dst); 1294 return; 1295 } 1296 dst_node = dstobjp->node; 1297 prop_list[i].dst_node = dst_node; 1298 } 1299 1300 /* determine destination property size */ 1301 err = ptree_get_first_prop(dst_node, &dst_prophdl); 1302 while (err == 0) { 1303 err = ptree_get_propinfo(dst_prophdl, &dstinfo); 1304 if (err != 0) 1305 break; 1306 if (strcmp(dst_prop, dstinfo.piclinfo.name) == 0) 1307 break; 1308 err = ptree_get_next_prop(dst_prophdl, &dst_prophdl); 1309 } 1310 if (err != 0) { 1311 init_err(SIZE_NOT_FOUND_MSG, funcname, dst_prop); 1312 return; 1313 } 1314 1315 propinfo.version = PSVC_PLUGIN_VERSION; 1316 propinfo.read = projected_read; 1317 propinfo.write = projected_write; 1318 propinfo.piclinfo.type = dstinfo.piclinfo.type; 1319 propinfo.piclinfo.accessmode = 1320 PICL_READ | PICL_WRITE | PICL_VOLATILE; 1321 propinfo.piclinfo.size = dstinfo.piclinfo.size; 1322 strcpy(propinfo.piclinfo.name, src_prop); 1323 1324 err = ptree_create_prop(&propinfo, 0, &src_prophdl); 1325 if (err != 0) { 1326 init_err(PTREE_CREATE_PROP_FAILED_MSG, funcname, 1327 picl_strerror(err)); 1328 return; 1329 } 1330 1331 err = ptree_add_prop(src_node, src_prophdl); 1332 if (err != 0) { 1333 init_err(PTREE_ADD_PROP_FAILED_MSG, funcname, 1334 picl_strerror(err)); 1335 return; 1336 } 1337 1338 prop_list[i].handle = src_prophdl; 1339 strcpy(prop_list[i].name, dst_prop); 1340 1341 } 1342 } 1343 1344 /* Load the association table */ 1345 static void load_associations(FILE *fp) 1346 { 1347 char *funcname = "load_associations"; 1348 uint32_t count; 1349 int found; 1350 int j; 1351 char assoc_name[32]; 1352 struct assoc_pair *assoc_tbl; 1353 char name1[32]; 1354 char buf[BUFSZ]; 1355 1356 /* 1357 * ignore count in the file, correct count is highest 1358 * association id + 1, now figured when loading ASSOC_STR 1359 * section. 1360 */ 1361 if (find_file_section(fp, "ASSOCIATIONS") != 0) 1362 return; 1363 1364 fgets(buf, BUFSZ, fp); 1365 while (strncmp("ASSOCIATIONS_END", buf, 16) != 0) { 1366 found = sscanf(buf, "%s %s", name1, assoc_name); 1367 if (found != 2) { 1368 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0); 1369 return; 1370 } 1371 1372 if (count_records(fp, "ASSOCIATION_END", &count) != 0) { 1373 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0); 1374 return; 1375 } 1376 1377 assoc_tbl = (struct assoc_pair *)malloc( 1378 sizeof (struct assoc_pair) * count); 1379 if (assoc_tbl == NULL) { 1380 init_err(MALLOC_FAILED_MSG, funcname, strerror(errno)); 1381 return; 1382 } 1383 1384 for (j = 0; j < count; ++j) { 1385 fgets(buf, BUFSZ, fp); 1386 found = sscanf(buf, "%s %s", assoc_tbl[j].antecedent, 1387 assoc_tbl[j].dependent); 1388 if (found != 2) { 1389 init_err(INVALID_FILE_FORMAT_MSG, funcname, 1390 0); 1391 return; 1392 } 1393 1394 } 1395 1396 fgets(buf, BUFSZ, fp); 1397 if (strncmp(buf, "ASSOCIATION_END", 15) != 0) { 1398 init_err(INVALID_FILE_FORMAT_MSG, funcname, 0); 1399 return; 1400 } 1401 1402 /* Create separate list of dependents for each antecedent */ 1403 if (strcmp(assoc_name, "PSVC_TABLE") != 0) { 1404 create_reference_properties(assoc_tbl, count, 1405 assoc_name); 1406 } 1407 1408 free(assoc_tbl); 1409 1410 fgets(buf, BUFSZ, fp); 1411 } 1412 1413 } 1414 1415 /* Enviornmental Lock Object's Read and Write routine */ 1416 static int 1417 env_lock_read(ptree_rarg_t *rarg, void *buf) 1418 { 1419 strlcpy((char *)buf, env_lock_state, LOCK_STRING_MAX); 1420 return (PSVC_SUCCESS); 1421 } 1422 1423 static int 1424 env_lock_write(ptree_warg_t *warg, const void *buf) 1425 { 1426 int32_t status = PSVC_SUCCESS; 1427 char *var = (char *)buf; 1428 1429 /* 1430 * Check to make sure that the value is either Disabled or Enabled 1431 * as these are the only 2 states that this object can be set to. 1432 */ 1433 if ((strcmp(var, PSVC_LOCK_DISABLED) != 0) && 1434 (strcmp(var, PSVC_LOCK_ENABLED) != 0)) { 1435 errno = EINVAL; 1436 return (PSVC_FAILURE); 1437 } 1438 1439 pthread_mutex_lock(&env_lock_mutex); 1440 1441 /* 1442 * If the state is already Enabled we can set the state to Disabled 1443 * to stop the policies. 1444 */ 1445 if (strcmp(env_lock_state, PSVC_LOCK_ENABLED) == 0) { 1446 pthread_mutex_unlock(&env_lock_mutex); 1447 status = timed_lock_wait(PSVC_LOCK_DISABLED); 1448 if (status == -1) { 1449 syslog(LOG_ERR, SEM_WAIT_FAILED_MSG); 1450 } 1451 return (status); 1452 } 1453 1454 /* 1455 * If the state is Running we must go into timed_lock_wait to aquire 1456 * the env_lock. 1457 */ 1458 if (strcmp(env_lock_state, PSVC_LOCK_RUNNING) == 0) { 1459 pthread_mutex_unlock(&env_lock_mutex); 1460 status = timed_lock_wait(PSVC_LOCK_DISABLED); 1461 if (status == -1) { 1462 syslog(LOG_ERR, SEM_WAIT_FAILED_MSG); 1463 } 1464 return (status); 1465 } 1466 1467 /* 1468 * If the state is already Disabled we need to first check to see if 1469 * we are resetting it to Disabled or changing it to Enabled. If we 1470 * are resetting it to Disabled then we need to stop the timer and 1471 * restart it. If we are changing it to Enabled we just set it to 1472 * enabled. 1473 */ 1474 if (strcmp(env_lock_state, PSVC_LOCK_DISABLED) == 0) { 1475 if (strcmp(var, PSVC_LOCK_DISABLED) == 0) { 1476 pthread_mutex_lock(&timer_mutex); 1477 if (timer_state == ACTIVE) { 1478 timer_state = NOT_READY; 1479 /* stop timer */ 1480 pthread_cond_signal(&timer_cond); 1481 pthread_mutex_unlock(&timer_mutex); 1482 /* wait for timer to reset */ 1483 while (timer_state != READY) 1484 sched_yield(); 1485 pthread_mutex_lock(&timer_mutex); 1486 timer_state = HAVE_REQUEST; 1487 /* restart timer */ 1488 pthread_cond_signal(&timer_cond); 1489 } 1490 pthread_mutex_unlock(&timer_mutex); 1491 } else { 1492 strlcpy(env_lock_state, var, LOCK_STRING_MAX); 1493 } 1494 } 1495 pthread_mutex_unlock(&env_lock_mutex); 1496 return (PSVC_SUCCESS); 1497 } 1498 1499 static int 1500 init_env_lock_node(picl_nodehdl_t root_node) 1501 { 1502 int err; 1503 ptree_propinfo_t propinfo; 1504 char *funcname = "init_env_lock_node"; 1505 1506 /* Here we are creating a Enviornmental Lock Node */ 1507 err = ptree_create_node("/plugins/environmental", "picl", &lock_node); 1508 if (err != PICL_SUCCESS) { 1509 init_err(PTREE_CREATE_NODE_FAILED_MSG, funcname, 1510 picl_strerror(err)); 1511 return (err); 1512 } 1513 1514 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION_1, 1515 PICL_PTYPE_CHARSTRING, PICL_READ | PICL_WRITE | PICL_VOLATILE, 1516 32, "State", env_lock_read, env_lock_write); 1517 if (err != PICL_SUCCESS) { 1518 init_err(NODE_PROP_FAILED_MSG, funcname, picl_strerror(err)); 1519 return (err); 1520 } 1521 1522 err = ptree_create_and_add_prop(lock_node, &propinfo, 1523 NULL, NULL); 1524 if (err != PICL_SUCCESS) { 1525 init_err(PTREE_ADD_PROP_FAILED_MSG, funcname, 1526 picl_strerror(err)); 1527 return (err); 1528 } 1529 1530 err = ptree_add_node(root_node, lock_node); 1531 if (err != PICL_SUCCESS) { 1532 init_err(PTREE_ADD_NODE_FAILED_MSG, funcname, 1533 picl_strerror(err)); 1534 return (err); 1535 } 1536 1537 return (PSVC_SUCCESS); 1538 } 1539 1540 void 1541 psvc_plugin_init(void) 1542 { 1543 struct classinfo *cp; 1544 picl_nodehdl_t root_node; 1545 picl_nodehdl_t parent_node; 1546 char *funcname = "psvc_plugin_init"; 1547 char platform[32]; 1548 char filename[256]; 1549 char buf[BUFSZ]; 1550 int32_t i, j; 1551 int err, found; 1552 1553 psvc_paths = NULL; 1554 psvc_hdl.obj_count = 0; 1555 psvc_hdl.objects = NULL; 1556 psvc_hdl.fp = NULL; 1557 first_interval = NULL; 1558 1559 /* 1560 * So the volatile read/write routines can retrieve data from 1561 * psvc or picl 1562 */ 1563 err = psvc_init(&hdlp); 1564 if (err != 0) { 1565 init_err(PSVC_INIT_ERR_MSG, funcname, strerror(errno)); 1566 } 1567 1568 if (sysinfo(SI_PLATFORM, platform, sizeof (platform)) == -1) { 1569 init_err(SYSINFO_FAILED_MSG, funcname, 0); 1570 return; 1571 } 1572 1573 sprintf(filename, "/usr/platform/%s/lib/psvcobj.conf", platform); 1574 if ((psvc_hdl.fp = fopen(filename, "r")) == NULL) { 1575 init_err(FILE_OPEN_FAILED_MSG, funcname, filename); 1576 return; 1577 } 1578 1579 /* Create all PICL nodes */ 1580 if (find_file_section(psvc_hdl.fp, "OBJECT_INFO") == -1) { 1581 init_err(INVALID_FILE_FORMAT1_MSG, funcname, filename); 1582 return; 1583 } 1584 if (count_records(psvc_hdl.fp, "OBJECT_INFO_END", &psvc_hdl.obj_count) 1585 == -1) { 1586 init_err(INVALID_FILE_FORMAT1_MSG, funcname, filename); 1587 return; 1588 } 1589 if ((psvc_hdl.objects = (picl_psvc_t *)malloc(sizeof (picl_psvc_t) * 1590 psvc_hdl.obj_count)) == NULL) { 1591 init_err(MALLOC_FAILED_MSG, funcname, strerror(errno)); 1592 return; 1593 } 1594 memset(psvc_hdl.objects, 0, sizeof (picl_psvc_t) * psvc_hdl.obj_count); 1595 1596 err = ptree_get_root(&root_node); 1597 if (err != 0) { 1598 init_err(PTREE_GET_ROOT_FAILED_MSG, funcname, 1599 picl_strerror(err)); 1600 return; 1601 } 1602 1603 /* Following array is accessed directly by the psvc policies. */ 1604 psvc_paths = (psvc_name_t *)malloc(sizeof (psvc_name_t) * 1605 psvc_hdl.obj_count); 1606 psvc_picl_nodes = psvc_hdl.obj_count; 1607 if (psvc_paths == NULL) { 1608 init_err(MALLOC_FAILED_MSG, funcname, strerror(errno)); 1609 return; 1610 } 1611 for (i = 0; i < psvc_hdl.obj_count; ++i) { 1612 char *start; 1613 int32_t class; 1614 int32_t subclass; 1615 int32_t cp_count; 1616 picl_psvc_t *objp = &psvc_hdl.objects[i]; 1617 1618 fgets(buf, BUFSZ, psvc_hdl.fp); 1619 if (strncmp(buf, "OBJECT_INFO_END", 15) == 0) 1620 break; 1621 1622 start = strrchr(buf, '/'); 1623 if (start == NULL) { 1624 init_err(INVALID_FILE_FORMAT1_MSG, funcname, 1625 filename); 1626 return; 1627 } 1628 found = sscanf(start + 1, "%s", objp->name); 1629 if (found != 1) { 1630 init_err(INVALID_FILE_FORMAT1_MSG, funcname, 1631 filename); 1632 return; 1633 } 1634 1635 /* get class */ 1636 err = psvc_get_attr(hdlp, objp->name, PSVC_CLASS_ATTR, &class); 1637 if (err != PSVC_SUCCESS) { 1638 init_err(CLASS_NOT_FOUND_MSG, funcname, objp->name); 1639 return; 1640 } 1641 if (class > NUM_CLASSES) { 1642 init_err(UNKNOWN_CLASS_MSG, funcname, 0); 1643 return; 1644 } 1645 1646 err = psvc_get_attr(hdlp, objp->name, PSVC_SUBCLASS_ATTR, 1647 &subclass); 1648 if (err != PSVC_SUCCESS) { 1649 init_err(SUBCLASS_NOT_FOUND_MSG, funcname, objp->name); 1650 return; 1651 } 1652 1653 err = ptree_create_node(objp->name, class_name[class], 1654 &objp->node); 1655 if (err != 0) { 1656 init_err(PTREE_CREATE_NODE_FAILED_MSG, funcname, 1657 picl_strerror(err)); 1658 return; 1659 } 1660 if (strcmp(objp->name, PSVC_CHASSIS) == 0) 1661 system_node = objp->node; 1662 1663 for (j = 0; j < COMMON_COUNT; ++j) { 1664 1665 err = node_property(objp->node, 1666 common[j].access & PICL_READ ? 1667 psvc_read_volatile : 0, 1668 common[j].access & PICL_WRITE ? 1669 psvc_write_volatile : 0, 1670 common[j].type, common[j].size, 1671 common[j].access, common[j].name, 0); 1672 if (err != PSVC_SUCCESS) { 1673 init_err(NODE_PROP_FAILED_MSG, funcname, 1674 picl_strerror(err)); 1675 return; 1676 } 1677 } 1678 cp = &class_properties[class]; 1679 /* Locator LED Support */ 1680 if (class == 2 && subclass == 2) { 1681 cp_count = 3; 1682 } else { 1683 cp_count = cp->count; 1684 } 1685 1686 for (j = 0; j < cp_count; ++j) { 1687 err = node_property(objp->node, psvc_read_volatile, 1688 psvc_write_volatile, cp->props[j].type, 1689 cp->props[j].size, 1690 cp->props[j].access, cp->props[j].name, 0); 1691 if (err != PSVC_SUCCESS) { 1692 init_err(NODE_PROP_FAILED_MSG, funcname, 1693 picl_strerror(err)); 1694 return; 1695 } 1696 } 1697 1698 /* Link the nodes into the PICL tree */ 1699 *start = 0; 1700 if (start == buf) { /* no parent */ 1701 parent_node = root_node; 1702 } else { 1703 err = ptree_get_node_by_path(buf, &parent_node); 1704 if (err != PICL_SUCCESS) { 1705 init_err(NODE_NOT_FOUND_MSG, funcname, buf); 1706 return; 1707 } 1708 } 1709 1710 err = ptree_add_node(parent_node, objp->node); 1711 if (err != PICL_SUCCESS) { 1712 init_err(PTREE_ADD_NODE_FAILED_MSG, funcname, 1713 picl_strerror(err)); 1714 return; 1715 } 1716 strcpy(psvc_paths[i].parent_path, buf); 1717 strcpy(psvc_paths[i].child_name, objp->name); 1718 psvc_paths[i].child_node = objp->node; 1719 } 1720 1721 qsort(psvc_hdl.objects, psvc_hdl.obj_count, sizeof (picl_psvc_t), 1722 (int (*)(const void *, const void *))name_compare_qsort); 1723 1724 load_associations(psvc_hdl.fp); 1725 load_projected_properties(psvc_hdl.fp); 1726 1727 if (init_env_lock_node(root_node) != PSVC_SUCCESS) 1728 return; 1729 1730 init_daemon(); 1731 1732 init_done = 1; 1733 1734 } 1735 1736 void 1737 psvc_plugin_fini(void) 1738 { 1739 int32_t i; 1740 EInterval_t *ip, *next; 1741 1742 /* Fix memory leaks */ 1743 free(prop_list); 1744 free(psvc_paths); 1745 for (ip = first_interval; ip != 0; ip = next) { 1746 /* 1747 * We don't check return types. 1748 * If this call fails, it's because we did not 1749 * run thread_setup() on this particular ip 1750 * 1751 * Please refer to init_daemon() for thread 1752 * assignments 1753 */ 1754 pthread_cancel(ip->thread); 1755 for (i = 0; i < ip->num_tasks; ++i) 1756 free(ip->task_list[i].obj_list); 1757 free(ip->task_list); 1758 1759 next = ip->next; 1760 free(ip); 1761 } 1762 1763 psvc_fini(hdlp); 1764 } 1765 1766 void 1767 psvc_plugin_register(void) 1768 { 1769 picld_plugin_register(&psvc_reg); 1770 } 1771