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 /* 23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include "libscf_impl.h" 27 28 #include <assert.h> 29 #include <strings.h> 30 31 /* 32 * Errors returned by smf_notify_{del|get|set}_params() 33 */ 34 static const scf_error_t errs_1[] = { 35 SCF_ERROR_BACKEND_ACCESS, 36 SCF_ERROR_BACKEND_READONLY, 37 SCF_ERROR_CONNECTION_BROKEN, 38 SCF_ERROR_DELETED, 39 SCF_ERROR_INTERNAL, 40 SCF_ERROR_INVALID_ARGUMENT, 41 SCF_ERROR_NO_MEMORY, 42 SCF_ERROR_NO_RESOURCES, 43 SCF_ERROR_NOT_FOUND, 44 SCF_ERROR_PERMISSION_DENIED, 45 0 46 }; 47 48 /* 49 * Errors returned by smf_notify_{del|get|set}_params() 50 * Except SCF_ERROR_INVALID_ARGUMENT 51 */ 52 static const scf_error_t errs_2[] = { 53 SCF_ERROR_BACKEND_ACCESS, 54 SCF_ERROR_BACKEND_READONLY, 55 SCF_ERROR_CONNECTION_BROKEN, 56 SCF_ERROR_DELETED, 57 SCF_ERROR_INTERNAL, 58 SCF_ERROR_NO_MEMORY, 59 SCF_ERROR_NO_RESOURCES, 60 SCF_ERROR_NOT_FOUND, 61 SCF_ERROR_PERMISSION_DENIED, 62 0 63 }; 64 65 /* 66 * Helper function that abort() on unexpected errors. 67 * The expected error set is a zero-terminated array of scf_error_t 68 */ 69 static int 70 check_scf_error(scf_error_t e, const scf_error_t *errs) 71 { 72 if (ismember(e, errs)) 73 return (1); 74 75 assert(0); 76 abort(); 77 78 /*NOTREACHED*/ 79 } 80 81 /* 82 * Mapping of state transition to pgname. 83 */ 84 static struct st_pgname { 85 const char *st_pgname; 86 int32_t st_state; 87 } st_pgnames[] = { 88 { "to-uninitialized", SCF_TRANS(0, SCF_STATE_UNINIT) }, 89 { "from-uninitialized", SCF_TRANS(SCF_STATE_UNINIT, 0) }, 90 { "to-maintenance", SCF_TRANS(0, SCF_STATE_MAINT) }, 91 { "from-maintenance", SCF_TRANS(SCF_STATE_MAINT, 0) }, 92 { "to-offline", SCF_TRANS(0, SCF_STATE_OFFLINE) }, 93 { "from-offline", SCF_TRANS(SCF_STATE_OFFLINE, 0) }, 94 { "to-disabled", SCF_TRANS(0, SCF_STATE_DISABLED) }, 95 { "from-disabled", SCF_TRANS(SCF_STATE_DISABLED, 0) }, 96 { "to-online", SCF_TRANS(0, SCF_STATE_ONLINE) }, 97 { "from-online", SCF_TRANS(SCF_STATE_ONLINE, 0) }, 98 { "to-degraded", SCF_TRANS(0, SCF_STATE_DEGRADED) }, 99 { "from-degraded", SCF_TRANS(SCF_STATE_DEGRADED, 0) }, 100 { NULL, 0 } 101 }; 102 103 /* 104 * Check if class matches or is a subclass of SCF_SVC_TRANSITION_CLASS 105 * 106 * returns 1, otherwise return 0 107 */ 108 static boolean_t 109 is_svc_stn(const char *class) 110 { 111 int n = strlen(SCF_SVC_TRANSITION_CLASS); 112 113 if (class && strncmp(class, SCF_SVC_TRANSITION_CLASS, n) == 0) 114 if (class[n] == '\0' || class[n] == '.') 115 return (1); 116 return (0); 117 } 118 119 /* 120 * Return the len of the base class. For instance, "class.class1.class2.*" 121 * will return the length of "class.class1.class2" 122 * This function does not check if the class or base class is valid. 123 * A class such as "class.class1....****" is not valid but will return the 124 * length of "class.class1....***" 125 */ 126 static size_t 127 base_class_len(const char *c) 128 { 129 const char *p; 130 size_t n; 131 132 if ((n = strlen(c)) == 0) 133 return (0); 134 135 p = c + n; 136 137 /* get rid of any trailing asterisk */ 138 if (*--p == '*') 139 n--; 140 141 /* make sure the class doesn't end in '.' */ 142 while (p >= c && *--p == '.') 143 n--; 144 145 return (n); 146 } 147 148 /* 149 * Allocates and builds the pgname for an FMA dotted class. 150 * The pgname will be of the form "class.class1.class2,SCF_NOTIFY_PG_POSTFIX" 151 * 152 * NULL on error 153 */ 154 static char * 155 class_to_pgname(const char *class) 156 { 157 size_t n; 158 ssize_t sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1; 159 char *pgname = NULL; 160 161 n = base_class_len(class); 162 163 if (n == 0) { 164 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 165 return (NULL); 166 } 167 168 if ((pgname = malloc(sz)) == NULL) { 169 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 170 goto error; 171 } 172 173 if (snprintf(pgname, sz, "%.*s,%s", (int)n, class, 174 SCF_NOTIFY_PG_POSTFIX) >= sz) { 175 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 176 goto error; 177 } 178 return (pgname); 179 180 error: 181 free(pgname); 182 pgname = NULL; 183 184 return (pgname); 185 } 186 187 /* 188 * Get the pg from the running snapshot of the instance (composed or not) 189 */ 190 static int 191 get_pg(scf_service_t *s, scf_instance_t *i, const char *n, 192 scf_propertygroup_t *pg, int composed) 193 { 194 scf_handle_t *h = scf_instance_handle(i); 195 scf_error_t scf_e = scf_error(); 196 scf_snapshot_t *snap = scf_snapshot_create(h); 197 scf_snaplevel_t *slvl = scf_snaplevel_create(h); 198 int r = -1; 199 200 if (h == NULL) { 201 /* 202 * Use the error stored in scf_e 203 */ 204 (void) scf_set_error(scf_e); 205 goto out; 206 } 207 if (s == NULL) { 208 if (snap == NULL || slvl == NULL) 209 goto out; 210 if (scf_instance_get_snapshot(i, "running", snap) != 0) 211 goto out; 212 213 if (composed) { 214 if (scf_instance_get_pg_composed(i, snap, n, pg) != 0) 215 goto out; 216 } else { 217 if (scf_snapshot_get_base_snaplevel(snap, slvl) != 0 || 218 scf_snaplevel_get_pg(slvl, n, pg) != 0) 219 goto out; 220 } 221 } else { 222 if (scf_service_get_pg(s, n, pg) != 0) 223 goto out; 224 } 225 226 r = 0; 227 out: 228 scf_snaplevel_destroy(slvl); 229 scf_snapshot_destroy(snap); 230 231 return (r); 232 } 233 234 /* 235 * Add a pg if it does not exist, or get it if it exists. 236 * It operates on the instance if the service parameter is NULL. 237 * 238 * returns 0 on success or -1 on failure 239 */ 240 static int 241 get_or_add_pg(scf_service_t *s, scf_instance_t *i, const char *n, const char *t, 242 uint32_t flags, scf_propertygroup_t *pg) 243 { 244 int r; 245 246 if (s == NULL) 247 r = scf_instance_add_pg(i, n, t, flags, pg); 248 else 249 r = scf_service_add_pg(s, n, t, flags, pg); 250 251 if (r == 0) 252 return (0); 253 else if (scf_error() != SCF_ERROR_EXISTS) 254 return (-1); 255 256 if (s == NULL) 257 r = scf_instance_get_pg(i, n, pg); 258 else 259 r = scf_service_get_pg(s, n, pg); 260 261 return (r); 262 } 263 264 /* 265 * Delete the property group form the instance or service. 266 * If service is NULL, use instance, otherwise use only the service. 267 * 268 * Return SCF_SUCCESS or SCF_FAILED on 269 * SCF_ERROR_BACKEND_ACCESS 270 * SCF_ERROR_BACKEND_READONLY 271 * SCF_ERROR_CONNECTION_BROKEN 272 * SCF_ERROR_DELETED 273 * SCF_ERROR_HANDLE_MISMATCH 274 * SCF_ERROR_INTERNAL 275 * SCF_ERROR_INVALID_ARGUMENT 276 * SCF_ERROR_NO_RESOURCES 277 * SCF_ERROR_NOT_BOUND 278 * SCF_ERROR_NOT_FOUND 279 * SCF_ERROR_NOT_SET 280 * SCF_ERROR_PERMISSION_DENIED 281 */ 282 static int 283 del_pg(scf_service_t *s, scf_instance_t *i, const char *n, 284 scf_propertygroup_t *pg) 285 { 286 if ((s == NULL ? scf_instance_get_pg(i, n, pg) : 287 scf_service_get_pg(s, n, pg)) != SCF_SUCCESS) 288 if (scf_error() == SCF_ERROR_NOT_FOUND) 289 return (SCF_SUCCESS); 290 else 291 return (SCF_FAILED); 292 293 if (scf_pg_delete(pg) != SCF_SUCCESS) 294 if (scf_error() == SCF_ERROR_DELETED) 295 return (SCF_SUCCESS); 296 else 297 return (SCF_FAILED); 298 299 return (SCF_SUCCESS); 300 } 301 302 static scf_type_t 303 get_scf_type(nvpair_t *p) 304 { 305 switch (nvpair_type(p)) { 306 case DATA_TYPE_BOOLEAN: 307 case DATA_TYPE_BOOLEAN_VALUE: 308 case DATA_TYPE_BOOLEAN_ARRAY: 309 return (SCF_TYPE_BOOLEAN); 310 311 case DATA_TYPE_BYTE: 312 case DATA_TYPE_UINT8: 313 case DATA_TYPE_UINT16: 314 case DATA_TYPE_UINT32: 315 case DATA_TYPE_UINT64: 316 case DATA_TYPE_BYTE_ARRAY: 317 case DATA_TYPE_UINT8_ARRAY: 318 case DATA_TYPE_UINT16_ARRAY: 319 case DATA_TYPE_UINT32_ARRAY: 320 case DATA_TYPE_UINT64_ARRAY: 321 return (SCF_TYPE_COUNT); 322 323 case DATA_TYPE_INT8: 324 case DATA_TYPE_INT16: 325 case DATA_TYPE_INT32: 326 case DATA_TYPE_INT64: 327 case DATA_TYPE_INT8_ARRAY: 328 case DATA_TYPE_INT16_ARRAY: 329 case DATA_TYPE_INT32_ARRAY: 330 case DATA_TYPE_INT64_ARRAY: 331 return (SCF_TYPE_INTEGER); 332 333 case DATA_TYPE_STRING: 334 case DATA_TYPE_STRING_ARRAY: 335 return (SCF_TYPE_ASTRING); 336 337 default: 338 return (SCF_TYPE_INVALID); 339 } 340 } 341 342 static int 343 add_entry(scf_transaction_entry_t *te, scf_value_t *val) 344 { 345 if (scf_entry_add_value(te, val) != 0) { 346 scf_value_destroy(val); 347 return (SCF_FAILED); 348 } 349 350 return (SCF_SUCCESS); 351 } 352 353 static int 354 add_boolean_entry(scf_handle_t *h, scf_transaction_entry_t *te, uint8_t v) 355 { 356 scf_value_t *val = scf_value_create(h); 357 358 if (val == NULL) 359 return (SCF_FAILED); 360 361 scf_value_set_boolean(val, v); 362 363 return (add_entry(te, val)); 364 } 365 366 static int 367 add_count_entry(scf_handle_t *h, scf_transaction_entry_t *te, uint64_t v) 368 { 369 scf_value_t *val = scf_value_create(h); 370 371 if (val == NULL) 372 return (SCF_FAILED); 373 374 scf_value_set_count(val, v); 375 376 return (add_entry(te, val)); 377 } 378 379 static int 380 add_integer_entry(scf_handle_t *h, scf_transaction_entry_t *te, int64_t v) 381 { 382 scf_value_t *val = scf_value_create(h); 383 384 if (val == NULL) 385 return (SCF_FAILED); 386 387 scf_value_set_integer(val, v); 388 389 return (add_entry(te, val)); 390 } 391 392 static int 393 add_astring_entry(scf_handle_t *h, scf_transaction_entry_t *te, char *s) 394 { 395 scf_value_t *val = scf_value_create(h); 396 397 if (val == NULL) 398 return (SCF_FAILED); 399 400 if (scf_value_set_astring(val, s) != 0) { 401 scf_value_destroy(val); 402 return (SCF_FAILED); 403 } 404 405 return (add_entry(te, val)); 406 } 407 408 static int 409 get_nvpair_vals(scf_handle_t *h, scf_transaction_entry_t *te, nvpair_t *p) 410 { 411 scf_value_t *val = scf_value_create(h); 412 uint_t n = 1; 413 int i; 414 415 if (val == NULL) 416 return (SCF_FAILED); 417 418 switch (nvpair_type(p)) { 419 case DATA_TYPE_BOOLEAN: 420 return (add_boolean_entry(h, te, 1)); 421 case DATA_TYPE_BOOLEAN_VALUE: 422 { 423 boolean_t v; 424 425 (void) nvpair_value_boolean_value(p, &v); 426 return (add_boolean_entry(h, te, (uint8_t)v)); 427 } 428 case DATA_TYPE_BOOLEAN_ARRAY: 429 { 430 boolean_t *v; 431 432 (void) nvpair_value_boolean_array(p, &v, &n); 433 for (i = 0; i < n; ++i) { 434 if (add_boolean_entry(h, te, (uint8_t)v[i]) != 435 SCF_SUCCESS) 436 return (SCF_FAILED); 437 } 438 return (SCF_SUCCESS); 439 } 440 case DATA_TYPE_BYTE: 441 { 442 uchar_t v; 443 444 (void) nvpair_value_byte(p, &v); 445 return (add_count_entry(h, te, v)); 446 } 447 case DATA_TYPE_UINT8: 448 { 449 uint8_t v; 450 451 (void) nvpair_value_uint8(p, &v); 452 return (add_count_entry(h, te, v)); 453 } 454 case DATA_TYPE_UINT16: 455 { 456 uint16_t v; 457 458 (void) nvpair_value_uint16(p, &v); 459 return (add_count_entry(h, te, v)); 460 } 461 case DATA_TYPE_UINT32: 462 { 463 uint32_t v; 464 465 (void) nvpair_value_uint32(p, &v); 466 return (add_count_entry(h, te, v)); 467 } 468 case DATA_TYPE_UINT64: 469 { 470 uint64_t v; 471 472 (void) nvpair_value_uint64(p, &v); 473 return (add_count_entry(h, te, v)); 474 } 475 case DATA_TYPE_BYTE_ARRAY: 476 { 477 uchar_t *v; 478 479 (void) nvpair_value_byte_array(p, &v, &n); 480 for (i = 0; i < n; ++i) { 481 if (add_count_entry(h, te, v[i]) != SCF_SUCCESS) 482 return (SCF_FAILED); 483 } 484 return (SCF_SUCCESS); 485 } 486 case DATA_TYPE_UINT8_ARRAY: 487 { 488 uint8_t *v; 489 490 (void) nvpair_value_uint8_array(p, &v, &n); 491 for (i = 0; i < n; ++i) { 492 if (add_count_entry(h, te, v[i]) != SCF_SUCCESS) 493 return (SCF_FAILED); 494 } 495 return (SCF_SUCCESS); 496 } 497 case DATA_TYPE_UINT16_ARRAY: 498 { 499 uint16_t *v; 500 501 (void) nvpair_value_uint16_array(p, &v, &n); 502 for (i = 0; i < n; ++i) { 503 if (add_count_entry(h, te, v[i]) != SCF_SUCCESS) 504 return (SCF_FAILED); 505 } 506 return (SCF_SUCCESS); 507 } 508 case DATA_TYPE_UINT32_ARRAY: 509 { 510 uint32_t *v; 511 512 (void) nvpair_value_uint32_array(p, &v, &n); 513 for (i = 0; i < n; ++i) { 514 if (add_count_entry(h, te, v[i]) != SCF_SUCCESS) 515 return (SCF_FAILED); 516 } 517 return (SCF_SUCCESS); 518 } 519 case DATA_TYPE_UINT64_ARRAY: 520 { 521 uint64_t *v; 522 523 (void) nvpair_value_uint64_array(p, &v, &n); 524 for (i = 0; i < n; ++i) { 525 if (add_count_entry(h, te, v[i]) != SCF_SUCCESS) 526 return (SCF_FAILED); 527 } 528 return (SCF_SUCCESS); 529 } 530 case DATA_TYPE_INT8: 531 { 532 int8_t v; 533 534 (void) nvpair_value_int8(p, &v); 535 return (add_integer_entry(h, te, v)); 536 } 537 case DATA_TYPE_INT16: 538 { 539 int16_t v; 540 541 (void) nvpair_value_int16(p, &v); 542 return (add_integer_entry(h, te, v)); 543 } 544 case DATA_TYPE_INT32: 545 { 546 int32_t v; 547 548 (void) nvpair_value_int32(p, &v); 549 return (add_integer_entry(h, te, v)); 550 } 551 case DATA_TYPE_INT64: 552 { 553 int64_t v; 554 555 (void) nvpair_value_int64(p, &v); 556 return (add_integer_entry(h, te, v)); 557 } 558 case DATA_TYPE_INT8_ARRAY: 559 { 560 int8_t *v; 561 562 (void) nvpair_value_int8_array(p, &v, &n); 563 for (i = 0; i < n; ++i) { 564 if (add_integer_entry(h, te, v[i]) != 565 SCF_SUCCESS) 566 return (SCF_FAILED); 567 } 568 return (SCF_SUCCESS); 569 } 570 case DATA_TYPE_INT16_ARRAY: 571 { 572 int16_t *v; 573 574 (void) nvpair_value_int16_array(p, &v, &n); 575 for (i = 0; i < n; ++i) { 576 if (add_integer_entry(h, te, v[i]) != 577 SCF_SUCCESS) 578 return (SCF_FAILED); 579 } 580 return (SCF_SUCCESS); 581 } 582 case DATA_TYPE_INT32_ARRAY: 583 { 584 int32_t *v; 585 586 (void) nvpair_value_int32_array(p, &v, &n); 587 for (i = 0; i < n; ++i) { 588 if (add_integer_entry(h, te, v[i]) != 589 SCF_SUCCESS) 590 return (SCF_FAILED); 591 } 592 return (SCF_SUCCESS); 593 } 594 case DATA_TYPE_INT64_ARRAY: 595 { 596 int64_t *v; 597 598 (void) nvpair_value_int64_array(p, &v, &n); 599 for (i = 0; i < n; ++i) { 600 if (add_integer_entry(h, te, v[i]) != 601 SCF_SUCCESS) 602 return (SCF_FAILED); 603 } 604 return (SCF_SUCCESS); 605 } 606 case DATA_TYPE_STRING: 607 { 608 char *str; 609 610 (void) nvpair_value_string(p, &str); 611 return (add_astring_entry(h, te, str)); 612 } 613 case DATA_TYPE_STRING_ARRAY: 614 { 615 char **v; 616 617 (void) nvpair_value_string_array(p, &v, &n); 618 for (i = 0; i < n; ++i) { 619 if (add_astring_entry(h, te, v[i]) != 620 SCF_SUCCESS) 621 return (SCF_FAILED); 622 } 623 return (SCF_SUCCESS); 624 } 625 default: 626 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 627 return (SCF_FAILED); 628 } 629 630 /*NOTREACHED*/ 631 } 632 633 /* 634 * Add new transaction entry to scf_transaction_t 635 * 636 * Can fail with 637 * SCF_ERROR_BACKEND_ACCESS 638 * SCF_ERROR_CONNECTION_BROKEN 639 * SCF_ERROR_DELETED 640 * SCF_ERROR_INTERNAL 641 * SCF_ERROR_NO_RESOURCES 642 * SCF_ERROR_NOT_FOUND 643 */ 644 static int 645 prep_transaction(scf_transaction_t *tx, scf_transaction_entry_t *te, 646 const char *prop, scf_type_t type) 647 { 648 if (scf_transaction_property_new(tx, te, prop, type) != SCF_SUCCESS && 649 (scf_error() != SCF_ERROR_EXISTS || 650 scf_transaction_property_change(tx, te, prop, type) != 651 SCF_SUCCESS)) { 652 if (check_scf_error(scf_error(), errs_2)) { 653 return (SCF_FAILED); 654 } 655 } 656 657 return (SCF_SUCCESS); 658 } 659 660 /* 661 * notify_set_params() 662 * returns 0 on success or -1 on failure 663 * SCF_ERROR_BACKEND_ACCESS 664 * SCF_ERROR_BACKEND_READONLY 665 * SCF_ERROR_CONNECTION_BROKEN 666 * SCF_ERROR_DELETED 667 * SCF_ERROR_INTERNAL 668 * SCF_ERROR_INVALID_ARGUMENT 669 * SCF_ERROR_NO_MEMORY 670 * SCF_ERROR_NO_RESOURCES 671 * SCF_ERROR_NOT_FOUND 672 * SCF_ERROR_PERMISSION_DENIED 673 */ 674 static int 675 notify_set_params(scf_propertygroup_t *pg, nvlist_t *params) 676 { 677 scf_handle_t *h = scf_pg_handle(pg); 678 scf_error_t scf_e = scf_error(); 679 scf_transaction_t *tx = scf_transaction_create(h); 680 int bufsz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1; 681 char *propname = malloc(bufsz); 682 int r = -1; 683 int err; 684 685 if (h == NULL) { 686 /* 687 * Use the error stored in scf_e 688 */ 689 (void) scf_set_error(scf_e); 690 goto cleanup; 691 } 692 if (tx == NULL) 693 goto cleanup; 694 695 if (propname == NULL) { 696 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 697 goto cleanup; 698 } 699 700 do { 701 nvpair_t *nvp; 702 703 /* 704 * make sure we have the most recent version of the pg 705 * start the transaction 706 */ 707 if (scf_pg_update(pg) == SCF_FAILED || 708 scf_transaction_start(tx, pg) != SCF_SUCCESS) { 709 if (check_scf_error(scf_error(), errs_2)) { 710 goto cleanup; 711 } 712 } 713 714 for (nvp = nvlist_next_nvpair(params, NULL); nvp != NULL; 715 nvp = nvlist_next_nvpair(params, nvp)) { 716 nvlist_t *m; 717 nvpair_t *p; 718 719 /* we ONLY take nvlists here */ 720 if (nvpair_type(nvp) != DATA_TYPE_NVLIST) { 721 char *name = nvpair_name(nvp); 722 723 /* 724 * if this is output from 725 * smf_notify_get_params() we want to skip 726 * the tset value of the nvlist 727 */ 728 if (strcmp(name, SCF_NOTIFY_NAME_TSET) == 0) 729 continue; 730 731 (void) scf_set_error( 732 SCF_ERROR_INVALID_ARGUMENT); 733 goto cleanup; 734 } 735 736 if (nvpair_value_nvlist(nvp, &m) != 0) { 737 (void) scf_set_error( 738 SCF_ERROR_INVALID_ARGUMENT); 739 goto cleanup; 740 } 741 742 /* 743 * Traverse each mechanism list 744 */ 745 for (p = nvlist_next_nvpair(m, NULL); p != NULL; 746 p = nvlist_next_nvpair(m, p)) { 747 scf_transaction_entry_t *te = 748 scf_entry_create(h); 749 /* map the nvpair type to scf type */ 750 scf_type_t type = get_scf_type(p); 751 752 if (te == NULL) { 753 if (scf_error() != 754 SCF_ERROR_INVALID_ARGUMENT) { 755 scf_entry_destroy(te); 756 goto cleanup; 757 } else { 758 assert(0); 759 abort(); 760 } 761 } 762 763 if (type == SCF_TYPE_INVALID) { 764 (void) scf_set_error( 765 SCF_ERROR_INVALID_ARGUMENT); 766 scf_entry_destroy(te); 767 goto cleanup; 768 } 769 770 if (snprintf(propname, bufsz, "%s,%s", 771 nvpair_name(nvp), nvpair_name(p)) >= 772 bufsz) { 773 (void) scf_set_error( 774 SCF_ERROR_INVALID_ARGUMENT); 775 scf_entry_destroy(te); 776 goto cleanup; 777 } 778 779 if (prep_transaction(tx, te, propname, type) != 780 SCF_SUCCESS) { 781 scf_entry_destroy(te); 782 goto cleanup; 783 } 784 785 if (get_nvpair_vals(h, te, p) != SCF_SUCCESS) { 786 if (check_scf_error(scf_error(), 787 errs_2)) { 788 goto cleanup; 789 } 790 } 791 } 792 } 793 err = scf_transaction_commit(tx); 794 scf_transaction_destroy_children(tx); 795 } while (err == 0); 796 797 if (err == -1) { 798 if (check_scf_error(scf_error(), errs_2)) { 799 goto cleanup; 800 } 801 } 802 803 r = 0; 804 805 cleanup: 806 scf_transaction_destroy_children(tx); 807 scf_transaction_destroy(tx); 808 free(propname); 809 810 return (r); 811 } 812 813 /* 814 * Decode fmri. Populates service OR instance depending on which one is an 815 * exact match to the fmri parameter. 816 * 817 * The function destroys and sets the unused entity (service or instance) to 818 * NULL. 819 * 820 * return SCF_SUCCESS or SCF_FAILED on 821 * SCF_ERROR_BACKEND_ACCESS 822 * SCF_ERROR_CONNECTION_BROKEN 823 * SCF_ERROR_CONSTRAINT_VIOLATED 824 * SCF_ERROR_DELETED 825 * SCF_ERROR_HANDLE_MISMATCH 826 * SCF_ERROR_INTERNAL 827 * SCF_ERROR_INVALID_ARGUMENT 828 * SCF_ERROR_NO_RESOURCES 829 * SCF_ERROR_NOT_BOUND 830 * SCF_ERROR_NOT_FOUND 831 * SCF_ERROR_NOT_SET 832 */ 833 static int 834 decode_fmri(const char *fmri, scf_handle_t *h, scf_service_t **s, 835 scf_instance_t **i) 836 { 837 if (scf_handle_decode_fmri(h, fmri, NULL, *s, NULL, NULL, NULL, 838 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 839 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) { 840 scf_service_destroy(*s); 841 *s = NULL; 842 } else { 843 return (SCF_FAILED); 844 } 845 } 846 if (*s == NULL) 847 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, *i, 848 NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 849 return (SCF_FAILED); 850 } 851 852 return (SCF_SUCCESS); 853 } 854 855 /* 856 * Return size in bytes for an SCF_TYPE_*. Not all libscf types are supported 857 */ 858 static int 859 get_type_size(scf_type_t t) 860 { 861 switch (t) { 862 case SCF_TYPE_BOOLEAN: 863 return (sizeof (uint8_t)); 864 case SCF_TYPE_COUNT: 865 return (sizeof (uint64_t)); 866 case SCF_TYPE_INTEGER: 867 return (sizeof (int64_t)); 868 case SCF_TYPE_ASTRING: 869 case SCF_TYPE_USTRING: 870 return (sizeof (void *)); 871 default: 872 return (-1); 873 } 874 875 /*NOTREACHED*/ 876 } 877 878 /* 879 * Return a pointer to the array of values according to its type 880 */ 881 static void ** 882 get_v_pointer(scf_values_t *v) 883 { 884 switch (v->value_type) { 885 case SCF_TYPE_BOOLEAN: 886 return ((void **)&v->values.v_boolean); 887 case SCF_TYPE_COUNT: 888 return ((void **)&v->values.v_count); 889 case SCF_TYPE_INTEGER: 890 return ((void **)&v->values.v_integer); 891 case SCF_TYPE_ASTRING: 892 return ((void **)&v->values.v_astring); 893 case SCF_TYPE_USTRING: 894 return ((void **)&v->values.v_ustring); 895 default: 896 return (NULL); 897 } 898 899 /*NOTREACHED*/ 900 } 901 902 /* 903 * Populate scf_values_t value array at position c. 904 */ 905 static int 906 get_value(scf_value_t *val, scf_values_t *v, int c, char *buf, int sz) 907 { 908 switch (v->value_type) { 909 case SCF_TYPE_BOOLEAN: 910 return (scf_value_get_boolean(val, v->values.v_boolean + c)); 911 case SCF_TYPE_COUNT: 912 return (scf_value_get_count(val, v->values.v_count + c)); 913 case SCF_TYPE_INTEGER: 914 return (scf_value_get_integer(val, v->values.v_integer + c)); 915 case SCF_TYPE_ASTRING: 916 if (scf_value_get_astring(val, buf, sz) < 0 || 917 (v->values.v_astring[c] = strdup(buf)) == NULL) { 918 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 919 return (-1); 920 } 921 return (0); 922 case SCF_TYPE_USTRING: 923 if (scf_value_get_ustring(val, buf, sz) < 0 || 924 (v->values.v_ustring[c] = strdup(buf)) == NULL) { 925 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 926 return (-1); 927 } 928 return (0); 929 default: 930 return (-1); 931 } 932 933 /*NOTREACHED*/ 934 } 935 936 /* 937 * Populate scf_values_t structure with values from prop 938 */ 939 static int 940 values_get(scf_property_t *prop, scf_values_t *v) 941 { 942 scf_handle_t *h = scf_property_handle(prop); 943 scf_error_t scf_e = scf_error(); 944 scf_value_t *val = scf_value_create(h); 945 scf_iter_t *it = scf_iter_create(h); 946 scf_type_t type = SCF_TYPE_INVALID; 947 ssize_t sz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1; 948 char *buf = malloc(sz); 949 void **p; 950 int err, elem_sz, count, cursz; 951 int r = SCF_FAILED; 952 953 assert(v != NULL); 954 assert(v->reserved == NULL); 955 if (buf == NULL) { 956 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 957 goto cleanup; 958 } 959 if (h == NULL) { 960 /* 961 * Use the error stored in scf_e 962 */ 963 (void) scf_set_error(scf_e); 964 goto cleanup; 965 } 966 if (val == NULL || it == NULL) 967 goto cleanup; 968 969 if (scf_property_type(prop, &type) != SCF_SUCCESS) 970 goto cleanup; 971 if (scf_property_is_type(prop, v->value_type) != SCF_SUCCESS) 972 goto error; 973 974 elem_sz = get_type_size(type); 975 assert(elem_sz > 0); 976 977 p = get_v_pointer(v); 978 assert(p != NULL); 979 980 cursz = count = v->value_count; 981 if (scf_iter_property_values(it, prop) != 0) { 982 goto error; 983 } 984 985 while ((err = scf_iter_next_value(it, val)) == 1) { 986 if (count + 1 >= cursz) { 987 void *tmp; 988 989 /* set initial size or double it */ 990 cursz = cursz ? 2 * cursz : 8; 991 if ((tmp = realloc(*p, cursz * elem_sz)) == NULL) { 992 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 993 goto error; 994 } 995 *p = tmp; 996 } 997 998 if (get_value(val, v, count, buf, sz) != 0) 999 goto error; 1000 1001 count++; 1002 } 1003 1004 v->value_count = count; 1005 1006 if (err != 0) 1007 goto error; 1008 1009 r = SCF_SUCCESS; 1010 goto cleanup; 1011 1012 error: 1013 v->value_count = count; 1014 scf_values_destroy(v); 1015 1016 cleanup: 1017 free(buf); 1018 scf_iter_destroy(it); 1019 scf_value_destroy(val); 1020 return (r); 1021 } 1022 1023 /* 1024 * Add values from property p to existing nvlist_t nvl. The data type in the 1025 * nvlist is inferred from the scf_type_t of the property. 1026 * 1027 * Returns SCF_SUCCESS or SCF_FAILED on 1028 * SCF_ERROR_CONNECTION_BROKEN 1029 * SCF_ERROR_DELETED 1030 * SCF_ERROR_HANDLE_DESTROYED 1031 * SCF_ERROR_HANDLE_MISMATCH 1032 * SCF_ERROR_INVALID_ARGUMENT 1033 * SCF_ERROR_NO_MEMORY 1034 * SCF_ERROR_NO_RESOURCES 1035 * SCF_ERROR_NOT_BOUND 1036 * SCF_ERROR_NOT_SET 1037 * SCF_ERROR_PERMISSION_DENIED 1038 * SCF_ERROR_TYPE_MISMATCH 1039 */ 1040 static int 1041 add_prop_to_nvlist(scf_property_t *p, const char *pname, nvlist_t *nvl, 1042 int array) 1043 { 1044 scf_values_t vals = { 0 }; 1045 scf_type_t type, base_type; 1046 int r = SCF_FAILED; 1047 int err = 0; 1048 1049 if (p == NULL || pname == NULL || *pname == '\0' || nvl == NULL) { 1050 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1051 return (r); 1052 } 1053 1054 if (scf_property_type(p, &type) != 0) 1055 goto cleanup; 1056 1057 /* 1058 * scf_values_t does not support subtypes of SCF_TYPE_USTRING, 1059 * mapping them all to SCF_TYPE_USTRING 1060 */ 1061 base_type = scf_true_base_type(type); 1062 if (base_type == SCF_TYPE_ASTRING && type != SCF_TYPE_ASTRING) 1063 type = SCF_TYPE_USTRING; 1064 1065 vals.value_type = type; 1066 if (values_get(p, &vals) != SCF_SUCCESS) { 1067 if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 1068 assert(0); 1069 abort(); 1070 } 1071 goto cleanup; 1072 } 1073 1074 switch (vals.value_type) { 1075 case SCF_TYPE_BOOLEAN: 1076 { 1077 boolean_t *v; 1078 int i; 1079 int n = vals.value_count; 1080 1081 v = calloc(n, sizeof (boolean_t)); 1082 if (v == NULL) { 1083 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1084 goto cleanup; 1085 } 1086 for (i = 0; i < n; ++i) 1087 v[i] = (boolean_t)vals.values.v_boolean[i]; 1088 1089 if (n == 1 && !array) 1090 err = nvlist_add_boolean_value(nvl, pname, *v); 1091 else 1092 err = nvlist_add_boolean_array(nvl, pname, 1093 v, n); 1094 if (err != 0) { 1095 free(v); 1096 goto cleanup; 1097 } 1098 free(v); 1099 } 1100 break; 1101 1102 case SCF_TYPE_COUNT: 1103 if (vals.value_count == 1 && !array) 1104 err = nvlist_add_uint64(nvl, pname, 1105 *vals.values.v_count); 1106 else 1107 err = nvlist_add_uint64_array(nvl, pname, 1108 vals.values.v_count, vals.value_count); 1109 if (err != 0) 1110 goto cleanup; 1111 1112 break; 1113 1114 case SCF_TYPE_INTEGER: 1115 if (vals.value_count == 1 && !array) 1116 err = nvlist_add_int64(nvl, pname, 1117 *vals.values.v_integer); 1118 else 1119 err = nvlist_add_int64_array(nvl, pname, 1120 vals.values.v_integer, vals.value_count); 1121 if (err != 0) 1122 goto cleanup; 1123 1124 break; 1125 1126 case SCF_TYPE_ASTRING: 1127 if (vals.value_count == 1 && !array) 1128 err = nvlist_add_string(nvl, pname, 1129 *vals.values.v_astring); 1130 else 1131 err = nvlist_add_string_array(nvl, pname, 1132 vals.values.v_astring, vals.value_count); 1133 if (err != 0) 1134 goto cleanup; 1135 break; 1136 1137 default: 1138 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1139 goto cleanup; 1140 } 1141 1142 r = SCF_SUCCESS; 1143 cleanup: 1144 scf_values_destroy(&vals); 1145 switch (err) { 1146 case 0: 1147 break; 1148 case EINVAL: 1149 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1150 break; 1151 case ENOMEM: 1152 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1153 break; 1154 default: 1155 /* we should *never* get here */ 1156 abort(); 1157 } 1158 1159 return (r); 1160 } 1161 1162 /* 1163 * Parse property name "mechanism,parameter" into separate mechanism 1164 * and parameter. *mech must be freed by caller. *val points into 1165 * *mech and must not be freed. 1166 * 1167 * Returns SCF_SUCCESS or SCF_FAILED on 1168 * SCF_ERROR_NO_MEMORY 1169 * SCF_ERROR_NOT_FOUND 1170 */ 1171 static int 1172 get_mech_name(const char *name, char **mech, char **val) 1173 { 1174 char *p; 1175 char *m; 1176 1177 if ((m = strdup(name)) == NULL) { 1178 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1179 return (SCF_FAILED); 1180 } 1181 if ((p = strchr(m, ',')) == NULL) { 1182 free(m); 1183 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 1184 return (SCF_FAILED); 1185 } 1186 *p = '\0'; 1187 *val = p + 1; 1188 *mech = m; 1189 1190 return (SCF_SUCCESS); 1191 } 1192 1193 /* 1194 * Return the number of transitions in a transition set. 1195 * If the transition set is invalid, it returns zero. 1196 */ 1197 static uint_t 1198 num_of_transitions(int32_t t) 1199 { 1200 int i; 1201 int n = 0; 1202 1203 if (SCF_TRANS_VALID(t)) { 1204 for (i = 0x1; i < SCF_STATE_ALL; i <<= 1) { 1205 if (i & t) 1206 ++n; 1207 if (SCF_TRANS_INITIAL_STATE(t) & i) 1208 ++n; 1209 } 1210 } 1211 1212 return (n); 1213 } 1214 1215 /* 1216 * Return the SCF_STATE_* macro value for the state in the FMA classes for 1217 * SMF state transitions. They are of type: 1218 * SCF_SVC_TRANSITION_CLASS.<state> 1219 * ireport.os.smf.state-transition.<state> 1220 */ 1221 static int32_t 1222 class_to_transition(const char *c) 1223 { 1224 const char *p; 1225 int r = 0; 1226 size_t n; 1227 1228 if (!is_svc_stn(c)) { 1229 return (0); 1230 } 1231 1232 /* 1233 * if we get here, c is SCF_SVC_TRANSITION_CLASS or longer 1234 */ 1235 p = c + strlen(SCF_SVC_TRANSITION_CLASS); 1236 if (*p == '.') 1237 ++p; 1238 else 1239 return (0); 1240 1241 if ((n = base_class_len(p)) == 0) 1242 return (0); 1243 1244 if ((r = state_from_string(p, n)) == -1) 1245 r = 0; 1246 1247 return (r); 1248 } 1249 1250 /* 1251 * return SCF_SUCCESS or SCF_FAILED on 1252 * SCF_ERROR_BACKEND_ACCESS 1253 * SCF_ERROR_BACKEND_READONLY 1254 * SCF_ERROR_CONNECTION_BROKEN 1255 * SCF_ERROR_DELETED 1256 * SCF_ERROR_INTERNAL 1257 * SCF_ERROR_INVALID_ARGUMENT 1258 * SCF_ERROR_NO_MEMORY 1259 * SCF_ERROR_NO_RESOURCES 1260 * SCF_ERROR_NOT_FOUND 1261 * SCF_ERROR_PERMISSION_DENIED 1262 */ 1263 int 1264 smf_notify_set_params(const char *class, nvlist_t *attr) 1265 { 1266 uint32_t ver; 1267 int32_t tset; 1268 scf_handle_t *h = _scf_handle_create_and_bind(SCF_VERSION); 1269 scf_error_t scf_e = scf_error(); 1270 scf_service_t *s = scf_service_create(h); 1271 scf_instance_t *i = scf_instance_create(h); 1272 scf_propertygroup_t *pg = scf_pg_create(h); 1273 nvlist_t *params = NULL; 1274 char *fmri = (char *)SCF_NOTIFY_PARAMS_INST; 1275 char *pgname = NULL; 1276 int r = SCF_FAILED; 1277 boolean_t is_stn; 1278 int j; 1279 1280 assert(class != NULL); 1281 if (h == NULL) { 1282 /* 1283 * use saved error if _scf_handle_create_and_bind() fails 1284 */ 1285 (void) scf_set_error(scf_e); 1286 goto cleanup; 1287 } 1288 if (i == NULL || s == NULL || pg == NULL) 1289 goto cleanup; 1290 1291 /* check version */ 1292 if (nvlist_lookup_uint32(attr, SCF_NOTIFY_NAME_VERSION, &ver) != 0 || 1293 ver != SCF_NOTIFY_PARAMS_VERSION) { 1294 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1295 goto cleanup; 1296 } 1297 1298 if (nvlist_lookup_nvlist(attr, SCF_NOTIFY_PARAMS, ¶ms) != 0) { 1299 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1300 goto cleanup; 1301 } 1302 1303 is_stn = is_svc_stn(class); 1304 /* special case SMF state transition notification */ 1305 if (is_stn && 1306 (nvlist_lookup_string(attr, SCF_NOTIFY_NAME_FMRI, &fmri) != 0 || 1307 nvlist_lookup_int32(attr, SCF_NOTIFY_NAME_TSET, &tset) != 0 || 1308 !SCF_TRANS_VALID(tset))) { 1309 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1310 goto cleanup; 1311 } 1312 if (decode_fmri(fmri, h, &s, &i) != SCF_SUCCESS) 1313 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) { 1314 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1315 } else if (check_scf_error(scf_error(), errs_1)) { 1316 goto cleanup; 1317 } 1318 1319 if (is_stn) { 1320 tset |= class_to_transition(class); 1321 1322 if (!SCF_TRANS_VALID(tset)) { 1323 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1324 goto cleanup; 1325 } 1326 1327 for (j = 0; st_pgnames[j].st_pgname != NULL; ++j) { 1328 /* if this transition is not in the tset, continue */ 1329 if (!(tset & st_pgnames[j].st_state)) 1330 continue; 1331 1332 if (get_or_add_pg(s, i, st_pgnames[j].st_pgname, 1333 SCF_NOTIFY_PARAMS_PG_TYPE, 0, pg) != 0 && 1334 check_scf_error(scf_error(), errs_2)) 1335 goto cleanup; 1336 1337 if (notify_set_params(pg, params) != 0) 1338 goto cleanup; 1339 } 1340 if (s == NULL) { 1341 /* We only need to refresh the instance */ 1342 if (_smf_refresh_instance_i(i) != 0 && 1343 check_scf_error(scf_error(), errs_1)) 1344 goto cleanup; 1345 } else { 1346 /* We have to refresh all instances in the service */ 1347 if (_smf_refresh_all_instances(s) != 0 && 1348 check_scf_error(scf_error(), errs_1)) 1349 goto cleanup; 1350 } 1351 } else { 1352 if ((pgname = class_to_pgname(class)) == NULL) 1353 goto cleanup; 1354 if (get_or_add_pg(s, i, pgname, SCF_GROUP_APPLICATION, 0, pg) != 1355 0) { 1356 if (check_scf_error(scf_error(), errs_2)) { 1357 goto cleanup; 1358 } 1359 } 1360 if (notify_set_params(pg, params) != 0) { 1361 goto cleanup; 1362 } 1363 if (_smf_refresh_instance_i(i) != 0 && 1364 check_scf_error(scf_error(), errs_1)) 1365 goto cleanup; 1366 } 1367 1368 r = SCF_SUCCESS; 1369 cleanup: 1370 scf_instance_destroy(i); 1371 scf_service_destroy(s); 1372 scf_pg_destroy(pg); 1373 scf_handle_destroy(h); 1374 free(pgname); 1375 1376 return (r); 1377 } 1378 1379 /* 1380 * returns SCF_SUCCESS or SCF_FAILED on 1381 * SCF_ERROR_CONNECTION_BROKEN 1382 * SCF_ERROR_DELETED 1383 * SCF_ERROR_HANDLE_DESTROYED 1384 * SCF_ERROR_HANDLE_MISMATCH 1385 * SCF_ERROR_INVALID_ARGUMENT 1386 * SCF_ERROR_NO_MEMORY 1387 * SCF_ERROR_NO_RESOURCES 1388 * SCF_ERROR_NOT_BOUND 1389 * SCF_ERROR_NOT_FOUND 1390 * SCF_ERROR_NOT_SET 1391 * SCF_ERROR_PERMISSION_DENIED 1392 */ 1393 int 1394 _scf_notify_get_params(scf_propertygroup_t *pg, nvlist_t *params) 1395 { 1396 scf_handle_t *h = scf_pg_handle(pg); 1397 scf_error_t scf_e = scf_error(); 1398 scf_property_t *p = scf_property_create(h); 1399 scf_iter_t *it = scf_iter_create(h); 1400 int sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1; 1401 char *name = malloc(sz); 1402 int r = SCF_FAILED; 1403 int err; 1404 1405 if (h == NULL) { 1406 /* 1407 * Use the error stored in scf_e 1408 */ 1409 (void) scf_set_error(scf_e); 1410 goto cleanup; 1411 } 1412 if (it == NULL || p == NULL) 1413 goto cleanup; 1414 1415 if (name == NULL) { 1416 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1417 goto cleanup; 1418 } 1419 1420 if (scf_iter_pg_properties(it, pg) != SCF_SUCCESS) { 1421 if (check_scf_error(scf_error(), errs_1)) { 1422 goto cleanup; 1423 } 1424 } 1425 1426 while ((err = scf_iter_next_property(it, p)) == 1) { 1427 nvlist_t *nvl; 1428 int nvl_new = 0; 1429 char *mech; 1430 char *val; 1431 1432 if (scf_property_get_name(p, name, sz) == SCF_FAILED) { 1433 if (check_scf_error(scf_error(), errs_1)) { 1434 goto cleanup; 1435 } 1436 } 1437 1438 if (get_mech_name(name, &mech, &val) != SCF_SUCCESS) { 1439 if (scf_error() == SCF_ERROR_NOT_FOUND) 1440 continue; 1441 goto cleanup; 1442 } 1443 1444 if (nvlist_lookup_nvlist(params, mech, &nvl) != 0) { 1445 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { 1446 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1447 free(mech); 1448 goto cleanup; 1449 } 1450 nvl_new = 1; 1451 } 1452 1453 if (add_prop_to_nvlist(p, val, nvl, 1) != SCF_SUCCESS) { 1454 if (check_scf_error(scf_error(), errs_2)) { 1455 free(mech); 1456 nvlist_free(nvl); 1457 goto cleanup; 1458 } 1459 } 1460 if (nvl_new) { 1461 if (nvlist_add_nvlist(params, mech, nvl) != 0) { 1462 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1463 free(mech); 1464 nvlist_free(nvl); 1465 goto cleanup; 1466 } 1467 nvlist_free(nvl); 1468 } 1469 1470 free(mech); 1471 } 1472 1473 if (err == 0) { 1474 r = SCF_SUCCESS; 1475 } else if (check_scf_error(scf_error(), errs_2)) { 1476 goto cleanup; 1477 } 1478 1479 cleanup: 1480 scf_iter_destroy(it); 1481 scf_property_destroy(p); 1482 free(name); 1483 1484 return (r); 1485 } 1486 1487 /* 1488 * Look up pg containing an SMF state transition parameters. If it cannot find 1489 * the pg in the composed view of the instance, it will look in the global 1490 * instance for the system wide parameters. 1491 * Instance, service and global instance have to be passed by caller. 1492 * 1493 * returns SCF_SUCCESS or SCF_FAILED on 1494 * SCF_ERROR_BACKEND_ACCESS 1495 * SCF_ERROR_CONNECTION_BROKEN 1496 * SCF_ERROR_DELETED 1497 * SCF_ERROR_HANDLE_DESTROYED 1498 * SCF_ERROR_HANDLE_MISMATCH 1499 * SCF_ERROR_INTERNAL 1500 * SCF_ERROR_INVALID_ARGUMENT 1501 * SCF_ERROR_NO_MEMORY 1502 * SCF_ERROR_NO_RESOURCES 1503 * SCF_ERROR_NOT_BOUND 1504 * SCF_ERROR_NOT_FOUND 1505 * SCF_ERROR_NOT_SET 1506 */ 1507 static int 1508 get_stn_pg(scf_service_t *s, scf_instance_t *i, scf_instance_t *g, 1509 const char *pgname, scf_propertygroup_t *pg) 1510 { 1511 if (get_pg(s, i, pgname, pg, 1) == 0 || 1512 scf_error() == SCF_ERROR_NOT_FOUND && 1513 get_pg(NULL, g, pgname, pg, 0) == 0) 1514 return (SCF_SUCCESS); 1515 1516 return (SCF_FAILED); 1517 } 1518 1519 /* 1520 * Populates nvlist_t params with the source fmri for the pg 1521 * 1522 * return SCF_SUCCESS or SCF_FAILED on 1523 * SCF_ERROR_DELETED 1524 * SCF_ERROR_CONNECTION_BROKEN 1525 * SCF_ERROR_NO_MEMORY 1526 */ 1527 static int 1528 get_pg_source(scf_propertygroup_t *pg, nvlist_t *params) 1529 { 1530 size_t sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH) + 1; 1531 char *fmri = malloc(sz); 1532 char *p; 1533 int r = SCF_FAILED; 1534 1535 if (fmri == NULL) { 1536 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1537 goto out; 1538 } 1539 1540 if (scf_pg_to_fmri(pg, fmri, sz) == -1) { 1541 if (check_scf_error(scf_error(), errs_1)) { 1542 goto out; 1543 } 1544 } 1545 1546 /* get rid of the properties part of the pg source */ 1547 if ((p = strrchr(fmri, ':')) != NULL && p > fmri) 1548 *(p - 1) = '\0'; 1549 if (nvlist_add_string(params, SCF_NOTIFY_PARAMS_SOURCE_NAME, fmri) != 1550 0) { 1551 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1552 goto out; 1553 } 1554 1555 r = SCF_SUCCESS; 1556 out: 1557 free(fmri); 1558 return (r); 1559 } 1560 1561 /* 1562 * Specialized function to get SMF state transition notification parameters 1563 * 1564 * return SCF_SUCCESS or SCF_FAILED on 1565 * SCF_ERROR_BACKEND_ACCESS 1566 * SCF_ERROR_CONNECTION_BROKEN 1567 * SCF_ERROR_DELETED 1568 * SCF_ERROR_INTERNAL 1569 * SCF_ERROR_INVALID_ARGUMENT 1570 * SCF_ERROR_NO_MEMORY 1571 * SCF_ERROR_NO_RESOURCES 1572 * SCF_ERROR_NOT_FOUND 1573 * SCF_ERROR_PERMISSION_DENIED 1574 */ 1575 int 1576 _scf_get_svc_notify_params(const char *fmri, nvlist_t *nvl, int32_t tset, 1577 int getsource, int getglobal) 1578 { 1579 scf_handle_t *h = _scf_handle_create_and_bind(SCF_VERSION); 1580 scf_error_t scf_e = scf_error(); 1581 scf_service_t *s = scf_service_create(h); 1582 scf_instance_t *i = scf_instance_create(h); 1583 scf_instance_t *g = scf_instance_create(h); 1584 scf_propertygroup_t *pg = scf_pg_create(h); 1585 int r = SCF_FAILED; 1586 nvlist_t **params = NULL; 1587 uint_t c, nvl_num = 0; 1588 int not_found = 1; 1589 int j; 1590 const char *pgname; 1591 1592 assert(fmri != NULL && nvl != NULL); 1593 if (h == NULL) { 1594 /* 1595 * use saved error if _scf_handle_create_and_bind() fails 1596 */ 1597 (void) scf_set_error(scf_e); 1598 goto cleanup; 1599 } 1600 if (s == NULL || i == NULL || g == NULL || pg == NULL) 1601 goto cleanup; 1602 1603 if (decode_fmri(fmri, h, &s, &i) != SCF_SUCCESS || 1604 scf_handle_decode_fmri(h, SCF_INSTANCE_GLOBAL, NULL, NULL, g, NULL, 1605 NULL, SCF_DECODE_FMRI_EXACT) != 0) { 1606 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) { 1607 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1608 } else if (check_scf_error(scf_error(), errs_1)) { 1609 goto cleanup; 1610 } 1611 } 1612 1613 nvl_num = num_of_transitions(tset); 1614 if ((params = calloc(nvl_num, sizeof (nvlist_t *))) == NULL) { 1615 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1616 goto cleanup; 1617 } 1618 1619 for (c = 0; c < nvl_num; ++c) 1620 if (nvlist_alloc(params + c, NV_UNIQUE_NAME, 0) != 0) { 1621 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1622 goto cleanup; 1623 } 1624 1625 for (c = 0, j = 0; st_pgnames[j].st_pgname != NULL; ++j) { 1626 /* if this transition is not in the tset, continue */ 1627 if (!(tset & st_pgnames[j].st_state)) 1628 continue; 1629 1630 assert(c < nvl_num); 1631 pgname = st_pgnames[j].st_pgname; 1632 1633 if (nvlist_add_int32(params[c], SCF_NOTIFY_NAME_TSET, 1634 st_pgnames[j].st_state) != 0) { 1635 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1636 goto cleanup; 1637 } 1638 if ((getglobal ? get_stn_pg(s, i, g, pgname, pg) : 1639 get_pg(s, i, pgname, pg, 1)) == SCF_SUCCESS) { 1640 not_found = 0; 1641 if (_scf_notify_get_params(pg, params[c]) != 1642 SCF_SUCCESS) 1643 goto cleanup; 1644 if (getsource && get_pg_source(pg, params[c]) != 1645 SCF_SUCCESS) 1646 goto cleanup; 1647 } else if (scf_error() == SCF_ERROR_NOT_FOUND || 1648 scf_error() == SCF_ERROR_DELETED) { 1649 /* keep driving */ 1650 /*EMPTY*/ 1651 } else if (check_scf_error(scf_error(), errs_1)) { 1652 goto cleanup; 1653 } 1654 ++c; 1655 } 1656 1657 if (not_found) { 1658 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 1659 goto cleanup; 1660 } 1661 1662 assert(c == nvl_num); 1663 1664 if (nvlist_add_nvlist_array(nvl, SCF_NOTIFY_PARAMS, params, nvl_num) != 1665 0 || nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION, 1666 SCF_NOTIFY_PARAMS_VERSION) != 0) { 1667 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1668 goto cleanup; 1669 } 1670 1671 r = SCF_SUCCESS; 1672 1673 cleanup: 1674 scf_pg_destroy(pg); 1675 scf_instance_destroy(i); 1676 scf_instance_destroy(g); 1677 scf_service_destroy(s); 1678 scf_handle_destroy(h); 1679 if (params != NULL) 1680 for (c = 0; c < nvl_num; ++c) 1681 nvlist_free(params[c]); 1682 free(params); 1683 1684 return (r); 1685 } 1686 1687 /* 1688 * Specialized function to get fma notification parameters 1689 * 1690 * return SCF_SUCCESS or SCF_FAILED on 1691 * SCF_ERROR_BACKEND_ACCESS 1692 * SCF_ERROR_CONNECTION_BROKEN 1693 * SCF_ERROR_DELETED 1694 * SCF_ERROR_INTERNAL 1695 * SCF_ERROR_INVALID_ARGUMENT 1696 * SCF_ERROR_NO_MEMORY 1697 * SCF_ERROR_NO_RESOURCES 1698 * SCF_ERROR_NOT_FOUND 1699 * SCF_ERROR_PERMISSION_DENIED 1700 */ 1701 int 1702 _scf_get_fma_notify_params(const char *class, nvlist_t *nvl, int getsource) 1703 { 1704 scf_handle_t *h = _scf_handle_create_and_bind(SCF_VERSION); 1705 scf_error_t scf_e = scf_error(); 1706 scf_instance_t *i = scf_instance_create(h); 1707 scf_propertygroup_t *pg = scf_pg_create(h); 1708 int r = SCF_FAILED; 1709 nvlist_t *params = NULL; 1710 char *pgname = NULL; 1711 1712 if (h == NULL) { 1713 /* 1714 * use saved error if _scf_handle_create_and_bind() fails 1715 */ 1716 (void) scf_set_error(scf_e); 1717 goto cleanup; 1718 } 1719 if (i == NULL || pg == NULL) 1720 goto cleanup; 1721 1722 if (scf_handle_decode_fmri(h, SCF_NOTIFY_PARAMS_INST, NULL, NULL, i, 1723 NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1724 if (check_scf_error(scf_error(), errs_1)) { 1725 goto cleanup; 1726 } 1727 } 1728 1729 if ((pgname = class_to_pgname(class)) == NULL) 1730 goto cleanup; 1731 1732 while (get_pg(NULL, i, pgname, pg, 0) != 0) { 1733 if (scf_error() == SCF_ERROR_NOT_FOUND) { 1734 char *p = strrchr(pgname, '.'); 1735 1736 if (p != NULL) { 1737 *p = ','; 1738 /* 1739 * since the resulting string is shorter, 1740 * there is no risk of buffer overflow 1741 */ 1742 (void) strcpy(p + 1, SCF_NOTIFY_PG_POSTFIX); 1743 continue; 1744 } 1745 } 1746 1747 if (check_scf_error(scf_error(), errs_1)) { 1748 goto cleanup; 1749 } 1750 } 1751 1752 if (nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0) { 1753 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1754 goto cleanup; 1755 } 1756 1757 if (_scf_notify_get_params(pg, params) != SCF_SUCCESS) 1758 goto cleanup; 1759 1760 if (getsource && get_pg_source(pg, params) != SCF_SUCCESS) 1761 goto cleanup; 1762 1763 if (nvlist_add_nvlist_array(nvl, SCF_NOTIFY_PARAMS, ¶ms, 1) != 0 || 1764 nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION, 1765 SCF_NOTIFY_PARAMS_VERSION) != 0) { 1766 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1767 goto cleanup; 1768 } 1769 1770 r = SCF_SUCCESS; 1771 1772 cleanup: 1773 nvlist_free(params); 1774 scf_pg_destroy(pg); 1775 scf_instance_destroy(i); 1776 scf_handle_destroy(h); 1777 free(pgname); 1778 1779 return (r); 1780 } 1781 1782 /* 1783 * Retrieve the notification parameters for the Event described in the 1784 * input nvlist_t nvl. 1785 * The function will allocate an nvlist_t to store the notification 1786 * parameters. The notification parameters in the output nvlist will have 1787 * the following format: 1788 * 1789 * version (uint32_t) 1790 * SCF_NOTIFY_PARAMS (array of embedded nvlists) 1791 * (start of notify-params[0]) 1792 * tset (int32_t) 1793 * <mechanism-name> (embedded nvlist) 1794 * <parameter-name> <parameter-type> 1795 * ... 1796 * (end <mechanism-name>) 1797 * ... 1798 * (end of notify-params[0]) 1799 * ... 1800 * 1801 * return SCF_SUCCESS or SCF_FAILED on 1802 * SCF_ERROR_BACKEND_ACCESS 1803 * SCF_ERROR_CONNECTION_BROKEN 1804 * SCF_ERROR_DELETED 1805 * SCF_ERROR_INTERNAL 1806 * SCF_ERROR_INVALID_ARGUMENT 1807 * SCF_ERROR_NO_MEMORY 1808 * SCF_ERROR_NO_RESOURCES 1809 * SCF_ERROR_NOT_FOUND 1810 * SCF_ERROR_PERMISSION_DENIED 1811 */ 1812 int 1813 smf_notify_get_params(nvlist_t **params, nvlist_t *nvl) 1814 { 1815 char *class; 1816 char *from; /* from state */ 1817 char *to; /* to state */ 1818 nvlist_t *attr; 1819 char *fmri; 1820 int32_t tset = 0; 1821 int r = SCF_FAILED; 1822 1823 if (params == NULL || nvlist_lookup_string(nvl, "class", &class) != 0) { 1824 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1825 return (r); 1826 } 1827 if (nvlist_alloc(params, NV_UNIQUE_NAME, 0) != 0) { 1828 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1829 return (r); 1830 } 1831 1832 if (is_svc_stn(class)) { 1833 if (nvlist_lookup_nvlist(nvl, "attr", &attr) != 0 || 1834 nvlist_lookup_string(attr, "svc-string", &fmri) != 0 || 1835 nvlist_lookup_string(attr, "from-state", &from) != 0 || 1836 nvlist_lookup_string(attr, "to-state", &to) != 0) { 1837 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1838 goto cleanup; 1839 } 1840 1841 tset = SCF_TRANS(smf_state_from_string(from), 1842 smf_state_from_string(to)); 1843 if (!SCF_TRANS_VALID(tset)) { 1844 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1845 goto cleanup; 1846 } 1847 tset |= class_to_transition(class); 1848 1849 r = _scf_get_svc_notify_params(fmri, *params, tset, 0, 1); 1850 } else { 1851 r = _scf_get_fma_notify_params(class, *params, 0); 1852 } 1853 1854 cleanup: 1855 if (r == SCF_FAILED) { 1856 nvlist_free(*params); 1857 *params = NULL; 1858 } 1859 1860 return (r); 1861 } 1862 1863 /* 1864 * return SCF_SUCCESS or SCF_FAILED on 1865 * SCF_ERROR_BACKEND_ACCESS 1866 * SCF_ERROR_BACKEND_READONLY 1867 * SCF_ERROR_CONNECTION_BROKEN 1868 * SCF_ERROR_DELETED 1869 * SCF_ERROR_INTERNAL 1870 * SCF_ERROR_INVALID_ARGUMENT 1871 * SCF_ERROR_NO_MEMORY 1872 * SCF_ERROR_NO_RESOURCES 1873 * SCF_ERROR_NOT_FOUND 1874 * SCF_ERROR_PERMISSION_DENIED 1875 */ 1876 int 1877 smf_notify_del_params(const char *class, const char *fmri, int32_t tset) 1878 { 1879 scf_handle_t *h = _scf_handle_create_and_bind(SCF_VERSION); 1880 scf_error_t scf_e = scf_error(); 1881 scf_service_t *s = scf_service_create(h); 1882 scf_instance_t *i = scf_instance_create(h); 1883 scf_propertygroup_t *pg = scf_pg_create(h); 1884 int r = SCF_FAILED; 1885 char *pgname = NULL; 1886 int j; 1887 1888 if (class == NULL) { 1889 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1890 goto cleanup; 1891 } 1892 1893 if (h == NULL) { 1894 /* 1895 * use saved error if _scf_handle_create_and_bind() fails 1896 */ 1897 (void) scf_set_error(scf_e); 1898 goto cleanup; 1899 } 1900 if (s == NULL || i == NULL || pg == NULL) 1901 goto cleanup; 1902 1903 if (is_svc_stn(class)) { 1904 tset |= class_to_transition(class); 1905 1906 if (!SCF_TRANS_VALID(tset) || fmri == NULL) { 1907 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1908 goto cleanup; 1909 } 1910 1911 if (decode_fmri(fmri, h, &s, &i) != SCF_SUCCESS) { 1912 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) 1913 (void) scf_set_error( 1914 SCF_ERROR_INVALID_ARGUMENT); 1915 if (check_scf_error(scf_error(), errs_1)) { 1916 goto cleanup; 1917 } 1918 } 1919 1920 for (j = 0; st_pgnames[j].st_pgname != NULL; ++j) { 1921 /* if this transition is not in the tset, continue */ 1922 if (!(tset & st_pgnames[j].st_state)) 1923 continue; 1924 1925 if (del_pg(s, i, st_pgnames[j].st_pgname, pg) != 1926 SCF_SUCCESS && 1927 scf_error() != SCF_ERROR_DELETED && 1928 scf_error() != SCF_ERROR_NOT_FOUND) { 1929 if (check_scf_error(scf_error(), 1930 errs_1)) { 1931 goto cleanup; 1932 } 1933 } 1934 } 1935 if (s == NULL) { 1936 /* We only need to refresh the instance */ 1937 if (_smf_refresh_instance_i(i) != 0 && 1938 check_scf_error(scf_error(), errs_1)) 1939 goto cleanup; 1940 } else { 1941 /* We have to refresh all instances in the service */ 1942 if (_smf_refresh_all_instances(s) != 0 && 1943 check_scf_error(scf_error(), errs_1)) 1944 goto cleanup; 1945 } 1946 } else { 1947 if ((pgname = class_to_pgname(class)) == NULL) 1948 goto cleanup; 1949 1950 if (scf_handle_decode_fmri(h, SCF_NOTIFY_PARAMS_INST, NULL, 1951 NULL, i, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 1952 goto cleanup; 1953 1954 if (del_pg(NULL, i, pgname, pg) != SCF_SUCCESS && 1955 scf_error() != SCF_ERROR_DELETED && 1956 scf_error() != SCF_ERROR_NOT_FOUND) { 1957 if (check_scf_error(scf_error(), errs_1)) { 1958 goto cleanup; 1959 } 1960 } 1961 1962 if (_smf_refresh_instance_i(i) != 0 && 1963 check_scf_error(scf_error(), errs_1)) 1964 goto cleanup; 1965 } 1966 1967 1968 r = SCF_SUCCESS; 1969 1970 cleanup: 1971 scf_pg_destroy(pg); 1972 scf_instance_destroy(i); 1973 scf_service_destroy(s); 1974 scf_handle_destroy(h); 1975 free(pgname); 1976 1977 return (r); 1978 } 1979