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 #include "libscf_impl.h" 30 31 #include <libuutil.h> 32 #include <stdio.h> 33 #include <strings.h> 34 #include <string.h> 35 #include <stdlib.h> 36 #include "midlevel_impl.h" 37 38 39 #ifndef NDEBUG 40 #define bad_error(func, err) { \ 41 uu_warn("%s:%d: %s failed with unexpected error %d. Aborting.\n", \ 42 __FILE__, __LINE__, func, err); \ 43 abort(); \ 44 } 45 #else 46 #define bad_error(func, err) abort() 47 #endif 48 49 /* 50 * Internal private function that creates and binds a handle. 51 */ 52 static scf_handle_t * 53 handle_create(void) 54 { 55 scf_handle_t *h; 56 57 h = scf_handle_create(SCF_VERSION); 58 if (h == NULL) 59 return (NULL); 60 61 if (scf_handle_bind(h) == -1) { 62 scf_handle_destroy(h); 63 return (NULL); 64 } 65 return (h); 66 } 67 68 /* 69 * Given a base service FMRI and the names of a property group and property, 70 * assemble_fmri() merges them into a property FMRI. Note that if the base 71 * FMRI is NULL, assemble_fmri() gets the base FMRI from scf_myname(). 72 */ 73 74 static char * 75 assemble_fmri(scf_handle_t *h, const char *base, const char *pg, 76 const char *prop) 77 { 78 size_t fmri_sz, pglen; 79 ssize_t baselen; 80 char *fmri_buf; 81 82 if (prop == NULL) { 83 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 84 return (NULL); 85 } 86 87 if (pg == NULL) 88 pglen = strlen(SCF_PG_APP_DEFAULT); 89 else 90 pglen = strlen(pg); 91 92 if (base == NULL) { 93 if ((baselen = scf_myname(h, NULL, 0)) == -1) 94 return (NULL); 95 } else { 96 baselen = strlen(base); 97 } 98 99 fmri_sz = baselen + sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1 + 100 pglen + sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1 + 101 strlen(prop) + 1; 102 103 if ((fmri_buf = malloc(fmri_sz)) == NULL) { 104 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 105 return (NULL); 106 } 107 108 if (base == NULL) { 109 if (scf_myname(h, fmri_buf, fmri_sz) == -1) { 110 free(fmri_buf); 111 return (NULL); 112 } 113 } else { 114 (void) strcpy(fmri_buf, base); 115 } 116 117 (void) strcat(fmri_buf, SCF_FMRI_PROPERTYGRP_PREFIX); 118 119 if (pg == NULL) 120 (void) strcat(fmri_buf, SCF_PG_APP_DEFAULT); 121 else 122 (void) strcat(fmri_buf, pg); 123 124 (void) strcat(fmri_buf, SCF_FMRI_PROPERTY_PREFIX); 125 (void) strcat(fmri_buf, prop); 126 return (fmri_buf); 127 } 128 129 /* 130 * Given a property, this function allocates and fills an scf_simple_prop_t 131 * with the data it contains. 132 */ 133 134 static scf_simple_prop_t * 135 fill_prop(scf_property_t *prop, const char *pgname, const char *propname, 136 scf_handle_t *h) 137 { 138 scf_simple_prop_t *ret; 139 scf_iter_t *iter; 140 scf_value_t *val; 141 int iterret, i; 142 ssize_t valsize, numvals; 143 union scf_simple_prop_val *vallist = NULL, *vallist_backup = NULL; 144 145 if ((ret = malloc(sizeof (*ret))) == NULL) { 146 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 147 return (NULL); 148 } 149 150 ret->pr_next = NULL; 151 ret->pr_pg = NULL; 152 ret->pr_iter = 0; 153 154 if (pgname == NULL) 155 ret->pr_pgname = strdup(SCF_PG_APP_DEFAULT); 156 else 157 ret->pr_pgname = strdup(pgname); 158 159 if (ret->pr_pgname == NULL) { 160 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 161 free(ret); 162 return (NULL); 163 } 164 165 if ((ret->pr_propname = strdup(propname)) == NULL) { 166 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 167 free(ret->pr_pgname); 168 free(ret); 169 return (NULL); 170 } 171 172 if (scf_property_type(prop, &ret->pr_type) == -1) 173 goto error3; 174 175 if ((iter = scf_iter_create(h)) == NULL) 176 goto error3; 177 if ((val = scf_value_create(h)) == NULL) { 178 scf_iter_destroy(iter); 179 goto error3; 180 } 181 182 if (scf_iter_property_values(iter, prop) == -1) 183 goto error1; 184 185 for (numvals = 0; (iterret = scf_iter_next_value(iter, val)) == 1; 186 numvals++) { 187 vallist_backup = vallist; 188 if ((vallist = realloc(vallist, (numvals + 1) * 189 sizeof (*vallist))) == NULL) { 190 vallist = vallist_backup; 191 goto error1; 192 } 193 194 switch (ret->pr_type) { 195 case SCF_TYPE_BOOLEAN: 196 if (scf_value_get_boolean(val, 197 &vallist[numvals].pv_bool) == -1) 198 goto error1; 199 break; 200 201 case SCF_TYPE_COUNT: 202 if (scf_value_get_count(val, 203 &vallist[numvals].pv_uint) == -1) 204 goto error1; 205 break; 206 207 case SCF_TYPE_INTEGER: 208 if (scf_value_get_integer(val, 209 &vallist[numvals].pv_int) == -1) 210 goto error1; 211 break; 212 213 case SCF_TYPE_TIME: 214 if (scf_value_get_time(val, 215 &vallist[numvals].pv_time.t_sec, 216 &vallist[numvals].pv_time.t_nsec) == -1) 217 goto error1; 218 break; 219 220 case SCF_TYPE_ASTRING: 221 vallist[numvals].pv_str = NULL; 222 if ((valsize = scf_value_get_astring(val, NULL, 0)) == 223 -1) 224 goto error1; 225 if ((vallist[numvals].pv_str = malloc(valsize+1)) == 226 NULL) { 227 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 228 goto error1; 229 } 230 if (scf_value_get_astring(val, 231 vallist[numvals].pv_str, valsize+1) == -1) { 232 free(vallist[numvals].pv_str); 233 goto error1; 234 } 235 break; 236 237 case SCF_TYPE_USTRING: 238 case SCF_TYPE_HOST: 239 case SCF_TYPE_HOSTNAME: 240 case SCF_TYPE_NET_ADDR_V4: 241 case SCF_TYPE_NET_ADDR_V6: 242 case SCF_TYPE_URI: 243 case SCF_TYPE_FMRI: 244 vallist[numvals].pv_str = NULL; 245 if ((valsize = scf_value_get_ustring(val, NULL, 0)) == 246 -1) 247 goto error1; 248 if ((vallist[numvals].pv_str = malloc(valsize+1)) == 249 NULL) { 250 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 251 goto error1; 252 } 253 if (scf_value_get_ustring(val, 254 vallist[numvals].pv_str, valsize+1) == -1) { 255 free(vallist[numvals].pv_str); 256 goto error1; 257 } 258 break; 259 260 case SCF_TYPE_OPAQUE: 261 vallist[numvals].pv_opaque.o_value = NULL; 262 if ((valsize = scf_value_get_opaque(val, NULL, 0)) == 263 -1) 264 goto error1; 265 if ((vallist[numvals].pv_opaque.o_value = 266 malloc(valsize)) == NULL) { 267 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 268 goto error1; 269 } 270 vallist[numvals].pv_opaque.o_size = valsize; 271 if (scf_value_get_opaque(val, 272 vallist[numvals].pv_opaque.o_value, 273 valsize) == -1) { 274 free(vallist[numvals].pv_opaque.o_value); 275 goto error1; 276 } 277 break; 278 279 default: 280 (void) scf_set_error(SCF_ERROR_INTERNAL); 281 goto error1; 282 283 } 284 } 285 286 if (iterret == -1) { 287 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 288 (void) scf_set_error(SCF_ERROR_INTERNAL); 289 goto error1; 290 } 291 292 ret->pr_vallist = vallist; 293 ret->pr_numvalues = numvals; 294 295 scf_iter_destroy(iter); 296 (void) scf_value_destroy(val); 297 298 return (ret); 299 300 /* 301 * Exit point for a successful call. Below this line are exit points 302 * for failures at various stages during the function. 303 */ 304 305 error1: 306 if (vallist == NULL) 307 goto error2; 308 309 switch (ret->pr_type) { 310 case SCF_TYPE_ASTRING: 311 case SCF_TYPE_USTRING: 312 case SCF_TYPE_HOST: 313 case SCF_TYPE_HOSTNAME: 314 case SCF_TYPE_NET_ADDR_V4: 315 case SCF_TYPE_NET_ADDR_V6: 316 case SCF_TYPE_URI: 317 case SCF_TYPE_FMRI: { 318 for (i = 0; i < numvals; i++) { 319 free(vallist[i].pv_str); 320 } 321 break; 322 } 323 case SCF_TYPE_OPAQUE: { 324 for (i = 0; i < numvals; i++) { 325 free(vallist[i].pv_opaque.o_value); 326 } 327 break; 328 } 329 default: 330 break; 331 } 332 333 free(vallist); 334 335 error2: 336 scf_iter_destroy(iter); 337 (void) scf_value_destroy(val); 338 339 error3: 340 free(ret->pr_pgname); 341 free(ret->pr_propname); 342 free(ret); 343 return (NULL); 344 } 345 346 /* 347 * insert_app_props iterates over a property iterator, getting all the 348 * properties from a property group, and adding or overwriting them into 349 * a simple_app_props_t. This is used by scf_simple_app_props_get to provide 350 * service/instance composition while filling the app_props_t. 351 * insert_app_props iterates over a single property group. 352 */ 353 354 static int 355 insert_app_props(scf_iter_t *propiter, char *pgname, char *propname, struct 356 scf_simple_pg *thispg, scf_property_t *prop, size_t namelen, 357 scf_handle_t *h) 358 { 359 scf_simple_prop_t *thisprop, *prevprop, *newprop; 360 uint8_t found; 361 int propiter_ret; 362 363 while ((propiter_ret = scf_iter_next_property(propiter, prop)) == 1) { 364 365 if (scf_property_get_name(prop, propname, namelen) < 0) { 366 if (scf_error() == SCF_ERROR_NOT_SET) 367 (void) scf_set_error(SCF_ERROR_INTERNAL); 368 return (-1); 369 } 370 371 thisprop = thispg->pg_proplist; 372 prevprop = thispg->pg_proplist; 373 found = 0; 374 375 while ((thisprop != NULL) && (!found)) { 376 if (strcmp(thisprop->pr_propname, propname) == 0) { 377 found = 1; 378 if ((newprop = fill_prop(prop, pgname, 379 propname, h)) == NULL) 380 return (-1); 381 382 if (thisprop == thispg->pg_proplist) 383 thispg->pg_proplist = newprop; 384 else 385 prevprop->pr_next = newprop; 386 387 newprop->pr_pg = thispg; 388 newprop->pr_next = thisprop->pr_next; 389 scf_simple_prop_free(thisprop); 390 thisprop = NULL; 391 } else { 392 if (thisprop != thispg->pg_proplist) 393 prevprop = prevprop->pr_next; 394 thisprop = thisprop->pr_next; 395 } 396 } 397 398 if (!found) { 399 if ((newprop = fill_prop(prop, pgname, propname, h)) == 400 NULL) 401 return (-1); 402 403 if (thispg->pg_proplist == NULL) 404 thispg->pg_proplist = newprop; 405 else 406 prevprop->pr_next = newprop; 407 408 newprop->pr_pg = thispg; 409 } 410 } 411 412 if (propiter_ret == -1) { 413 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 414 (void) scf_set_error(SCF_ERROR_INTERNAL); 415 return (-1); 416 } 417 418 return (0); 419 } 420 421 422 /* 423 * Sets up e in tx to set pname's values. Returns 0 on success or -1 on 424 * failure, with scf_error() set to 425 * SCF_ERROR_HANDLE_MISMATCH - tx & e are derived from different handles 426 * SCF_ERROR_INVALID_ARGUMENT - pname or ty are invalid 427 * SCF_ERROR_NOT_BOUND - handle is not bound 428 * SCF_ERROR_CONNECTION_BROKEN - connection was broken 429 * SCF_ERROR_NOT_SET - tx has not been started 430 * SCF_ERROR_DELETED - the pg tx was started on was deleted 431 */ 432 static int 433 transaction_property_set(scf_transaction_t *tx, scf_transaction_entry_t *e, 434 const char *pname, scf_type_t ty) 435 { 436 for (;;) { 437 if (scf_transaction_property_change_type(tx, e, pname, ty) == 0) 438 return (0); 439 440 switch (scf_error()) { 441 case SCF_ERROR_HANDLE_MISMATCH: 442 case SCF_ERROR_INVALID_ARGUMENT: 443 case SCF_ERROR_NOT_BOUND: 444 case SCF_ERROR_CONNECTION_BROKEN: 445 case SCF_ERROR_NOT_SET: 446 case SCF_ERROR_DELETED: 447 default: 448 return (-1); 449 450 case SCF_ERROR_NOT_FOUND: 451 break; 452 } 453 454 if (scf_transaction_property_new(tx, e, pname, ty) == 0) 455 return (0); 456 457 switch (scf_error()) { 458 case SCF_ERROR_HANDLE_MISMATCH: 459 case SCF_ERROR_INVALID_ARGUMENT: 460 case SCF_ERROR_NOT_BOUND: 461 case SCF_ERROR_CONNECTION_BROKEN: 462 case SCF_ERROR_NOT_SET: 463 case SCF_ERROR_DELETED: 464 default: 465 return (-1); 466 467 case SCF_ERROR_EXISTS: 468 break; 469 } 470 } 471 } 472 473 static int 474 get_inst_enabled(const scf_instance_t *inst, const char *pgname) 475 { 476 scf_propertygroup_t *gpg = NULL; 477 scf_property_t *eprop = NULL; 478 scf_value_t *v = NULL; 479 scf_handle_t *h = NULL; 480 uint8_t enabled; 481 int ret = -1; 482 483 if ((h = scf_instance_handle(inst)) == NULL) 484 return (-1); 485 486 if ((gpg = scf_pg_create(h)) == NULL || 487 (eprop = scf_property_create(h)) == NULL || 488 (v = scf_value_create(h)) == NULL) 489 goto out; 490 491 if (scf_instance_get_pg(inst, pgname, gpg) || 492 scf_pg_get_property(gpg, SCF_PROPERTY_ENABLED, eprop) || 493 scf_property_get_value(eprop, v) || 494 scf_value_get_boolean(v, &enabled)) 495 goto out; 496 ret = enabled; 497 498 out: 499 scf_pg_destroy(gpg); 500 scf_property_destroy(eprop); 501 scf_value_destroy(v); 502 return (ret); 503 } 504 505 /* 506 * set_inst_enabled() is a "master" enable/disable call that takes the 507 * instance and the desired state for the enabled bit in the instance's 508 * named property group. If the group doesn't exist, it's created with the 509 * given flags. Called by smf_{dis,en}able_instance(). 510 */ 511 static int 512 set_inst_enabled(const scf_instance_t *inst, uint8_t desired, 513 const char *pgname, uint32_t pgflags) 514 { 515 scf_transaction_t *tx = NULL; 516 scf_transaction_entry_t *ent = NULL; 517 scf_propertygroup_t *gpg = NULL; 518 scf_property_t *eprop = NULL; 519 scf_value_t *v = NULL; 520 scf_handle_t *h = NULL; 521 int ret = -1; 522 int committed; 523 uint8_t b; 524 525 if ((h = scf_instance_handle(inst)) == NULL) 526 return (-1); 527 528 if ((gpg = scf_pg_create(h)) == NULL || 529 (eprop = scf_property_create(h)) == NULL || 530 (v = scf_value_create(h)) == NULL || 531 (tx = scf_transaction_create(h)) == NULL || 532 (ent = scf_entry_create(h)) == NULL) 533 goto out; 534 535 get: 536 if (scf_instance_get_pg(inst, pgname, gpg) == -1) { 537 if (scf_error() != SCF_ERROR_NOT_FOUND) 538 goto out; 539 540 if (scf_instance_add_pg(inst, pgname, SCF_GROUP_FRAMEWORK, 541 pgflags, gpg) == -1) { 542 if (scf_error() != SCF_ERROR_EXISTS) 543 goto out; 544 goto get; 545 } 546 } 547 if (scf_pg_get_property(gpg, SCF_PROPERTY_ENABLED, eprop) == -1) { 548 if (scf_error() != SCF_ERROR_NOT_FOUND) 549 goto out; 550 else 551 goto set; 552 } 553 554 /* 555 * If it's already set the way we want, forgo the transaction. 556 */ 557 if (scf_property_get_value(eprop, v) == -1) { 558 switch (scf_error()) { 559 case SCF_ERROR_CONSTRAINT_VIOLATED: 560 case SCF_ERROR_NOT_FOUND: 561 /* Misconfigured, so set anyway. */ 562 goto set; 563 564 default: 565 goto out; 566 } 567 } 568 if (scf_value_get_boolean(v, &b) == -1) { 569 if (scf_error() != SCF_ERROR_TYPE_MISMATCH) 570 goto out; 571 goto set; 572 } 573 if (b == desired) { 574 ret = 0; 575 goto out; 576 } 577 578 set: 579 do { 580 if (scf_transaction_start(tx, gpg) == -1) 581 goto out; 582 583 if (transaction_property_set(tx, ent, SCF_PROPERTY_ENABLED, 584 SCF_TYPE_BOOLEAN) != 0) { 585 switch (scf_error()) { 586 case SCF_ERROR_CONNECTION_BROKEN: 587 case SCF_ERROR_DELETED: 588 default: 589 goto out; 590 591 case SCF_ERROR_HANDLE_MISMATCH: 592 case SCF_ERROR_INVALID_ARGUMENT: 593 case SCF_ERROR_NOT_BOUND: 594 case SCF_ERROR_NOT_SET: 595 bad_error("transaction_property_set", 596 scf_error()); 597 } 598 } 599 600 scf_value_set_boolean(v, desired); 601 if (scf_entry_add_value(ent, v) == -1) 602 goto out; 603 604 committed = scf_transaction_commit(tx); 605 if (committed == -1) 606 goto out; 607 608 scf_transaction_reset(tx); 609 610 if (committed == 0) { /* out-of-sync */ 611 if (scf_pg_update(gpg) == -1) 612 goto out; 613 } 614 } while (committed == 0); 615 616 ret = 0; 617 618 out: 619 scf_value_destroy(v); 620 scf_entry_destroy(ent); 621 scf_transaction_destroy(tx); 622 scf_property_destroy(eprop); 623 scf_pg_destroy(gpg); 624 625 return (ret); 626 } 627 628 static int 629 delete_inst_enabled(const scf_instance_t *inst, const char *pgname) 630 { 631 scf_transaction_t *tx = NULL; 632 scf_transaction_entry_t *ent = NULL; 633 scf_propertygroup_t *gpg = NULL; 634 scf_handle_t *h = NULL; 635 int ret = -1; 636 int committed; 637 638 if ((h = scf_instance_handle(inst)) == NULL) 639 return (-1); 640 641 if ((gpg = scf_pg_create(h)) == NULL || 642 (tx = scf_transaction_create(h)) == NULL || 643 (ent = scf_entry_create(h)) == NULL) 644 goto out; 645 646 if (scf_instance_get_pg(inst, pgname, gpg) != 0) 647 goto error; 648 do { 649 if (scf_transaction_start(tx, gpg) == -1 || 650 scf_transaction_property_delete(tx, ent, 651 SCF_PROPERTY_ENABLED) == -1 || 652 (committed = scf_transaction_commit(tx)) == -1) 653 goto error; 654 655 scf_transaction_reset(tx); 656 657 if (committed == 0 && scf_pg_update(gpg) == -1) 658 goto error; 659 } while (committed == 0); 660 661 ret = 0; 662 goto out; 663 664 error: 665 switch (scf_error()) { 666 case SCF_ERROR_DELETED: 667 case SCF_ERROR_NOT_FOUND: 668 /* success */ 669 ret = 0; 670 } 671 672 out: 673 scf_entry_destroy(ent); 674 scf_transaction_destroy(tx); 675 scf_pg_destroy(gpg); 676 677 return (ret); 678 } 679 680 /* 681 * Returns 0 on success or -1 on failure. On failure leaves scf_error() set to 682 * SCF_ERROR_HANDLE_DESTROYED - inst's handle has been destroyed 683 * SCF_ERROR_NOT_BOUND - inst's handle is not bound 684 * SCF_ERROR_CONNECTION_BROKEN - the repository connection was broken 685 * SCF_ERROR_NOT_SET - inst is not set 686 * SCF_ERROR_DELETED - inst was deleted 687 * SCF_ERROR_PERMISSION_DENIED 688 * SCF_ERROR_BACKEND_ACCESS 689 * SCF_ERROR_BACKEND_READONLY 690 */ 691 static int 692 set_inst_action_inst(scf_instance_t *inst, const char *action) 693 { 694 scf_handle_t *h; 695 scf_transaction_t *tx = NULL; 696 scf_transaction_entry_t *ent = NULL; 697 scf_propertygroup_t *pg = NULL; 698 scf_property_t *prop = NULL; 699 scf_value_t *v = NULL; 700 int trans, ret = -1; 701 int64_t t; 702 hrtime_t timestamp; 703 704 if ((h = scf_instance_handle(inst)) == NULL || 705 (pg = scf_pg_create(h)) == NULL || 706 (prop = scf_property_create(h)) == NULL || 707 (v = scf_value_create(h)) == NULL || 708 (tx = scf_transaction_create(h)) == NULL || 709 (ent = scf_entry_create(h)) == NULL) 710 goto out; 711 712 get: 713 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER_ACTIONS, pg) == -1) { 714 switch (scf_error()) { 715 case SCF_ERROR_NOT_BOUND: 716 case SCF_ERROR_CONNECTION_BROKEN: 717 case SCF_ERROR_NOT_SET: 718 case SCF_ERROR_DELETED: 719 default: 720 goto out; 721 722 case SCF_ERROR_NOT_FOUND: 723 break; 724 725 case SCF_ERROR_HANDLE_MISMATCH: 726 case SCF_ERROR_INVALID_ARGUMENT: 727 bad_error("scf_instance_get_pg", scf_error()); 728 } 729 730 /* Try creating the restarter_actions property group. */ 731 add: 732 if (scf_instance_add_pg(inst, SCF_PG_RESTARTER_ACTIONS, 733 SCF_PG_RESTARTER_ACTIONS_TYPE, 734 SCF_PG_RESTARTER_ACTIONS_FLAGS, pg) == -1) { 735 switch (scf_error()) { 736 case SCF_ERROR_NOT_BOUND: 737 case SCF_ERROR_CONNECTION_BROKEN: 738 case SCF_ERROR_NOT_SET: 739 case SCF_ERROR_DELETED: 740 case SCF_ERROR_PERMISSION_DENIED: 741 case SCF_ERROR_BACKEND_ACCESS: 742 case SCF_ERROR_BACKEND_READONLY: 743 default: 744 goto out; 745 746 case SCF_ERROR_EXISTS: 747 goto get; 748 749 case SCF_ERROR_HANDLE_MISMATCH: 750 case SCF_ERROR_INVALID_ARGUMENT: 751 bad_error("scf_instance_add_pg", scf_error()); 752 } 753 } 754 } 755 756 for (;;) { 757 timestamp = gethrtime(); 758 759 if (scf_pg_get_property(pg, action, prop) != 0) { 760 switch (scf_error()) { 761 case SCF_ERROR_CONNECTION_BROKEN: 762 default: 763 goto out; 764 765 case SCF_ERROR_DELETED: 766 goto add; 767 768 case SCF_ERROR_NOT_FOUND: 769 break; 770 771 case SCF_ERROR_HANDLE_MISMATCH: 772 case SCF_ERROR_INVALID_ARGUMENT: 773 case SCF_ERROR_NOT_BOUND: 774 case SCF_ERROR_NOT_SET: 775 bad_error("scf_pg_get_property", scf_error()); 776 } 777 } else if (scf_property_get_value(prop, v) != 0) { 778 switch (scf_error()) { 779 case SCF_ERROR_CONNECTION_BROKEN: 780 default: 781 goto out; 782 783 case SCF_ERROR_DELETED: 784 goto add; 785 786 case SCF_ERROR_CONSTRAINT_VIOLATED: 787 case SCF_ERROR_NOT_FOUND: 788 break; 789 790 case SCF_ERROR_HANDLE_MISMATCH: 791 case SCF_ERROR_NOT_BOUND: 792 case SCF_ERROR_NOT_SET: 793 bad_error("scf_property_get_value", 794 scf_error()); 795 } 796 } else if (scf_value_get_integer(v, &t) != 0) { 797 bad_error("scf_value_get_integer", scf_error()); 798 } else if (t > timestamp) { 799 break; 800 } 801 802 if (scf_transaction_start(tx, pg) == -1) { 803 switch (scf_error()) { 804 case SCF_ERROR_NOT_BOUND: 805 case SCF_ERROR_CONNECTION_BROKEN: 806 case SCF_ERROR_PERMISSION_DENIED: 807 case SCF_ERROR_BACKEND_ACCESS: 808 case SCF_ERROR_BACKEND_READONLY: 809 default: 810 goto out; 811 812 case SCF_ERROR_DELETED: 813 goto add; 814 815 case SCF_ERROR_HANDLE_MISMATCH: 816 case SCF_ERROR_NOT_SET: 817 case SCF_ERROR_IN_USE: 818 bad_error("scf_transaction_start", scf_error()); 819 } 820 } 821 822 if (transaction_property_set(tx, ent, action, 823 SCF_TYPE_INTEGER) != 0) { 824 switch (scf_error()) { 825 case SCF_ERROR_NOT_BOUND: 826 case SCF_ERROR_CONNECTION_BROKEN: 827 case SCF_ERROR_DELETED: 828 default: 829 goto out; 830 831 case SCF_ERROR_HANDLE_MISMATCH: 832 case SCF_ERROR_INVALID_ARGUMENT: 833 case SCF_ERROR_NOT_SET: 834 bad_error("transaction_property_set", 835 scf_error()); 836 } 837 } 838 839 scf_value_set_integer(v, timestamp); 840 if (scf_entry_add_value(ent, v) == -1) 841 bad_error("scf_entry_add_value", scf_error()); 842 843 trans = scf_transaction_commit(tx); 844 if (trans == 1) 845 break; 846 847 if (trans != 0) { 848 switch (scf_error()) { 849 case SCF_ERROR_CONNECTION_BROKEN: 850 case SCF_ERROR_PERMISSION_DENIED: 851 case SCF_ERROR_BACKEND_ACCESS: 852 case SCF_ERROR_BACKEND_READONLY: 853 default: 854 goto out; 855 856 case SCF_ERROR_DELETED: 857 scf_transaction_reset(tx); 858 goto add; 859 860 case SCF_ERROR_INVALID_ARGUMENT: 861 case SCF_ERROR_NOT_BOUND: 862 case SCF_ERROR_NOT_SET: 863 bad_error("scf_transaction_commit", 864 scf_error()); 865 } 866 } 867 868 scf_transaction_reset(tx); 869 if (scf_pg_update(pg) != 0) { 870 switch (scf_error()) { 871 case SCF_ERROR_CONNECTION_BROKEN: 872 default: 873 goto out; 874 875 case SCF_ERROR_DELETED: 876 goto add; 877 878 case SCF_ERROR_NOT_SET: 879 case SCF_ERROR_NOT_BOUND: 880 bad_error("scf_pg_update", scf_error()); 881 } 882 } 883 } 884 885 ret = 0; 886 887 out: 888 scf_value_destroy(v); 889 scf_entry_destroy(ent); 890 scf_transaction_destroy(tx); 891 scf_property_destroy(prop); 892 scf_pg_destroy(pg); 893 return (ret); 894 } 895 896 static int 897 set_inst_action(const char *fmri, const char *action) 898 { 899 scf_handle_t *h; 900 scf_instance_t *inst; 901 int ret = -1; 902 903 h = handle_create(); 904 if (h == NULL) 905 return (-1); 906 907 inst = scf_instance_create(h); 908 909 if (inst != NULL) { 910 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, 911 NULL, SCF_DECODE_FMRI_EXACT) == 0) 912 ret = set_inst_action_inst(inst, action); 913 else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) 914 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 915 916 scf_instance_destroy(inst); 917 } 918 919 scf_handle_destroy(h); 920 921 return (ret); 922 } 923 924 925 /* 926 * get_inst_state() gets the state string from an instance, and returns 927 * the SCF_STATE_* constant that coincides with the instance's current state. 928 */ 929 930 static int 931 get_inst_state(scf_instance_t *inst, scf_handle_t *h) 932 { 933 scf_propertygroup_t *pg = NULL; 934 scf_property_t *prop = NULL; 935 scf_value_t *val = NULL; 936 char state[MAX_SCF_STATE_STRING_SZ]; 937 int ret = -1; 938 939 if (((pg = scf_pg_create(h)) == NULL) || 940 ((prop = scf_property_create(h)) == NULL) || 941 ((val = scf_value_create(h)) == NULL)) 942 goto out; 943 944 /* Pull the state property from the instance */ 945 946 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) == -1 || 947 scf_pg_get_property(pg, SCF_PROPERTY_STATE, prop) == -1 || 948 scf_property_get_value(prop, val) == -1) { 949 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 950 (void) scf_set_error(SCF_ERROR_INTERNAL); 951 goto out; 952 } 953 954 if (scf_value_get_astring(val, state, sizeof (state)) <= 0) { 955 (void) scf_set_error(SCF_ERROR_INTERNAL); 956 goto out; 957 } 958 959 if (strcmp(state, SCF_STATE_STRING_UNINIT) == 0) { 960 ret = SCF_STATE_UNINIT; 961 } else if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) { 962 ret = SCF_STATE_MAINT; 963 } else if (strcmp(state, SCF_STATE_STRING_OFFLINE) == 0) { 964 ret = SCF_STATE_OFFLINE; 965 } else if (strcmp(state, SCF_STATE_STRING_DISABLED) == 0) { 966 ret = SCF_STATE_DISABLED; 967 } else if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0) { 968 ret = SCF_STATE_ONLINE; 969 } else if (strcmp(state, SCF_STATE_STRING_DEGRADED) == 0) { 970 ret = SCF_STATE_DEGRADED; 971 } 972 973 out: 974 scf_pg_destroy(pg); 975 scf_property_destroy(prop); 976 (void) scf_value_destroy(val); 977 978 return (ret); 979 } 980 981 /* 982 * Sets an instance to be enabled or disabled after reboot, using the 983 * temporary (overriding) general_ovr property group to reflect the 984 * present state, if it is different. 985 */ 986 static int 987 set_inst_enabled_atboot(scf_instance_t *inst, uint8_t desired) 988 { 989 int enabled; 990 int persistent; 991 int ret = -1; 992 993 if ((persistent = get_inst_enabled(inst, SCF_PG_GENERAL)) < 0) { 994 if (scf_error() != SCF_ERROR_NOT_FOUND) 995 goto out; 996 persistent = B_FALSE; 997 } 998 if ((enabled = get_inst_enabled(inst, SCF_PG_GENERAL_OVR)) < 0) { 999 enabled = persistent; 1000 if (persistent != desired) { 1001 /* 1002 * Temporarily store the present enabled state. 1003 */ 1004 if (set_inst_enabled(inst, persistent, 1005 SCF_PG_GENERAL_OVR, SCF_PG_GENERAL_OVR_FLAGS)) 1006 goto out; 1007 } 1008 } 1009 if (persistent != desired) 1010 if (set_inst_enabled(inst, desired, SCF_PG_GENERAL, 1011 SCF_PG_GENERAL_FLAGS)) 1012 goto out; 1013 if (enabled == desired) 1014 ret = delete_inst_enabled(inst, SCF_PG_GENERAL_OVR); 1015 else 1016 ret = 0; 1017 1018 out: 1019 return (ret); 1020 } 1021 1022 static int 1023 set_inst_enabled_flags(const char *fmri, int flags, uint8_t desired) 1024 { 1025 int ret = -1; 1026 scf_handle_t *h; 1027 scf_instance_t *inst; 1028 1029 if (flags & ~(SMF_TEMPORARY | SMF_AT_NEXT_BOOT) || 1030 flags & SMF_TEMPORARY && flags & SMF_AT_NEXT_BOOT) { 1031 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1032 return (ret); 1033 } 1034 1035 if ((h = handle_create()) == NULL) 1036 return (ret); 1037 1038 if ((inst = scf_instance_create(h)) == NULL) { 1039 scf_handle_destroy(h); 1040 return (ret); 1041 } 1042 1043 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, NULL, 1044 SCF_DECODE_FMRI_EXACT) == -1) { 1045 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) 1046 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1047 goto out; 1048 } 1049 1050 if (flags & SMF_AT_NEXT_BOOT) { 1051 ret = set_inst_enabled_atboot(inst, desired); 1052 } else { 1053 if (set_inst_enabled(inst, desired, flags & SMF_TEMPORARY ? 1054 SCF_PG_GENERAL_OVR : SCF_PG_GENERAL, flags & SMF_TEMPORARY ? 1055 SCF_PG_GENERAL_OVR_FLAGS : SCF_PG_GENERAL_FLAGS)) 1056 goto out; 1057 1058 /* 1059 * Make the persistent value effective by deleting the 1060 * temporary one. 1061 */ 1062 if (flags & SMF_TEMPORARY) 1063 ret = 0; 1064 else 1065 ret = delete_inst_enabled(inst, SCF_PG_GENERAL_OVR); 1066 } 1067 1068 out: 1069 scf_instance_destroy(inst); 1070 scf_handle_destroy(h); 1071 return (ret); 1072 } 1073 1074 int 1075 smf_enable_instance(const char *fmri, int flags) 1076 { 1077 return (set_inst_enabled_flags(fmri, flags, B_TRUE)); 1078 } 1079 1080 int 1081 smf_disable_instance(const char *fmri, int flags) 1082 { 1083 return (set_inst_enabled_flags(fmri, flags, B_FALSE)); 1084 } 1085 1086 int 1087 _smf_refresh_instance_i(scf_instance_t *inst) 1088 { 1089 return (set_inst_action_inst(inst, SCF_PROPERTY_REFRESH)); 1090 } 1091 1092 int 1093 smf_refresh_instance(const char *instance) 1094 { 1095 return (set_inst_action(instance, SCF_PROPERTY_REFRESH)); 1096 } 1097 1098 int 1099 smf_restart_instance(const char *instance) 1100 { 1101 return (set_inst_action(instance, SCF_PROPERTY_RESTART)); 1102 } 1103 1104 int 1105 smf_maintain_instance(const char *instance, int flags) 1106 { 1107 if (flags & SMF_TEMPORARY) 1108 return (set_inst_action(instance, 1109 (flags & SMF_IMMEDIATE) ? 1110 SCF_PROPERTY_MAINT_ON_IMMTEMP : 1111 SCF_PROPERTY_MAINT_ON_TEMPORARY)); 1112 else 1113 return (set_inst_action(instance, 1114 (flags & SMF_IMMEDIATE) ? 1115 SCF_PROPERTY_MAINT_ON_IMMEDIATE : 1116 SCF_PROPERTY_MAINT_ON)); 1117 } 1118 1119 int 1120 smf_degrade_instance(const char *instance, int flags) 1121 { 1122 scf_simple_prop_t *prop; 1123 const char *state_str; 1124 1125 if (flags & SMF_TEMPORARY) 1126 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 1127 1128 if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER, 1129 SCF_PROPERTY_STATE)) == NULL) 1130 return (SCF_FAILED); 1131 1132 if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) { 1133 scf_simple_prop_free(prop); 1134 return (SCF_FAILED); 1135 } 1136 1137 if (strcmp(state_str, SCF_STATE_STRING_ONLINE) != 0) { 1138 scf_simple_prop_free(prop); 1139 return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED)); 1140 } 1141 scf_simple_prop_free(prop); 1142 1143 return (set_inst_action(instance, (flags & SMF_IMMEDIATE) ? 1144 SCF_PROPERTY_DEGRADE_IMMEDIATE : SCF_PROPERTY_DEGRADED)); 1145 } 1146 1147 int 1148 smf_restore_instance(const char *instance) 1149 { 1150 scf_simple_prop_t *prop; 1151 const char *state_str; 1152 int ret; 1153 1154 if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER, 1155 SCF_PROPERTY_STATE)) == NULL) 1156 return (SCF_FAILED); 1157 1158 if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) { 1159 scf_simple_prop_free(prop); 1160 return (SCF_FAILED); 1161 } 1162 1163 if (strcmp(state_str, SCF_STATE_STRING_MAINT) == 0) { 1164 ret = set_inst_action(instance, SCF_PROPERTY_MAINT_OFF); 1165 } else if (strcmp(state_str, SCF_STATE_STRING_DEGRADED) == 0) { 1166 ret = set_inst_action(instance, SCF_PROPERTY_RESTORE); 1167 } else { 1168 ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED); 1169 } 1170 1171 scf_simple_prop_free(prop); 1172 return (ret); 1173 } 1174 1175 char * 1176 smf_get_state(const char *instance) 1177 { 1178 scf_simple_prop_t *prop; 1179 const char *state_str; 1180 char *ret; 1181 1182 if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER, 1183 SCF_PROPERTY_STATE)) == NULL) 1184 return (NULL); 1185 1186 if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) { 1187 scf_simple_prop_free(prop); 1188 return (NULL); 1189 } 1190 1191 if ((ret = strdup(state_str)) == NULL) 1192 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1193 1194 scf_simple_prop_free(prop); 1195 return (ret); 1196 } 1197 1198 int 1199 scf_simple_walk_instances(uint_t state_flags, void *private, 1200 int (*inst_callback)(scf_handle_t *, scf_instance_t *, void *)) 1201 { 1202 scf_scope_t *scope = NULL; 1203 scf_service_t *svc = NULL; 1204 scf_instance_t *inst = NULL; 1205 scf_iter_t *svc_iter = NULL, *inst_iter = NULL; 1206 scf_handle_t *h = NULL; 1207 int ret = SCF_FAILED; 1208 int svc_iter_ret, inst_iter_ret; 1209 int inst_state; 1210 1211 if ((h = handle_create()) == NULL) 1212 return (ret); 1213 1214 if (((scope = scf_scope_create(h)) == NULL) || 1215 ((svc = scf_service_create(h)) == NULL) || 1216 ((inst = scf_instance_create(h)) == NULL) || 1217 ((svc_iter = scf_iter_create(h)) == NULL) || 1218 ((inst_iter = scf_iter_create(h)) == NULL)) 1219 goto out; 1220 1221 /* 1222 * Get the local scope, and set up nested iteration through every 1223 * local service, and every instance of every service. 1224 */ 1225 1226 if ((scf_handle_get_local_scope(h, scope) != SCF_SUCCESS) || 1227 (scf_iter_scope_services(svc_iter, scope) != SCF_SUCCESS)) 1228 goto out; 1229 1230 while ((svc_iter_ret = scf_iter_next_service(svc_iter, svc)) > 0) { 1231 1232 if ((scf_iter_service_instances(inst_iter, svc)) != 1233 SCF_SUCCESS) 1234 goto out; 1235 1236 while ((inst_iter_ret = 1237 scf_iter_next_instance(inst_iter, inst)) > 0) { 1238 /* 1239 * If get_inst_state fails from an internal error, 1240 * IE, being unable to get the property group or 1241 * property containing the state of the instance, 1242 * we continue instead of failing, as this might just 1243 * be an improperly configured instance. 1244 */ 1245 if ((inst_state = get_inst_state(inst, h)) == -1) { 1246 if (scf_error() == SCF_ERROR_INTERNAL) { 1247 continue; 1248 } else { 1249 goto out; 1250 } 1251 } 1252 1253 if ((uint_t)inst_state & state_flags) { 1254 if (inst_callback(h, inst, private) != 1255 SCF_SUCCESS) { 1256 (void) scf_set_error( 1257 SCF_ERROR_CALLBACK_FAILED); 1258 goto out; 1259 } 1260 } 1261 } 1262 1263 if (inst_iter_ret == -1) 1264 goto out; 1265 scf_iter_reset(inst_iter); 1266 } 1267 1268 if (svc_iter_ret != -1) 1269 ret = SCF_SUCCESS; 1270 1271 out: 1272 scf_scope_destroy(scope); 1273 scf_service_destroy(svc); 1274 scf_instance_destroy(inst); 1275 scf_iter_destroy(svc_iter); 1276 scf_iter_destroy(inst_iter); 1277 scf_handle_destroy(h); 1278 1279 return (ret); 1280 } 1281 1282 1283 scf_simple_prop_t * 1284 scf_simple_prop_get(scf_handle_t *hin, const char *instance, const char *pgname, 1285 const char *propname) 1286 { 1287 char *fmri_buf, *svcfmri = NULL; 1288 ssize_t fmri_sz; 1289 scf_property_t *prop = NULL; 1290 scf_service_t *svc = NULL; 1291 scf_simple_prop_t *ret; 1292 scf_handle_t *h = NULL; 1293 boolean_t local_h = B_TRUE; 1294 1295 /* If the user passed in a handle, use it. */ 1296 if (hin != NULL) { 1297 h = hin; 1298 local_h = B_FALSE; 1299 } 1300 1301 if (local_h && ((h = handle_create()) == NULL)) 1302 return (NULL); 1303 1304 if ((fmri_buf = assemble_fmri(h, instance, pgname, propname)) == NULL) { 1305 if (local_h) 1306 scf_handle_destroy(h); 1307 return (NULL); 1308 } 1309 1310 if ((svc = scf_service_create(h)) == NULL || 1311 (prop = scf_property_create(h)) == NULL) 1312 goto error1; 1313 if (scf_handle_decode_fmri(h, fmri_buf, NULL, NULL, NULL, NULL, prop, 1314 SCF_DECODE_FMRI_REQUIRE_INSTANCE) == -1) { 1315 switch (scf_error()) { 1316 /* 1317 * If the property isn't found in the instance, we grab the 1318 * underlying service, create an FMRI out of it, and then 1319 * query the datastore again at the service level for the 1320 * property. 1321 */ 1322 case SCF_ERROR_NOT_FOUND: 1323 if (scf_handle_decode_fmri(h, fmri_buf, NULL, svc, 1324 NULL, NULL, NULL, SCF_DECODE_FMRI_TRUNCATE) == -1) 1325 goto error1; 1326 if ((fmri_sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) == 1327 -1) { 1328 (void) scf_set_error(SCF_ERROR_INTERNAL); 1329 goto error1; 1330 } 1331 if (scf_service_to_fmri(svc, fmri_buf, fmri_sz) == -1) 1332 goto error1; 1333 if ((svcfmri = assemble_fmri(h, fmri_buf, pgname, 1334 propname)) == NULL) 1335 goto error1; 1336 if (scf_handle_decode_fmri(h, svcfmri, NULL, NULL, 1337 NULL, NULL, prop, 0) == -1) { 1338 free(svcfmri); 1339 goto error1; 1340 } 1341 free(svcfmri); 1342 break; 1343 case SCF_ERROR_CONSTRAINT_VIOLATED: 1344 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1345 default: 1346 goto error1; 1347 } 1348 } 1349 /* 1350 * At this point, we've successfully pulled the property from the 1351 * datastore, and simply need to copy its innards into an 1352 * scf_simple_prop_t. 1353 */ 1354 if ((ret = fill_prop(prop, pgname, propname, h)) == NULL) 1355 goto error1; 1356 1357 scf_service_destroy(svc); 1358 scf_property_destroy(prop); 1359 free(fmri_buf); 1360 if (local_h) 1361 scf_handle_destroy(h); 1362 return (ret); 1363 1364 /* 1365 * Exit point for a successful call. Below this line are exit points 1366 * for failures at various stages during the function. 1367 */ 1368 1369 error1: 1370 scf_service_destroy(svc); 1371 scf_property_destroy(prop); 1372 error2: 1373 free(fmri_buf); 1374 if (local_h) 1375 scf_handle_destroy(h); 1376 return (NULL); 1377 } 1378 1379 1380 void 1381 scf_simple_prop_free(scf_simple_prop_t *prop) 1382 { 1383 int i; 1384 1385 if (prop == NULL) 1386 return; 1387 1388 free(prop->pr_propname); 1389 free(prop->pr_pgname); 1390 switch (prop->pr_type) { 1391 case SCF_TYPE_OPAQUE: { 1392 for (i = 0; i < prop->pr_numvalues; i++) { 1393 free(prop->pr_vallist[i].pv_opaque.o_value); 1394 } 1395 break; 1396 } 1397 case SCF_TYPE_ASTRING: 1398 case SCF_TYPE_USTRING: 1399 case SCF_TYPE_HOST: 1400 case SCF_TYPE_HOSTNAME: 1401 case SCF_TYPE_NET_ADDR_V4: 1402 case SCF_TYPE_NET_ADDR_V6: 1403 case SCF_TYPE_URI: 1404 case SCF_TYPE_FMRI: { 1405 for (i = 0; i < prop->pr_numvalues; i++) { 1406 free(prop->pr_vallist[i].pv_str); 1407 } 1408 break; 1409 } 1410 default: 1411 break; 1412 } 1413 free(prop->pr_vallist); 1414 free(prop); 1415 } 1416 1417 1418 scf_simple_app_props_t * 1419 scf_simple_app_props_get(scf_handle_t *hin, const char *inst_fmri) 1420 { 1421 scf_instance_t *inst = NULL; 1422 scf_service_t *svc = NULL; 1423 scf_propertygroup_t *pg = NULL; 1424 scf_property_t *prop = NULL; 1425 scf_simple_app_props_t *ret = NULL; 1426 scf_iter_t *pgiter = NULL, *propiter = NULL; 1427 struct scf_simple_pg *thispg = NULL, *nextpg; 1428 scf_simple_prop_t *thisprop, *nextprop; 1429 scf_handle_t *h = NULL; 1430 int pgiter_ret, propiter_ret; 1431 ssize_t namelen; 1432 char *propname = NULL, *pgname = NULL, *sys_fmri; 1433 uint8_t found; 1434 boolean_t local_h = B_TRUE; 1435 1436 /* If the user passed in a handle, use it. */ 1437 if (hin != NULL) { 1438 h = hin; 1439 local_h = B_FALSE; 1440 } 1441 1442 if (local_h && ((h = handle_create()) == NULL)) 1443 return (NULL); 1444 1445 if (inst_fmri == NULL) { 1446 if ((namelen = scf_myname(h, NULL, 0)) == -1) { 1447 if (local_h) 1448 scf_handle_destroy(h); 1449 return (NULL); 1450 } 1451 if ((sys_fmri = malloc(namelen + 1)) == NULL) { 1452 if (local_h) 1453 scf_handle_destroy(h); 1454 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1455 return (NULL); 1456 } 1457 if (scf_myname(h, sys_fmri, namelen + 1) == -1) { 1458 if (local_h) 1459 scf_handle_destroy(h); 1460 free(sys_fmri); 1461 return (NULL); 1462 } 1463 } else { 1464 sys_fmri = strdup(inst_fmri); 1465 } 1466 1467 if ((namelen = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) == -1) { 1468 (void) scf_set_error(SCF_ERROR_INTERNAL); 1469 return (NULL); 1470 } 1471 1472 if ((inst = scf_instance_create(h)) == NULL || 1473 (svc = scf_service_create(h)) == NULL || 1474 (pgiter = scf_iter_create(h)) == NULL || 1475 (propiter = scf_iter_create(h)) == NULL || 1476 (pg = scf_pg_create(h)) == NULL || 1477 (prop = scf_property_create(h)) == NULL) 1478 goto error2; 1479 1480 if (scf_handle_decode_fmri(h, sys_fmri, NULL, svc, inst, NULL, NULL, 1481 SCF_DECODE_FMRI_REQUIRE_INSTANCE) == -1) { 1482 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) 1483 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1484 goto error2; 1485 } 1486 1487 if ((ret = malloc(sizeof (*ret))) == NULL || 1488 (thispg = malloc(sizeof (*thispg))) == NULL || 1489 (propname = malloc(namelen)) == NULL || 1490 (pgname = malloc(namelen)) == NULL) { 1491 free(thispg); 1492 free(ret); 1493 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1494 goto error2; 1495 } 1496 1497 ret->ap_fmri = sys_fmri; 1498 thispg->pg_name = NULL; 1499 thispg->pg_proplist = NULL; 1500 thispg->pg_next = NULL; 1501 ret->ap_pglist = thispg; 1502 1503 if (scf_iter_service_pgs_typed(pgiter, svc, SCF_GROUP_APPLICATION) != 1504 0) { 1505 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 1506 (void) scf_set_error(SCF_ERROR_INTERNAL); 1507 goto error1; 1508 } 1509 1510 while ((pgiter_ret = scf_iter_next_pg(pgiter, pg)) == 1) { 1511 if (thispg->pg_name != NULL) { 1512 if ((nextpg = malloc(sizeof (*nextpg))) == NULL) { 1513 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1514 goto error1; 1515 } 1516 thispg->pg_next = nextpg; 1517 thispg = nextpg; 1518 } else { 1519 /* This is the first iteration */ 1520 nextpg = thispg; 1521 } 1522 1523 if ((nextpg->pg_name = malloc(namelen)) == NULL) { 1524 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1525 goto error1; 1526 } 1527 1528 if (scf_pg_get_name(pg, nextpg->pg_name, namelen) < 0) { 1529 if (scf_error() == SCF_ERROR_NOT_SET) 1530 (void) scf_set_error(SCF_ERROR_INTERNAL); 1531 goto error1; 1532 } 1533 1534 nextpg->pg_next = NULL; 1535 nextpg->pg_proplist = NULL; 1536 thisprop = NULL; 1537 1538 scf_iter_reset(propiter); 1539 1540 if (scf_iter_pg_properties(propiter, pg) != 0) { 1541 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 1542 (void) scf_set_error(SCF_ERROR_INTERNAL); 1543 goto error1; 1544 } 1545 1546 while ((propiter_ret = scf_iter_next_property(propiter, prop)) 1547 == 1) { 1548 if (scf_property_get_name(prop, propname, namelen) < 1549 0) { 1550 if (scf_error() == SCF_ERROR_NOT_SET) 1551 (void) scf_set_error( 1552 SCF_ERROR_INTERNAL); 1553 goto error1; 1554 } 1555 if (thisprop != NULL) { 1556 if ((nextprop = fill_prop(prop, 1557 nextpg->pg_name, propname, h)) == NULL) 1558 goto error1; 1559 thisprop->pr_next = nextprop; 1560 thisprop = nextprop; 1561 } else { 1562 /* This is the first iteration */ 1563 if ((thisprop = fill_prop(prop, 1564 nextpg->pg_name, propname, h)) == NULL) 1565 goto error1; 1566 nextpg->pg_proplist = thisprop; 1567 nextprop = thisprop; 1568 } 1569 nextprop->pr_pg = nextpg; 1570 nextprop->pr_next = NULL; 1571 } 1572 1573 if (propiter_ret == -1) { 1574 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 1575 (void) scf_set_error(SCF_ERROR_INTERNAL); 1576 goto error1; 1577 } 1578 } 1579 1580 if (pgiter_ret == -1) { 1581 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 1582 (void) scf_set_error(SCF_ERROR_INTERNAL); 1583 goto error1; 1584 } 1585 1586 /* 1587 * At this point, we've filled the scf_simple_app_props_t with all the 1588 * properties at the service level. Now we iterate over all the 1589 * properties at the instance level, overwriting any duplicate 1590 * properties, in order to provide service/instance composition. 1591 */ 1592 1593 scf_iter_reset(pgiter); 1594 scf_iter_reset(propiter); 1595 1596 if (scf_iter_instance_pgs_typed(pgiter, inst, SCF_GROUP_APPLICATION) 1597 != 0) { 1598 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 1599 (void) scf_set_error(SCF_ERROR_INTERNAL); 1600 goto error1; 1601 } 1602 1603 while ((pgiter_ret = scf_iter_next_pg(pgiter, pg)) == 1) { 1604 1605 thispg = ret->ap_pglist; 1606 found = 0; 1607 1608 /* 1609 * Find either the end of the list, so we can append the 1610 * property group, or an existing property group that matches 1611 * it, so we can insert/overwrite its properties. 1612 */ 1613 1614 if (scf_pg_get_name(pg, pgname, namelen) < 0) { 1615 if (scf_error() == SCF_ERROR_NOT_SET) 1616 (void) scf_set_error(SCF_ERROR_INTERNAL); 1617 goto error1; 1618 } 1619 1620 while ((thispg != NULL) && (thispg->pg_name != NULL)) { 1621 if (strcmp(thispg->pg_name, pgname) == 0) { 1622 found = 1; 1623 break; 1624 } 1625 if (thispg->pg_next == NULL) 1626 break; 1627 1628 thispg = thispg->pg_next; 1629 } 1630 1631 scf_iter_reset(propiter); 1632 1633 if (scf_iter_pg_properties(propiter, pg) != 0) { 1634 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 1635 (void) scf_set_error(SCF_ERROR_INTERNAL); 1636 goto error1; 1637 } 1638 1639 if (found) { 1640 /* 1641 * insert_app_props inserts or overwrites the 1642 * properties in thispg. 1643 */ 1644 1645 if (insert_app_props(propiter, pgname, propname, 1646 thispg, prop, namelen, h) == -1) 1647 goto error1; 1648 1649 } else { 1650 /* 1651 * If the property group wasn't found, we're adding 1652 * a newly allocated property group to the end of the 1653 * list. 1654 */ 1655 1656 if ((nextpg = malloc(sizeof (*nextpg))) == NULL) { 1657 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1658 goto error1; 1659 } 1660 nextpg->pg_next = NULL; 1661 nextpg->pg_proplist = NULL; 1662 thisprop = NULL; 1663 1664 if ((nextpg->pg_name = strdup(pgname)) == NULL) { 1665 free(nextpg); 1666 goto error1; 1667 } 1668 1669 if (thispg->pg_name == NULL) { 1670 free(thispg); 1671 ret->ap_pglist = nextpg; 1672 } else { 1673 thispg->pg_next = nextpg; 1674 } 1675 1676 while ((propiter_ret = 1677 scf_iter_next_property(propiter, prop)) == 1) { 1678 if (scf_property_get_name(prop, propname, 1679 namelen) < 0) { 1680 if (scf_error() == SCF_ERROR_NOT_SET) 1681 (void) scf_set_error( 1682 SCF_ERROR_INTERNAL); 1683 goto error1; 1684 } 1685 if (thisprop != NULL) { 1686 if ((nextprop = fill_prop(prop, 1687 pgname, propname, h)) == 1688 NULL) 1689 goto error1; 1690 thisprop->pr_next = nextprop; 1691 thisprop = nextprop; 1692 } else { 1693 /* This is the first iteration */ 1694 if ((thisprop = fill_prop(prop, 1695 pgname, propname, h)) == 1696 NULL) 1697 goto error1; 1698 nextpg->pg_proplist = thisprop; 1699 nextprop = thisprop; 1700 } 1701 nextprop->pr_pg = nextpg; 1702 nextprop->pr_next = NULL; 1703 } 1704 1705 if (propiter_ret == -1) { 1706 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 1707 (void) scf_set_error( 1708 SCF_ERROR_INTERNAL); 1709 goto error1; 1710 } 1711 } 1712 1713 } 1714 1715 if (pgiter_ret == -1) { 1716 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 1717 (void) scf_set_error(SCF_ERROR_INTERNAL); 1718 goto error1; 1719 } 1720 1721 scf_iter_destroy(pgiter); 1722 scf_iter_destroy(propiter); 1723 scf_pg_destroy(pg); 1724 scf_property_destroy(prop); 1725 scf_instance_destroy(inst); 1726 scf_service_destroy(svc); 1727 free(propname); 1728 free(pgname); 1729 if (local_h) 1730 scf_handle_destroy(h); 1731 1732 if (ret->ap_pglist->pg_name == NULL) 1733 return (NULL); 1734 1735 return (ret); 1736 1737 /* 1738 * Exit point for a successful call. Below this line are exit points 1739 * for failures at various stages during the function. 1740 */ 1741 1742 error1: 1743 scf_simple_app_props_free(ret); 1744 1745 error2: 1746 scf_iter_destroy(pgiter); 1747 scf_iter_destroy(propiter); 1748 scf_pg_destroy(pg); 1749 scf_property_destroy(prop); 1750 scf_instance_destroy(inst); 1751 scf_service_destroy(svc); 1752 free(propname); 1753 free(pgname); 1754 if (local_h) 1755 scf_handle_destroy(h); 1756 return (NULL); 1757 } 1758 1759 1760 void 1761 scf_simple_app_props_free(scf_simple_app_props_t *propblock) 1762 { 1763 struct scf_simple_pg *pgthis, *pgnext; 1764 scf_simple_prop_t *propthis, *propnext; 1765 1766 if ((propblock == NULL) || (propblock->ap_pglist == NULL)) 1767 return; 1768 1769 for (pgthis = propblock->ap_pglist; pgthis != NULL; pgthis = pgnext) { 1770 pgnext = pgthis->pg_next; 1771 1772 propthis = pgthis->pg_proplist; 1773 1774 while (propthis != NULL) { 1775 propnext = propthis->pr_next; 1776 scf_simple_prop_free(propthis); 1777 propthis = propnext; 1778 } 1779 1780 free(pgthis->pg_name); 1781 free(pgthis); 1782 } 1783 1784 free(propblock->ap_fmri); 1785 free(propblock); 1786 } 1787 1788 const scf_simple_prop_t * 1789 scf_simple_app_props_next(const scf_simple_app_props_t *propblock, 1790 scf_simple_prop_t *last) 1791 { 1792 struct scf_simple_pg *this; 1793 1794 if (propblock == NULL) { 1795 (void) scf_set_error(SCF_ERROR_NOT_SET); 1796 return (NULL); 1797 } 1798 1799 this = propblock->ap_pglist; 1800 1801 /* 1802 * We're looking for the first property in this block if last is 1803 * NULL 1804 */ 1805 1806 if (last == NULL) { 1807 /* An empty pglist is legal, it just means no properties */ 1808 if (this == NULL) { 1809 (void) scf_set_error(SCF_ERROR_NONE); 1810 return (NULL); 1811 } 1812 /* 1813 * Walk until we find a pg with a property in it, or we run 1814 * out of property groups. 1815 */ 1816 while ((this->pg_proplist == NULL) && (this->pg_next != NULL)) 1817 this = this->pg_next; 1818 1819 if (this->pg_proplist == NULL) { 1820 (void) scf_set_error(SCF_ERROR_NONE); 1821 return (NULL); 1822 } 1823 1824 return (this->pg_proplist); 1825 1826 } 1827 /* 1828 * If last isn't NULL, then return the next prop in the property group, 1829 * or walk the property groups until we find another property, or 1830 * run out of property groups. 1831 */ 1832 if (last->pr_next != NULL) 1833 return (last->pr_next); 1834 1835 if (last->pr_pg->pg_next == NULL) { 1836 (void) scf_set_error(SCF_ERROR_NONE); 1837 return (NULL); 1838 } 1839 1840 this = last->pr_pg->pg_next; 1841 1842 while ((this->pg_proplist == NULL) && (this->pg_next != NULL)) 1843 this = this->pg_next; 1844 1845 if (this->pg_proplist == NULL) { 1846 (void) scf_set_error(SCF_ERROR_NONE); 1847 return (NULL); 1848 } 1849 1850 return (this->pg_proplist); 1851 } 1852 1853 const scf_simple_prop_t * 1854 scf_simple_app_props_search(const scf_simple_app_props_t *propblock, 1855 const char *pgname, const char *propname) 1856 { 1857 struct scf_simple_pg *pg; 1858 scf_simple_prop_t *prop; 1859 1860 if ((propblock == NULL) || (propname == NULL)) { 1861 (void) scf_set_error(SCF_ERROR_NOT_SET); 1862 return (NULL); 1863 } 1864 1865 pg = propblock->ap_pglist; 1866 1867 /* 1868 * If pgname is NULL, we're searching the default application 1869 * property group, otherwise we look for the specified group. 1870 */ 1871 if (pgname == NULL) { 1872 while ((pg != NULL) && 1873 (strcmp(SCF_PG_APP_DEFAULT, pg->pg_name) != 0)) 1874 pg = pg->pg_next; 1875 } else { 1876 while ((pg != NULL) && (strcmp(pgname, pg->pg_name) != 0)) 1877 pg = pg->pg_next; 1878 } 1879 1880 if (pg == NULL) { 1881 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 1882 return (NULL); 1883 } 1884 1885 prop = pg->pg_proplist; 1886 1887 while ((prop != NULL) && (strcmp(propname, prop->pr_propname) != 0)) 1888 prop = prop->pr_next; 1889 1890 if (prop == NULL) { 1891 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 1892 return (NULL); 1893 } 1894 1895 return (prop); 1896 } 1897 1898 void 1899 scf_simple_prop_next_reset(scf_simple_prop_t *prop) 1900 { 1901 if (prop == NULL) 1902 return; 1903 prop->pr_iter = 0; 1904 } 1905 1906 ssize_t 1907 scf_simple_prop_numvalues(const scf_simple_prop_t *prop) 1908 { 1909 if (prop == NULL) 1910 return (scf_set_error(SCF_ERROR_NOT_SET)); 1911 1912 return (prop->pr_numvalues); 1913 } 1914 1915 1916 scf_type_t 1917 scf_simple_prop_type(const scf_simple_prop_t *prop) 1918 { 1919 if (prop == NULL) 1920 return (scf_set_error(SCF_ERROR_NOT_SET)); 1921 1922 return (prop->pr_type); 1923 } 1924 1925 1926 char * 1927 scf_simple_prop_name(const scf_simple_prop_t *prop) 1928 { 1929 if ((prop == NULL) || (prop->pr_propname == NULL)) { 1930 (void) scf_set_error(SCF_ERROR_NOT_SET); 1931 return (NULL); 1932 } 1933 1934 return (prop->pr_propname); 1935 } 1936 1937 1938 char * 1939 scf_simple_prop_pgname(const scf_simple_prop_t *prop) 1940 { 1941 if ((prop == NULL) || (prop->pr_pgname == NULL)) { 1942 (void) scf_set_error(SCF_ERROR_NOT_SET); 1943 return (NULL); 1944 } 1945 1946 return (prop->pr_pgname); 1947 } 1948 1949 1950 static union scf_simple_prop_val * 1951 scf_next_val(scf_simple_prop_t *prop, scf_type_t type) 1952 { 1953 if (prop == NULL) { 1954 (void) scf_set_error(SCF_ERROR_NOT_SET); 1955 return (NULL); 1956 } 1957 1958 switch (prop->pr_type) { 1959 case SCF_TYPE_USTRING: 1960 case SCF_TYPE_HOST: 1961 case SCF_TYPE_HOSTNAME: 1962 case SCF_TYPE_NET_ADDR_V4: 1963 case SCF_TYPE_NET_ADDR_V6: 1964 case SCF_TYPE_URI: 1965 case SCF_TYPE_FMRI: { 1966 if (type != SCF_TYPE_USTRING) { 1967 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH); 1968 return (NULL); 1969 } 1970 break; 1971 } 1972 default: { 1973 if (type != prop->pr_type) { 1974 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH); 1975 return (NULL); 1976 } 1977 break; 1978 } 1979 } 1980 1981 if (prop->pr_iter >= prop->pr_numvalues) { 1982 (void) scf_set_error(SCF_ERROR_NONE); 1983 return (NULL); 1984 } 1985 1986 return (&prop->pr_vallist[prop->pr_iter++]); 1987 } 1988 1989 1990 uint8_t * 1991 scf_simple_prop_next_boolean(scf_simple_prop_t *prop) 1992 { 1993 union scf_simple_prop_val *ret; 1994 1995 ret = scf_next_val(prop, SCF_TYPE_BOOLEAN); 1996 1997 if (ret == NULL) 1998 return (NULL); 1999 2000 return (&ret->pv_bool); 2001 } 2002 2003 2004 uint64_t * 2005 scf_simple_prop_next_count(scf_simple_prop_t *prop) 2006 { 2007 union scf_simple_prop_val *ret; 2008 2009 ret = scf_next_val(prop, SCF_TYPE_COUNT); 2010 2011 if (ret == NULL) 2012 return (NULL); 2013 2014 return (&ret->pv_uint); 2015 } 2016 2017 2018 int64_t * 2019 scf_simple_prop_next_integer(scf_simple_prop_t *prop) 2020 { 2021 union scf_simple_prop_val *ret; 2022 2023 ret = scf_next_val(prop, SCF_TYPE_INTEGER); 2024 2025 if (ret == NULL) 2026 return (NULL); 2027 2028 return (&ret->pv_int); 2029 } 2030 2031 int64_t * 2032 scf_simple_prop_next_time(scf_simple_prop_t *prop, int32_t *nsec) 2033 { 2034 union scf_simple_prop_val *ret; 2035 2036 ret = scf_next_val(prop, SCF_TYPE_TIME); 2037 2038 if (ret == NULL) 2039 return (NULL); 2040 2041 if (nsec != NULL) 2042 *nsec = ret->pv_time.t_nsec; 2043 2044 return (&ret->pv_time.t_sec); 2045 } 2046 2047 char * 2048 scf_simple_prop_next_astring(scf_simple_prop_t *prop) 2049 { 2050 union scf_simple_prop_val *ret; 2051 2052 ret = scf_next_val(prop, SCF_TYPE_ASTRING); 2053 2054 if (ret == NULL) 2055 return (NULL); 2056 2057 return (ret->pv_str); 2058 } 2059 2060 char * 2061 scf_simple_prop_next_ustring(scf_simple_prop_t *prop) 2062 { 2063 union scf_simple_prop_val *ret; 2064 2065 ret = scf_next_val(prop, SCF_TYPE_USTRING); 2066 2067 if (ret == NULL) 2068 return (NULL); 2069 2070 return (ret->pv_str); 2071 } 2072 2073 void * 2074 scf_simple_prop_next_opaque(scf_simple_prop_t *prop, size_t *length) 2075 { 2076 union scf_simple_prop_val *ret; 2077 2078 ret = scf_next_val(prop, SCF_TYPE_OPAQUE); 2079 2080 if (ret == NULL) { 2081 *length = 0; 2082 return (NULL); 2083 } 2084 2085 *length = ret->pv_opaque.o_size; 2086 return (ret->pv_opaque.o_value); 2087 } 2088