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