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 get: 555 if (scf_instance_get_pg(inst, pgname, gpg) == -1) { 556 if (scf_error() != SCF_ERROR_NOT_FOUND) 557 goto out; 558 559 if (scf_instance_add_pg(inst, pgname, SCF_GROUP_FRAMEWORK, 560 pgflags, gpg) == -1) { 561 if (scf_error() != SCF_ERROR_EXISTS) 562 goto out; 563 goto get; 564 } 565 } 566 if (scf_pg_get_property(gpg, SCF_PROPERTY_ENABLED, eprop) == -1) { 567 if (scf_error() != SCF_ERROR_NOT_FOUND) 568 goto out; 569 else 570 goto set; 571 } 572 573 /* 574 * If it's already set the way we want, forgo the transaction. 575 */ 576 if (scf_property_get_value(eprop, v) == -1) { 577 switch (scf_error()) { 578 case SCF_ERROR_CONSTRAINT_VIOLATED: 579 case SCF_ERROR_NOT_FOUND: 580 /* Misconfigured, so set anyway. */ 581 goto set; 582 583 default: 584 goto out; 585 } 586 } 587 if (scf_value_get_boolean(v, &b) == -1) { 588 if (scf_error() != SCF_ERROR_TYPE_MISMATCH) 589 goto out; 590 goto set; 591 } 592 if (b == desired) { 593 ret = 0; 594 goto out; 595 } 596 597 set: 598 do { 599 if (scf_transaction_start(tx, gpg) == -1) 600 goto out; 601 602 if (transaction_property_set(tx, ent, SCF_PROPERTY_ENABLED, 603 SCF_TYPE_BOOLEAN) != 0) { 604 switch (scf_error()) { 605 case SCF_ERROR_CONNECTION_BROKEN: 606 case SCF_ERROR_DELETED: 607 default: 608 goto out; 609 610 case SCF_ERROR_HANDLE_MISMATCH: 611 case SCF_ERROR_INVALID_ARGUMENT: 612 case SCF_ERROR_NOT_BOUND: 613 case SCF_ERROR_NOT_SET: 614 bad_error("transaction_property_set", 615 scf_error()); 616 } 617 } 618 619 scf_value_set_boolean(v, desired); 620 if (scf_entry_add_value(ent, v) == -1) 621 goto out; 622 623 committed = scf_transaction_commit(tx); 624 if (committed == -1) 625 goto out; 626 627 scf_transaction_reset(tx); 628 629 if (committed == 0) { /* out-of-sync */ 630 if (scf_pg_update(gpg) == -1) 631 goto out; 632 } 633 } while (committed == 0); 634 635 ret = 0; 636 637 out: 638 scf_value_destroy(v); 639 scf_entry_destroy(ent); 640 scf_transaction_destroy(tx); 641 scf_property_destroy(eprop); 642 scf_pg_destroy(gpg); 643 644 return (ret); 645 } 646 647 static int 648 delete_inst_enabled(const scf_instance_t *inst, const char *pgname) 649 { 650 scf_transaction_t *tx = NULL; 651 scf_transaction_entry_t *ent = NULL; 652 scf_propertygroup_t *gpg = NULL; 653 scf_handle_t *h = NULL; 654 int ret = -1; 655 int committed; 656 657 if ((h = scf_instance_handle(inst)) == NULL) 658 return (-1); 659 660 if ((gpg = scf_pg_create(h)) == NULL || 661 (tx = scf_transaction_create(h)) == NULL || 662 (ent = scf_entry_create(h)) == NULL) 663 goto out; 664 665 if (scf_instance_get_pg(inst, pgname, gpg) != 0) 666 goto error; 667 do { 668 if (scf_transaction_start(tx, gpg) == -1 || 669 scf_transaction_property_delete(tx, ent, 670 SCF_PROPERTY_ENABLED) == -1 || 671 (committed = scf_transaction_commit(tx)) == -1) 672 goto error; 673 674 scf_transaction_reset(tx); 675 676 if (committed == 0 && scf_pg_update(gpg) == -1) 677 goto error; 678 } while (committed == 0); 679 680 ret = 0; 681 goto out; 682 683 error: 684 switch (scf_error()) { 685 case SCF_ERROR_DELETED: 686 case SCF_ERROR_NOT_FOUND: 687 /* success */ 688 ret = 0; 689 } 690 691 out: 692 scf_entry_destroy(ent); 693 scf_transaction_destroy(tx); 694 scf_pg_destroy(gpg); 695 696 return (ret); 697 } 698 699 /* 700 * Returns 0 on success or -1 on failure. On failure leaves scf_error() set to 701 * SCF_ERROR_HANDLE_DESTROYED - inst's handle has been destroyed 702 * SCF_ERROR_NOT_BOUND - inst's handle is not bound 703 * SCF_ERROR_CONNECTION_BROKEN - the repository connection was broken 704 * SCF_ERROR_NOT_SET - inst is not set 705 * SCF_ERROR_DELETED - inst was deleted 706 * SCF_ERROR_PERMISSION_DENIED 707 * SCF_ERROR_BACKEND_ACCESS 708 * SCF_ERROR_BACKEND_READONLY 709 */ 710 static int 711 set_inst_action_inst(scf_instance_t *inst, const char *action) 712 { 713 scf_handle_t *h; 714 scf_transaction_t *tx = NULL; 715 scf_transaction_entry_t *ent = NULL; 716 scf_propertygroup_t *pg = NULL; 717 scf_property_t *prop = NULL; 718 scf_value_t *v = NULL; 719 int trans, ret = -1; 720 int64_t t; 721 hrtime_t timestamp; 722 723 if ((h = scf_instance_handle(inst)) == NULL || 724 (pg = scf_pg_create(h)) == NULL || 725 (prop = scf_property_create(h)) == NULL || 726 (v = scf_value_create(h)) == NULL || 727 (tx = scf_transaction_create(h)) == NULL || 728 (ent = scf_entry_create(h)) == NULL) 729 goto out; 730 731 get: 732 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER_ACTIONS, pg) == -1) { 733 switch (scf_error()) { 734 case SCF_ERROR_NOT_BOUND: 735 case SCF_ERROR_CONNECTION_BROKEN: 736 case SCF_ERROR_NOT_SET: 737 case SCF_ERROR_DELETED: 738 default: 739 goto out; 740 741 case SCF_ERROR_NOT_FOUND: 742 break; 743 744 case SCF_ERROR_HANDLE_MISMATCH: 745 case SCF_ERROR_INVALID_ARGUMENT: 746 bad_error("scf_instance_get_pg", scf_error()); 747 } 748 749 /* Try creating the restarter_actions property group. */ 750 add: 751 if (scf_instance_add_pg(inst, SCF_PG_RESTARTER_ACTIONS, 752 SCF_PG_RESTARTER_ACTIONS_TYPE, 753 SCF_PG_RESTARTER_ACTIONS_FLAGS, pg) == -1) { 754 switch (scf_error()) { 755 case SCF_ERROR_NOT_BOUND: 756 case SCF_ERROR_CONNECTION_BROKEN: 757 case SCF_ERROR_NOT_SET: 758 case SCF_ERROR_DELETED: 759 case SCF_ERROR_PERMISSION_DENIED: 760 case SCF_ERROR_BACKEND_ACCESS: 761 case SCF_ERROR_BACKEND_READONLY: 762 default: 763 goto out; 764 765 case SCF_ERROR_EXISTS: 766 goto get; 767 768 case SCF_ERROR_HANDLE_MISMATCH: 769 case SCF_ERROR_INVALID_ARGUMENT: 770 bad_error("scf_instance_add_pg", scf_error()); 771 } 772 } 773 } 774 775 for (;;) { 776 timestamp = gethrtime(); 777 778 if (scf_pg_get_property(pg, action, prop) != 0) { 779 switch (scf_error()) { 780 case SCF_ERROR_CONNECTION_BROKEN: 781 default: 782 goto out; 783 784 case SCF_ERROR_DELETED: 785 goto add; 786 787 case SCF_ERROR_NOT_FOUND: 788 break; 789 790 case SCF_ERROR_HANDLE_MISMATCH: 791 case SCF_ERROR_INVALID_ARGUMENT: 792 case SCF_ERROR_NOT_BOUND: 793 case SCF_ERROR_NOT_SET: 794 bad_error("scf_pg_get_property", scf_error()); 795 } 796 } else if (scf_property_get_value(prop, v) != 0) { 797 switch (scf_error()) { 798 case SCF_ERROR_CONNECTION_BROKEN: 799 default: 800 goto out; 801 802 case SCF_ERROR_DELETED: 803 goto add; 804 805 case SCF_ERROR_CONSTRAINT_VIOLATED: 806 case SCF_ERROR_NOT_FOUND: 807 break; 808 809 case SCF_ERROR_HANDLE_MISMATCH: 810 case SCF_ERROR_NOT_BOUND: 811 case SCF_ERROR_NOT_SET: 812 bad_error("scf_property_get_value", 813 scf_error()); 814 } 815 } else if (scf_value_get_integer(v, &t) != 0) { 816 bad_error("scf_value_get_integer", scf_error()); 817 } else if (t > timestamp) { 818 break; 819 } 820 821 if (scf_transaction_start(tx, pg) == -1) { 822 switch (scf_error()) { 823 case SCF_ERROR_NOT_BOUND: 824 case SCF_ERROR_CONNECTION_BROKEN: 825 case SCF_ERROR_PERMISSION_DENIED: 826 case SCF_ERROR_BACKEND_ACCESS: 827 case SCF_ERROR_BACKEND_READONLY: 828 default: 829 goto out; 830 831 case SCF_ERROR_DELETED: 832 goto add; 833 834 case SCF_ERROR_HANDLE_MISMATCH: 835 case SCF_ERROR_NOT_SET: 836 case SCF_ERROR_IN_USE: 837 bad_error("scf_transaction_start", scf_error()); 838 } 839 } 840 841 if (transaction_property_set(tx, ent, action, 842 SCF_TYPE_INTEGER) != 0) { 843 switch (scf_error()) { 844 case SCF_ERROR_NOT_BOUND: 845 case SCF_ERROR_CONNECTION_BROKEN: 846 case SCF_ERROR_DELETED: 847 default: 848 goto out; 849 850 case SCF_ERROR_HANDLE_MISMATCH: 851 case SCF_ERROR_INVALID_ARGUMENT: 852 case SCF_ERROR_NOT_SET: 853 bad_error("transaction_property_set", 854 scf_error()); 855 } 856 } 857 858 scf_value_set_integer(v, timestamp); 859 if (scf_entry_add_value(ent, v) == -1) 860 bad_error("scf_entry_add_value", scf_error()); 861 862 trans = scf_transaction_commit(tx); 863 if (trans == 1) 864 break; 865 866 if (trans != 0) { 867 switch (scf_error()) { 868 case SCF_ERROR_CONNECTION_BROKEN: 869 case SCF_ERROR_PERMISSION_DENIED: 870 case SCF_ERROR_BACKEND_ACCESS: 871 case SCF_ERROR_BACKEND_READONLY: 872 default: 873 goto out; 874 875 case SCF_ERROR_DELETED: 876 scf_transaction_reset(tx); 877 goto add; 878 879 case SCF_ERROR_INVALID_ARGUMENT: 880 case SCF_ERROR_NOT_BOUND: 881 case SCF_ERROR_NOT_SET: 882 bad_error("scf_transaction_commit", 883 scf_error()); 884 } 885 } 886 887 scf_transaction_reset(tx); 888 if (scf_pg_update(pg) != 0) { 889 switch (scf_error()) { 890 case SCF_ERROR_CONNECTION_BROKEN: 891 default: 892 goto out; 893 894 case SCF_ERROR_DELETED: 895 goto add; 896 897 case SCF_ERROR_NOT_SET: 898 case SCF_ERROR_NOT_BOUND: 899 bad_error("scf_pg_update", scf_error()); 900 } 901 } 902 } 903 904 ret = 0; 905 906 out: 907 scf_value_destroy(v); 908 scf_entry_destroy(ent); 909 scf_transaction_destroy(tx); 910 scf_property_destroy(prop); 911 scf_pg_destroy(pg); 912 return (ret); 913 } 914 915 static int 916 set_inst_action(const char *fmri, const char *action) 917 { 918 scf_handle_t *h; 919 scf_instance_t *inst; 920 int ret = -1; 921 922 h = handle_create(); 923 if (h == NULL) 924 return (-1); 925 926 inst = scf_instance_create(h); 927 928 if (inst != NULL) { 929 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, 930 NULL, SCF_DECODE_FMRI_EXACT) == 0) 931 ret = set_inst_action_inst(inst, action); 932 else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) 933 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 934 935 scf_instance_destroy(inst); 936 } 937 938 scf_handle_destroy(h); 939 940 return (ret); 941 } 942 943 944 /* 945 * get_inst_state() gets the state string from an instance, and returns 946 * the SCF_STATE_* constant that coincides with the instance's current state. 947 */ 948 949 static int 950 get_inst_state(scf_instance_t *inst, scf_handle_t *h) 951 { 952 scf_propertygroup_t *pg = NULL; 953 scf_property_t *prop = NULL; 954 scf_value_t *val = NULL; 955 char state[MAX_SCF_STATE_STRING_SZ]; 956 int ret = -1; 957 958 if (((pg = scf_pg_create(h)) == NULL) || 959 ((prop = scf_property_create(h)) == NULL) || 960 ((val = scf_value_create(h)) == NULL)) 961 goto out; 962 963 /* Pull the state property from the instance */ 964 965 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) == -1 || 966 scf_pg_get_property(pg, SCF_PROPERTY_STATE, prop) == -1 || 967 scf_property_get_value(prop, val) == -1) { 968 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 969 (void) scf_set_error(SCF_ERROR_INTERNAL); 970 goto out; 971 } 972 973 if (scf_value_get_astring(val, state, sizeof (state)) <= 0) { 974 (void) scf_set_error(SCF_ERROR_INTERNAL); 975 goto out; 976 } 977 978 if (strcmp(state, SCF_STATE_STRING_UNINIT) == 0) { 979 ret = SCF_STATE_UNINIT; 980 } else if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) { 981 ret = SCF_STATE_MAINT; 982 } else if (strcmp(state, SCF_STATE_STRING_OFFLINE) == 0) { 983 ret = SCF_STATE_OFFLINE; 984 } else if (strcmp(state, SCF_STATE_STRING_DISABLED) == 0) { 985 ret = SCF_STATE_DISABLED; 986 } else if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0) { 987 ret = SCF_STATE_ONLINE; 988 } else if (strcmp(state, SCF_STATE_STRING_DEGRADED) == 0) { 989 ret = SCF_STATE_DEGRADED; 990 } 991 992 out: 993 scf_pg_destroy(pg); 994 scf_property_destroy(prop); 995 (void) scf_value_destroy(val); 996 997 return (ret); 998 } 999 1000 /* 1001 * Sets an instance to be enabled or disabled after reboot, using the 1002 * temporary (overriding) general_ovr property group to reflect the 1003 * present state, if it is different. 1004 */ 1005 static int 1006 set_inst_enabled_atboot(scf_instance_t *inst, uint8_t desired) 1007 { 1008 int enabled; 1009 int persistent; 1010 int ret = -1; 1011 1012 if ((persistent = get_inst_enabled(inst, SCF_PG_GENERAL)) < 0) { 1013 if (scf_error() != SCF_ERROR_NOT_FOUND) 1014 goto out; 1015 persistent = B_FALSE; 1016 } 1017 if ((enabled = get_inst_enabled(inst, SCF_PG_GENERAL_OVR)) < 0) { 1018 enabled = persistent; 1019 if (persistent != desired) { 1020 /* 1021 * Temporarily store the present enabled state. 1022 */ 1023 if (set_inst_enabled(inst, persistent, 1024 SCF_PG_GENERAL_OVR, SCF_PG_GENERAL_OVR_FLAGS)) 1025 goto out; 1026 } 1027 } 1028 if (persistent != desired) 1029 if (set_inst_enabled(inst, desired, SCF_PG_GENERAL, 1030 SCF_PG_GENERAL_FLAGS)) 1031 goto out; 1032 if (enabled == desired) 1033 ret = delete_inst_enabled(inst, SCF_PG_GENERAL_OVR); 1034 else 1035 ret = 0; 1036 1037 out: 1038 return (ret); 1039 } 1040 1041 static int 1042 set_inst_enabled_flags(const char *fmri, int flags, uint8_t desired) 1043 { 1044 int ret = -1; 1045 scf_handle_t *h; 1046 scf_instance_t *inst; 1047 1048 if (flags & ~(SMF_TEMPORARY | SMF_AT_NEXT_BOOT) || 1049 flags & SMF_TEMPORARY && flags & SMF_AT_NEXT_BOOT) { 1050 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1051 return (ret); 1052 } 1053 1054 if ((h = handle_create()) == NULL) 1055 return (ret); 1056 1057 if ((inst = scf_instance_create(h)) == NULL) { 1058 scf_handle_destroy(h); 1059 return (ret); 1060 } 1061 1062 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, NULL, 1063 SCF_DECODE_FMRI_EXACT) == -1) { 1064 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) 1065 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1066 goto out; 1067 } 1068 1069 if (flags & SMF_AT_NEXT_BOOT) { 1070 ret = set_inst_enabled_atboot(inst, desired); 1071 } else { 1072 if (set_inst_enabled(inst, desired, flags & SMF_TEMPORARY ? 1073 SCF_PG_GENERAL_OVR : SCF_PG_GENERAL, flags & SMF_TEMPORARY ? 1074 SCF_PG_GENERAL_OVR_FLAGS : SCF_PG_GENERAL_FLAGS)) 1075 goto out; 1076 1077 /* 1078 * Make the persistent value effective by deleting the 1079 * temporary one. 1080 */ 1081 if (flags & SMF_TEMPORARY) 1082 ret = 0; 1083 else 1084 ret = delete_inst_enabled(inst, SCF_PG_GENERAL_OVR); 1085 } 1086 1087 out: 1088 scf_instance_destroy(inst); 1089 scf_handle_destroy(h); 1090 return (ret); 1091 } 1092 1093 /* 1094 * Create and return a pg from the instance associated with the given handle. 1095 * This function is only called in scf_transaction_setup and 1096 * scf_transaction_restart where the h->rh_instance pointer is properly filled 1097 * in by scf_general_setup_pg(). 1098 */ 1099 static scf_propertygroup_t * 1100 get_instance_pg(scf_simple_handle_t *simple_h) 1101 { 1102 scf_propertygroup_t *ret_pg = scf_pg_create(simple_h->h); 1103 char *pg_name; 1104 ssize_t namelen; 1105 1106 if (ret_pg == NULL) { 1107 return (NULL); 1108 } 1109 1110 if ((namelen = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) == -1) { 1111 if (scf_error() == SCF_ERROR_NOT_SET) { 1112 (void) scf_set_error(SCF_ERROR_INTERNAL); 1113 } 1114 return (NULL); 1115 } 1116 1117 if ((pg_name = malloc(namelen)) == NULL) { 1118 if (scf_error() == SCF_ERROR_NOT_SET) { 1119 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1120 } 1121 return (NULL); 1122 } 1123 1124 if (scf_pg_get_name(simple_h->running_pg, pg_name, namelen) < 0) { 1125 if (scf_error() == SCF_ERROR_NOT_SET) { 1126 (void) scf_set_error(SCF_ERROR_INTERNAL); 1127 } 1128 return (NULL); 1129 } 1130 1131 /* Get pg from instance */ 1132 if (scf_instance_get_pg(simple_h->inst, pg_name, ret_pg) == -1) { 1133 return (NULL); 1134 } 1135 1136 return (ret_pg); 1137 } 1138 1139 int 1140 smf_enable_instance(const char *fmri, int flags) 1141 { 1142 return (set_inst_enabled_flags(fmri, flags, B_TRUE)); 1143 } 1144 1145 int 1146 smf_disable_instance(const char *fmri, int flags) 1147 { 1148 return (set_inst_enabled_flags(fmri, flags, B_FALSE)); 1149 } 1150 1151 int 1152 _smf_refresh_instance_i(scf_instance_t *inst) 1153 { 1154 return (set_inst_action_inst(inst, SCF_PROPERTY_REFRESH)); 1155 } 1156 1157 int 1158 smf_refresh_instance(const char *instance) 1159 { 1160 return (set_inst_action(instance, SCF_PROPERTY_REFRESH)); 1161 } 1162 1163 int 1164 smf_restart_instance(const char *instance) 1165 { 1166 return (set_inst_action(instance, SCF_PROPERTY_RESTART)); 1167 } 1168 1169 int 1170 smf_maintain_instance(const char *instance, int flags) 1171 { 1172 if (flags & SMF_TEMPORARY) 1173 return (set_inst_action(instance, 1174 (flags & SMF_IMMEDIATE) ? 1175 SCF_PROPERTY_MAINT_ON_IMMTEMP : 1176 SCF_PROPERTY_MAINT_ON_TEMPORARY)); 1177 else 1178 return (set_inst_action(instance, 1179 (flags & SMF_IMMEDIATE) ? 1180 SCF_PROPERTY_MAINT_ON_IMMEDIATE : 1181 SCF_PROPERTY_MAINT_ON)); 1182 } 1183 1184 int 1185 smf_degrade_instance(const char *instance, int flags) 1186 { 1187 scf_simple_prop_t *prop; 1188 const char *state_str; 1189 1190 if (flags & SMF_TEMPORARY) 1191 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 1192 1193 if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER, 1194 SCF_PROPERTY_STATE)) == NULL) 1195 return (SCF_FAILED); 1196 1197 if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) { 1198 scf_simple_prop_free(prop); 1199 return (SCF_FAILED); 1200 } 1201 1202 if (strcmp(state_str, SCF_STATE_STRING_ONLINE) != 0) { 1203 scf_simple_prop_free(prop); 1204 return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED)); 1205 } 1206 scf_simple_prop_free(prop); 1207 1208 return (set_inst_action(instance, (flags & SMF_IMMEDIATE) ? 1209 SCF_PROPERTY_DEGRADE_IMMEDIATE : SCF_PROPERTY_DEGRADED)); 1210 } 1211 1212 int 1213 smf_restore_instance(const char *instance) 1214 { 1215 scf_simple_prop_t *prop; 1216 const char *state_str; 1217 int ret; 1218 1219 if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER, 1220 SCF_PROPERTY_STATE)) == NULL) 1221 return (SCF_FAILED); 1222 1223 if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) { 1224 scf_simple_prop_free(prop); 1225 return (SCF_FAILED); 1226 } 1227 1228 if (strcmp(state_str, SCF_STATE_STRING_MAINT) == 0) { 1229 ret = set_inst_action(instance, SCF_PROPERTY_MAINT_OFF); 1230 } else if (strcmp(state_str, SCF_STATE_STRING_DEGRADED) == 0) { 1231 ret = set_inst_action(instance, SCF_PROPERTY_RESTORE); 1232 } else { 1233 ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED); 1234 } 1235 1236 scf_simple_prop_free(prop); 1237 return (ret); 1238 } 1239 1240 char * 1241 smf_get_state(const char *instance) 1242 { 1243 scf_simple_prop_t *prop; 1244 const char *state_str; 1245 char *ret; 1246 1247 if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER, 1248 SCF_PROPERTY_STATE)) == NULL) 1249 return (NULL); 1250 1251 if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) { 1252 scf_simple_prop_free(prop); 1253 return (NULL); 1254 } 1255 1256 if ((ret = strdup(state_str)) == NULL) 1257 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1258 1259 scf_simple_prop_free(prop); 1260 return (ret); 1261 } 1262 1263 /* 1264 * scf_general_pg_setup(fmri, pg_name) 1265 * Create a scf_simple_handle_t and fill in the instance, snapshot, and 1266 * property group fields associated with the given fmri and property group 1267 * name. 1268 * Returns: 1269 * Handle on success 1270 * Null on error with scf_error set to: 1271 * SCF_ERROR_HANDLE_MISMATCH, 1272 * SCF_ERROR_INVALID_ARGUMENT, 1273 * SCF_ERROR_CONSTRAINT_VIOLATED, 1274 * SCF_ERROR_NOT_FOUND, 1275 * SCF_ERROR_NOT_SET, 1276 * SCF_ERROR_DELETED, 1277 * SCF_ERROR_NOT_BOUND, 1278 * SCF_ERROR_CONNECTION_BROKEN, 1279 * SCF_ERROR_INTERNAL, 1280 * SCF_ERROR_NO_RESOURCES, 1281 * SCF_ERROR_BACKEND_ACCESS 1282 */ 1283 scf_simple_handle_t * 1284 scf_general_pg_setup(const char *fmri, const char *pg_name) 1285 { 1286 scf_simple_handle_t *ret; 1287 1288 ret = uu_zalloc(sizeof (*ret)); 1289 if (ret == NULL) { 1290 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1291 return (NULL); 1292 } else { 1293 1294 ret->h = handle_create(); 1295 ret->inst = scf_instance_create(ret->h); 1296 ret->snap = scf_snapshot_create(ret->h); 1297 ret->running_pg = scf_pg_create(ret->h); 1298 } 1299 1300 if ((ret->h == NULL) || (ret->inst == NULL) || 1301 (ret->snap == NULL) || (ret->running_pg == NULL)) { 1302 goto out; 1303 } 1304 1305 if (scf_handle_decode_fmri(ret->h, fmri, NULL, NULL, ret->inst, 1306 NULL, NULL, NULL) == -1) { 1307 goto out; 1308 } 1309 1310 if ((scf_instance_get_snapshot(ret->inst, "running", ret->snap)) 1311 != 0) { 1312 goto out; 1313 } 1314 1315 if (scf_instance_get_pg_composed(ret->inst, ret->snap, pg_name, 1316 ret->running_pg) != 0) { 1317 goto out; 1318 } 1319 1320 return (ret); 1321 1322 out: 1323 scf_simple_handle_destroy(ret); 1324 return (NULL); 1325 } 1326 1327 /* 1328 * scf_transaction_setup(h) 1329 * creates and starts the transaction 1330 * Returns: 1331 * transaction on success 1332 * NULL on failure with scf_error set to: 1333 * SCF_ERROR_NO_MEMORY, 1334 * SCF_ERROR_INVALID_ARGUMENT, 1335 * SCF_ERROR_HANDLE_DESTROYED, 1336 * SCF_ERROR_INTERNAL, 1337 * SCF_ERROR_NO_RESOURCES, 1338 * SCF_ERROR_NOT_BOUND, 1339 * SCF_ERROR_CONNECTION_BROKEN, 1340 * SCF_ERROR_NOT_SET, 1341 * SCF_ERROR_DELETED, 1342 * SCF_ERROR_CONSTRAINT_VIOLATED, 1343 * SCF_ERROR_HANDLE_MISMATCH, 1344 * SCF_ERROR_BACKEND_ACCESS, 1345 * SCF_ERROR_IN_USE 1346 */ 1347 scf_transaction_t * 1348 scf_transaction_setup(scf_simple_handle_t *simple_h) 1349 { 1350 scf_transaction_t *tx = NULL; 1351 1352 if ((tx = scf_transaction_create(simple_h->h)) == NULL) { 1353 return (NULL); 1354 } 1355 1356 if ((simple_h->editing_pg = get_instance_pg(simple_h)) == NULL) { 1357 return (NULL); 1358 } 1359 1360 if (scf_transaction_start(tx, simple_h->editing_pg) == -1) { 1361 scf_pg_destroy(simple_h->editing_pg); 1362 simple_h->editing_pg = NULL; 1363 return (NULL); 1364 } 1365 1366 return (tx); 1367 } 1368 1369 int 1370 scf_transaction_restart(scf_simple_handle_t *simple_h, scf_transaction_t *tx) 1371 { 1372 scf_transaction_reset(tx); 1373 1374 if (scf_pg_update(simple_h->editing_pg) == -1) { 1375 return (SCF_FAILED); 1376 } 1377 1378 if (scf_transaction_start(tx, simple_h->editing_pg) == -1) { 1379 return (SCF_FAILED); 1380 } 1381 1382 return (SCF_SUCCESS); 1383 } 1384 1385 /* 1386 * scf_read_count_property(scf_simple_handle_t *simple_h, char *prop_name, 1387 * uint64_t *ret_count) 1388 * 1389 * For the given property name, return the count value. 1390 * RETURNS: 1391 * SCF_SUCCESS 1392 * SCF_FAILED on failure with scf_error() set to: 1393 * SCF_ERROR_HANDLE_DESTROYED 1394 * SCF_ERROR_INTERNAL 1395 * SCF_ERROR_NO_RESOURCES 1396 * SCF_ERROR_NO_MEMORY 1397 * SCF_ERROR_HANDLE_MISMATCH 1398 * SCF_ERROR_INVALID_ARGUMENT 1399 * SCF_ERROR_NOT_BOUND 1400 * SCF_ERROR_CONNECTION_BROKEN 1401 * SCF_ERROR_NOT_SET 1402 * SCF_ERROR_DELETED 1403 * SCF_ERROR_BACKEND_ACCESS 1404 * SCF_ERROR_CONSTRAINT_VIOLATED 1405 * SCF_ERROR_TYPE_MISMATCH 1406 */ 1407 int 1408 scf_read_count_property( 1409 scf_simple_handle_t *simple_h, 1410 char *prop_name, 1411 uint64_t *ret_count) 1412 { 1413 scf_property_t *prop = scf_property_create(simple_h->h); 1414 scf_value_t *val = scf_value_create(simple_h->h); 1415 int ret = SCF_FAILED; 1416 1417 if ((val == NULL) || (prop == NULL)) { 1418 goto out; 1419 } 1420 1421 /* 1422 * Get the property struct that goes with this property group and 1423 * property name. 1424 */ 1425 if (scf_pg_get_property(simple_h->running_pg, prop_name, prop) != 0) { 1426 goto out; 1427 } 1428 1429 /* Get the value structure */ 1430 if (scf_property_get_value(prop, val) == -1) { 1431 goto out; 1432 } 1433 1434 /* 1435 * Now get the count value. 1436 */ 1437 if (scf_value_get_count(val, ret_count) == -1) { 1438 goto out; 1439 } 1440 1441 ret = SCF_SUCCESS; 1442 1443 out: 1444 scf_property_destroy(prop); 1445 scf_value_destroy(val); 1446 return (ret); 1447 } 1448 1449 /* 1450 * scf_trans_add_count_property(trans, propname, count, create_flag) 1451 * 1452 * Set a count property transaction entry into the pending SMF transaction. 1453 * The transaction is created and committed outside of this function. 1454 * Returns: 1455 * SCF_SUCCESS 1456 * SCF_FAILED on failure with scf_error() set to: 1457 * SCF_ERROR_HANDLE_DESTROYED, 1458 * SCF_ERROR_INVALID_ARGUMENT, 1459 * SCF_ERROR_NO_MEMORY, 1460 * SCF_ERROR_HANDLE_MISMATCH, 1461 * SCF_ERROR_NOT_SET, 1462 * SCF_ERROR_IN_USE, 1463 * SCF_ERROR_NOT_FOUND, 1464 * SCF_ERROR_EXISTS, 1465 * SCF_ERROR_TYPE_MISMATCH, 1466 * SCF_ERROR_NOT_BOUND, 1467 * SCF_ERROR_CONNECTION_BROKEN, 1468 * SCF_ERROR_INTERNAL, 1469 * SCF_ERROR_DELETED, 1470 * SCF_ERROR_NO_RESOURCES, 1471 * SCF_ERROR_BACKEND_ACCESS 1472 */ 1473 int 1474 scf_set_count_property( 1475 scf_transaction_t *trans, 1476 char *propname, 1477 uint64_t count, 1478 boolean_t create_flag) 1479 { 1480 scf_handle_t *handle = scf_transaction_handle(trans); 1481 scf_value_t *value = scf_value_create(handle); 1482 scf_transaction_entry_t *entry = scf_entry_create(handle); 1483 1484 if ((value == NULL) || (entry == NULL)) { 1485 return (SCF_FAILED); 1486 } 1487 1488 /* 1489 * Property must be set in transaction and won't take 1490 * effect until the transaction is committed. 1491 * 1492 * Attempt to change the current value. However, create new property 1493 * if it doesn't exist and the create flag is set. 1494 */ 1495 if (scf_transaction_property_change(trans, entry, propname, 1496 SCF_TYPE_COUNT) == 0) { 1497 scf_value_set_count(value, count); 1498 if (scf_entry_add_value(entry, value) == 0) { 1499 return (SCF_SUCCESS); 1500 } 1501 } else { 1502 if ((create_flag == B_TRUE) && 1503 (scf_error() == SCF_ERROR_NOT_FOUND)) { 1504 if (scf_transaction_property_new(trans, entry, propname, 1505 SCF_TYPE_COUNT) == 0) { 1506 scf_value_set_count(value, count); 1507 if (scf_entry_add_value(entry, value) == 0) { 1508 return (SCF_SUCCESS); 1509 } 1510 } 1511 } 1512 } 1513 1514 /* 1515 * cleanup if there were any errors that didn't leave these 1516 * values where they would be cleaned up later. 1517 */ 1518 if (value != NULL) 1519 scf_value_destroy(value); 1520 if (entry != NULL) 1521 scf_entry_destroy(entry); 1522 return (SCF_FAILED); 1523 } 1524 1525 int 1526 scf_simple_walk_instances(uint_t state_flags, void *private, 1527 int (*inst_callback)(scf_handle_t *, scf_instance_t *, void *)) 1528 { 1529 scf_scope_t *scope = NULL; 1530 scf_service_t *svc = NULL; 1531 scf_instance_t *inst = NULL; 1532 scf_iter_t *svc_iter = NULL, *inst_iter = NULL; 1533 scf_handle_t *h = NULL; 1534 int ret = SCF_FAILED; 1535 int svc_iter_ret, inst_iter_ret; 1536 int inst_state; 1537 1538 if ((h = handle_create()) == NULL) 1539 return (ret); 1540 1541 if (((scope = scf_scope_create(h)) == NULL) || 1542 ((svc = scf_service_create(h)) == NULL) || 1543 ((inst = scf_instance_create(h)) == NULL) || 1544 ((svc_iter = scf_iter_create(h)) == NULL) || 1545 ((inst_iter = scf_iter_create(h)) == NULL)) 1546 goto out; 1547 1548 /* 1549 * Get the local scope, and set up nested iteration through every 1550 * local service, and every instance of every service. 1551 */ 1552 1553 if ((scf_handle_get_local_scope(h, scope) != SCF_SUCCESS) || 1554 (scf_iter_scope_services(svc_iter, scope) != SCF_SUCCESS)) 1555 goto out; 1556 1557 while ((svc_iter_ret = scf_iter_next_service(svc_iter, svc)) > 0) { 1558 1559 if ((scf_iter_service_instances(inst_iter, svc)) != 1560 SCF_SUCCESS) 1561 goto out; 1562 1563 while ((inst_iter_ret = 1564 scf_iter_next_instance(inst_iter, inst)) > 0) { 1565 /* 1566 * If get_inst_state fails from an internal error, 1567 * IE, being unable to get the property group or 1568 * property containing the state of the instance, 1569 * we continue instead of failing, as this might just 1570 * be an improperly configured instance. 1571 */ 1572 if ((inst_state = get_inst_state(inst, h)) == -1) { 1573 if (scf_error() == SCF_ERROR_INTERNAL) { 1574 continue; 1575 } else { 1576 goto out; 1577 } 1578 } 1579 1580 if ((uint_t)inst_state & state_flags) { 1581 if (inst_callback(h, inst, private) != 1582 SCF_SUCCESS) { 1583 (void) scf_set_error( 1584 SCF_ERROR_CALLBACK_FAILED); 1585 goto out; 1586 } 1587 } 1588 } 1589 1590 if (inst_iter_ret == -1) 1591 goto out; 1592 scf_iter_reset(inst_iter); 1593 } 1594 1595 if (svc_iter_ret != -1) 1596 ret = SCF_SUCCESS; 1597 1598 out: 1599 scf_scope_destroy(scope); 1600 scf_service_destroy(svc); 1601 scf_instance_destroy(inst); 1602 scf_iter_destroy(svc_iter); 1603 scf_iter_destroy(inst_iter); 1604 scf_handle_destroy(h); 1605 1606 return (ret); 1607 } 1608 1609 1610 scf_simple_prop_t * 1611 scf_simple_prop_get(scf_handle_t *hin, const char *instance, const char *pgname, 1612 const char *propname) 1613 { 1614 char *fmri_buf, *svcfmri = NULL; 1615 ssize_t fmri_sz; 1616 scf_property_t *prop = NULL; 1617 scf_service_t *svc = NULL; 1618 scf_simple_prop_t *ret; 1619 scf_handle_t *h = NULL; 1620 boolean_t local_h = B_TRUE; 1621 1622 /* If the user passed in a handle, use it. */ 1623 if (hin != NULL) { 1624 h = hin; 1625 local_h = B_FALSE; 1626 } 1627 1628 if (local_h && ((h = handle_create()) == NULL)) 1629 return (NULL); 1630 1631 if ((fmri_buf = assemble_fmri(h, instance, pgname, propname)) == NULL) { 1632 if (local_h) 1633 scf_handle_destroy(h); 1634 return (NULL); 1635 } 1636 1637 if ((svc = scf_service_create(h)) == NULL || 1638 (prop = scf_property_create(h)) == NULL) 1639 goto error1; 1640 if (scf_handle_decode_fmri(h, fmri_buf, NULL, NULL, NULL, NULL, prop, 1641 SCF_DECODE_FMRI_REQUIRE_INSTANCE) == -1) { 1642 switch (scf_error()) { 1643 /* 1644 * If the property isn't found in the instance, we grab the 1645 * underlying service, create an FMRI out of it, and then 1646 * query the datastore again at the service level for the 1647 * property. 1648 */ 1649 case SCF_ERROR_NOT_FOUND: 1650 if (scf_handle_decode_fmri(h, fmri_buf, NULL, svc, 1651 NULL, NULL, NULL, SCF_DECODE_FMRI_TRUNCATE) == -1) 1652 goto error1; 1653 if ((fmri_sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) == 1654 -1) { 1655 (void) scf_set_error(SCF_ERROR_INTERNAL); 1656 goto error1; 1657 } 1658 if (scf_service_to_fmri(svc, fmri_buf, fmri_sz) == -1) 1659 goto error1; 1660 if ((svcfmri = assemble_fmri(h, fmri_buf, pgname, 1661 propname)) == NULL) 1662 goto error1; 1663 if (scf_handle_decode_fmri(h, svcfmri, NULL, NULL, 1664 NULL, NULL, prop, 0) == -1) { 1665 free(svcfmri); 1666 goto error1; 1667 } 1668 free(svcfmri); 1669 break; 1670 case SCF_ERROR_CONSTRAINT_VIOLATED: 1671 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1672 default: 1673 goto error1; 1674 } 1675 } 1676 /* 1677 * At this point, we've successfully pulled the property from the 1678 * datastore, and simply need to copy its innards into an 1679 * scf_simple_prop_t. 1680 */ 1681 if ((ret = fill_prop(prop, pgname, propname, h)) == NULL) 1682 goto error1; 1683 1684 scf_service_destroy(svc); 1685 scf_property_destroy(prop); 1686 free(fmri_buf); 1687 if (local_h) 1688 scf_handle_destroy(h); 1689 return (ret); 1690 1691 /* 1692 * Exit point for a successful call. Below this line are exit points 1693 * for failures at various stages during the function. 1694 */ 1695 1696 error1: 1697 scf_service_destroy(svc); 1698 scf_property_destroy(prop); 1699 error2: 1700 free(fmri_buf); 1701 if (local_h) 1702 scf_handle_destroy(h); 1703 return (NULL); 1704 } 1705 1706 1707 void 1708 scf_simple_prop_free(scf_simple_prop_t *prop) 1709 { 1710 int i; 1711 1712 if (prop == NULL) 1713 return; 1714 1715 free(prop->pr_propname); 1716 free(prop->pr_pgname); 1717 switch (prop->pr_type) { 1718 case SCF_TYPE_OPAQUE: { 1719 for (i = 0; i < prop->pr_numvalues; i++) { 1720 free(prop->pr_vallist[i].pv_opaque.o_value); 1721 } 1722 break; 1723 } 1724 case SCF_TYPE_ASTRING: 1725 case SCF_TYPE_USTRING: 1726 case SCF_TYPE_HOST: 1727 case SCF_TYPE_HOSTNAME: 1728 case SCF_TYPE_NET_ADDR_V4: 1729 case SCF_TYPE_NET_ADDR_V6: 1730 case SCF_TYPE_URI: 1731 case SCF_TYPE_FMRI: { 1732 for (i = 0; i < prop->pr_numvalues; i++) { 1733 free(prop->pr_vallist[i].pv_str); 1734 } 1735 break; 1736 } 1737 default: 1738 break; 1739 } 1740 free(prop->pr_vallist); 1741 free(prop); 1742 } 1743 1744 1745 scf_simple_app_props_t * 1746 scf_simple_app_props_get(scf_handle_t *hin, const char *inst_fmri) 1747 { 1748 scf_instance_t *inst = NULL; 1749 scf_service_t *svc = NULL; 1750 scf_propertygroup_t *pg = NULL; 1751 scf_property_t *prop = NULL; 1752 scf_simple_app_props_t *ret = NULL; 1753 scf_iter_t *pgiter = NULL, *propiter = NULL; 1754 struct scf_simple_pg *thispg = NULL, *nextpg; 1755 scf_simple_prop_t *thisprop, *nextprop; 1756 scf_handle_t *h = NULL; 1757 int pgiter_ret, propiter_ret; 1758 ssize_t namelen; 1759 char *propname = NULL, *pgname = NULL, *sys_fmri; 1760 uint8_t found; 1761 boolean_t local_h = B_TRUE; 1762 1763 /* If the user passed in a handle, use it. */ 1764 if (hin != NULL) { 1765 h = hin; 1766 local_h = B_FALSE; 1767 } 1768 1769 if (local_h && ((h = handle_create()) == NULL)) 1770 return (NULL); 1771 1772 if (inst_fmri == NULL) { 1773 if ((namelen = scf_myname(h, NULL, 0)) == -1) { 1774 if (local_h) 1775 scf_handle_destroy(h); 1776 return (NULL); 1777 } 1778 if ((sys_fmri = malloc(namelen + 1)) == NULL) { 1779 if (local_h) 1780 scf_handle_destroy(h); 1781 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1782 return (NULL); 1783 } 1784 if (scf_myname(h, sys_fmri, namelen + 1) == -1) { 1785 if (local_h) 1786 scf_handle_destroy(h); 1787 free(sys_fmri); 1788 return (NULL); 1789 } 1790 } else { 1791 sys_fmri = strdup(inst_fmri); 1792 } 1793 1794 if ((namelen = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) == -1) { 1795 (void) scf_set_error(SCF_ERROR_INTERNAL); 1796 return (NULL); 1797 } 1798 1799 if ((inst = scf_instance_create(h)) == NULL || 1800 (svc = scf_service_create(h)) == NULL || 1801 (pgiter = scf_iter_create(h)) == NULL || 1802 (propiter = scf_iter_create(h)) == NULL || 1803 (pg = scf_pg_create(h)) == NULL || 1804 (prop = scf_property_create(h)) == NULL) 1805 goto error2; 1806 1807 if (scf_handle_decode_fmri(h, sys_fmri, NULL, svc, inst, NULL, NULL, 1808 SCF_DECODE_FMRI_REQUIRE_INSTANCE) == -1) { 1809 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) 1810 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1811 goto error2; 1812 } 1813 1814 if ((ret = malloc(sizeof (*ret))) == NULL || 1815 (thispg = malloc(sizeof (*thispg))) == NULL || 1816 (propname = malloc(namelen)) == NULL || 1817 (pgname = malloc(namelen)) == NULL) { 1818 free(thispg); 1819 free(ret); 1820 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1821 goto error2; 1822 } 1823 1824 ret->ap_fmri = sys_fmri; 1825 thispg->pg_name = NULL; 1826 thispg->pg_proplist = NULL; 1827 thispg->pg_next = NULL; 1828 ret->ap_pglist = thispg; 1829 1830 if (scf_iter_service_pgs_typed(pgiter, svc, SCF_GROUP_APPLICATION) != 1831 0) { 1832 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 1833 (void) scf_set_error(SCF_ERROR_INTERNAL); 1834 goto error1; 1835 } 1836 1837 while ((pgiter_ret = scf_iter_next_pg(pgiter, pg)) == 1) { 1838 if (thispg->pg_name != NULL) { 1839 if ((nextpg = malloc(sizeof (*nextpg))) == NULL) { 1840 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1841 goto error1; 1842 } 1843 thispg->pg_next = nextpg; 1844 thispg = nextpg; 1845 } else { 1846 /* This is the first iteration */ 1847 nextpg = thispg; 1848 } 1849 1850 if ((nextpg->pg_name = malloc(namelen)) == NULL) { 1851 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1852 goto error1; 1853 } 1854 1855 if (scf_pg_get_name(pg, nextpg->pg_name, namelen) < 0) { 1856 if (scf_error() == SCF_ERROR_NOT_SET) 1857 (void) scf_set_error(SCF_ERROR_INTERNAL); 1858 goto error1; 1859 } 1860 1861 nextpg->pg_next = NULL; 1862 nextpg->pg_proplist = NULL; 1863 thisprop = NULL; 1864 1865 scf_iter_reset(propiter); 1866 1867 if (scf_iter_pg_properties(propiter, pg) != 0) { 1868 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 1869 (void) scf_set_error(SCF_ERROR_INTERNAL); 1870 goto error1; 1871 } 1872 1873 while ((propiter_ret = scf_iter_next_property(propiter, prop)) 1874 == 1) { 1875 if (scf_property_get_name(prop, propname, namelen) < 1876 0) { 1877 if (scf_error() == SCF_ERROR_NOT_SET) 1878 (void) scf_set_error( 1879 SCF_ERROR_INTERNAL); 1880 goto error1; 1881 } 1882 if (thisprop != NULL) { 1883 if ((nextprop = fill_prop(prop, 1884 nextpg->pg_name, propname, h)) == NULL) 1885 goto error1; 1886 thisprop->pr_next = nextprop; 1887 thisprop = nextprop; 1888 } else { 1889 /* This is the first iteration */ 1890 if ((thisprop = fill_prop(prop, 1891 nextpg->pg_name, propname, h)) == NULL) 1892 goto error1; 1893 nextpg->pg_proplist = thisprop; 1894 nextprop = thisprop; 1895 } 1896 nextprop->pr_pg = nextpg; 1897 nextprop->pr_next = NULL; 1898 } 1899 1900 if (propiter_ret == -1) { 1901 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 1902 (void) scf_set_error(SCF_ERROR_INTERNAL); 1903 goto error1; 1904 } 1905 } 1906 1907 if (pgiter_ret == -1) { 1908 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 1909 (void) scf_set_error(SCF_ERROR_INTERNAL); 1910 goto error1; 1911 } 1912 1913 /* 1914 * At this point, we've filled the scf_simple_app_props_t with all the 1915 * properties at the service level. Now we iterate over all the 1916 * properties at the instance level, overwriting any duplicate 1917 * properties, in order to provide service/instance composition. 1918 */ 1919 1920 scf_iter_reset(pgiter); 1921 scf_iter_reset(propiter); 1922 1923 if (scf_iter_instance_pgs_typed(pgiter, inst, SCF_GROUP_APPLICATION) 1924 != 0) { 1925 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 1926 (void) scf_set_error(SCF_ERROR_INTERNAL); 1927 goto error1; 1928 } 1929 1930 while ((pgiter_ret = scf_iter_next_pg(pgiter, pg)) == 1) { 1931 1932 thispg = ret->ap_pglist; 1933 found = 0; 1934 1935 /* 1936 * Find either the end of the list, so we can append the 1937 * property group, or an existing property group that matches 1938 * it, so we can insert/overwrite its properties. 1939 */ 1940 1941 if (scf_pg_get_name(pg, pgname, namelen) < 0) { 1942 if (scf_error() == SCF_ERROR_NOT_SET) 1943 (void) scf_set_error(SCF_ERROR_INTERNAL); 1944 goto error1; 1945 } 1946 1947 while ((thispg != NULL) && (thispg->pg_name != NULL)) { 1948 if (strcmp(thispg->pg_name, pgname) == 0) { 1949 found = 1; 1950 break; 1951 } 1952 if (thispg->pg_next == NULL) 1953 break; 1954 1955 thispg = thispg->pg_next; 1956 } 1957 1958 scf_iter_reset(propiter); 1959 1960 if (scf_iter_pg_properties(propiter, pg) != 0) { 1961 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 1962 (void) scf_set_error(SCF_ERROR_INTERNAL); 1963 goto error1; 1964 } 1965 1966 if (found) { 1967 /* 1968 * insert_app_props inserts or overwrites the 1969 * properties in thispg. 1970 */ 1971 1972 if (insert_app_props(propiter, pgname, propname, 1973 thispg, prop, namelen, h) == -1) 1974 goto error1; 1975 1976 } else { 1977 /* 1978 * If the property group wasn't found, we're adding 1979 * a newly allocated property group to the end of the 1980 * list. 1981 */ 1982 1983 if ((nextpg = malloc(sizeof (*nextpg))) == NULL) { 1984 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1985 goto error1; 1986 } 1987 nextpg->pg_next = NULL; 1988 nextpg->pg_proplist = NULL; 1989 thisprop = NULL; 1990 1991 if ((nextpg->pg_name = strdup(pgname)) == NULL) { 1992 free(nextpg); 1993 goto error1; 1994 } 1995 1996 if (thispg->pg_name == NULL) { 1997 free(thispg); 1998 ret->ap_pglist = nextpg; 1999 } else { 2000 thispg->pg_next = nextpg; 2001 } 2002 2003 while ((propiter_ret = 2004 scf_iter_next_property(propiter, prop)) == 1) { 2005 if (scf_property_get_name(prop, propname, 2006 namelen) < 0) { 2007 if (scf_error() == SCF_ERROR_NOT_SET) 2008 (void) scf_set_error( 2009 SCF_ERROR_INTERNAL); 2010 goto error1; 2011 } 2012 if (thisprop != NULL) { 2013 if ((nextprop = fill_prop(prop, 2014 pgname, propname, h)) == 2015 NULL) 2016 goto error1; 2017 thisprop->pr_next = nextprop; 2018 thisprop = nextprop; 2019 } else { 2020 /* This is the first iteration */ 2021 if ((thisprop = fill_prop(prop, 2022 pgname, propname, h)) == 2023 NULL) 2024 goto error1; 2025 nextpg->pg_proplist = thisprop; 2026 nextprop = thisprop; 2027 } 2028 nextprop->pr_pg = nextpg; 2029 nextprop->pr_next = NULL; 2030 } 2031 2032 if (propiter_ret == -1) { 2033 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 2034 (void) scf_set_error( 2035 SCF_ERROR_INTERNAL); 2036 goto error1; 2037 } 2038 } 2039 2040 } 2041 2042 if (pgiter_ret == -1) { 2043 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 2044 (void) scf_set_error(SCF_ERROR_INTERNAL); 2045 goto error1; 2046 } 2047 2048 scf_iter_destroy(pgiter); 2049 scf_iter_destroy(propiter); 2050 scf_pg_destroy(pg); 2051 scf_property_destroy(prop); 2052 scf_instance_destroy(inst); 2053 scf_service_destroy(svc); 2054 free(propname); 2055 free(pgname); 2056 if (local_h) 2057 scf_handle_destroy(h); 2058 2059 if (ret->ap_pglist->pg_name == NULL) 2060 return (NULL); 2061 2062 return (ret); 2063 2064 /* 2065 * Exit point for a successful call. Below this line are exit points 2066 * for failures at various stages during the function. 2067 */ 2068 2069 error1: 2070 scf_simple_app_props_free(ret); 2071 2072 error2: 2073 scf_iter_destroy(pgiter); 2074 scf_iter_destroy(propiter); 2075 scf_pg_destroy(pg); 2076 scf_property_destroy(prop); 2077 scf_instance_destroy(inst); 2078 scf_service_destroy(svc); 2079 free(propname); 2080 free(pgname); 2081 if (local_h) 2082 scf_handle_destroy(h); 2083 return (NULL); 2084 } 2085 2086 2087 void 2088 scf_simple_app_props_free(scf_simple_app_props_t *propblock) 2089 { 2090 struct scf_simple_pg *pgthis, *pgnext; 2091 scf_simple_prop_t *propthis, *propnext; 2092 2093 if ((propblock == NULL) || (propblock->ap_pglist == NULL)) 2094 return; 2095 2096 for (pgthis = propblock->ap_pglist; pgthis != NULL; pgthis = pgnext) { 2097 pgnext = pgthis->pg_next; 2098 2099 propthis = pgthis->pg_proplist; 2100 2101 while (propthis != NULL) { 2102 propnext = propthis->pr_next; 2103 scf_simple_prop_free(propthis); 2104 propthis = propnext; 2105 } 2106 2107 free(pgthis->pg_name); 2108 free(pgthis); 2109 } 2110 2111 free(propblock->ap_fmri); 2112 free(propblock); 2113 } 2114 2115 const scf_simple_prop_t * 2116 scf_simple_app_props_next(const scf_simple_app_props_t *propblock, 2117 scf_simple_prop_t *last) 2118 { 2119 struct scf_simple_pg *this; 2120 2121 if (propblock == NULL) { 2122 (void) scf_set_error(SCF_ERROR_NOT_SET); 2123 return (NULL); 2124 } 2125 2126 this = propblock->ap_pglist; 2127 2128 /* 2129 * We're looking for the first property in this block if last is 2130 * NULL 2131 */ 2132 2133 if (last == NULL) { 2134 /* An empty pglist is legal, it just means no properties */ 2135 if (this == NULL) { 2136 (void) scf_set_error(SCF_ERROR_NONE); 2137 return (NULL); 2138 } 2139 /* 2140 * Walk until we find a pg with a property in it, or we run 2141 * out of property groups. 2142 */ 2143 while ((this->pg_proplist == NULL) && (this->pg_next != NULL)) 2144 this = this->pg_next; 2145 2146 if (this->pg_proplist == NULL) { 2147 (void) scf_set_error(SCF_ERROR_NONE); 2148 return (NULL); 2149 } 2150 2151 return (this->pg_proplist); 2152 2153 } 2154 /* 2155 * If last isn't NULL, then return the next prop in the property group, 2156 * or walk the property groups until we find another property, or 2157 * run out of property groups. 2158 */ 2159 if (last->pr_next != NULL) 2160 return (last->pr_next); 2161 2162 if (last->pr_pg->pg_next == NULL) { 2163 (void) scf_set_error(SCF_ERROR_NONE); 2164 return (NULL); 2165 } 2166 2167 this = last->pr_pg->pg_next; 2168 2169 while ((this->pg_proplist == NULL) && (this->pg_next != NULL)) 2170 this = this->pg_next; 2171 2172 if (this->pg_proplist == NULL) { 2173 (void) scf_set_error(SCF_ERROR_NONE); 2174 return (NULL); 2175 } 2176 2177 return (this->pg_proplist); 2178 } 2179 2180 const scf_simple_prop_t * 2181 scf_simple_app_props_search(const scf_simple_app_props_t *propblock, 2182 const char *pgname, const char *propname) 2183 { 2184 struct scf_simple_pg *pg; 2185 scf_simple_prop_t *prop; 2186 2187 if ((propblock == NULL) || (propname == NULL)) { 2188 (void) scf_set_error(SCF_ERROR_NOT_SET); 2189 return (NULL); 2190 } 2191 2192 pg = propblock->ap_pglist; 2193 2194 /* 2195 * If pgname is NULL, we're searching the default application 2196 * property group, otherwise we look for the specified group. 2197 */ 2198 if (pgname == NULL) { 2199 while ((pg != NULL) && 2200 (strcmp(SCF_PG_APP_DEFAULT, pg->pg_name) != 0)) 2201 pg = pg->pg_next; 2202 } else { 2203 while ((pg != NULL) && (strcmp(pgname, pg->pg_name) != 0)) 2204 pg = pg->pg_next; 2205 } 2206 2207 if (pg == NULL) { 2208 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 2209 return (NULL); 2210 } 2211 2212 prop = pg->pg_proplist; 2213 2214 while ((prop != NULL) && (strcmp(propname, prop->pr_propname) != 0)) 2215 prop = prop->pr_next; 2216 2217 if (prop == NULL) { 2218 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 2219 return (NULL); 2220 } 2221 2222 return (prop); 2223 } 2224 2225 void 2226 scf_simple_prop_next_reset(scf_simple_prop_t *prop) 2227 { 2228 if (prop == NULL) 2229 return; 2230 prop->pr_iter = 0; 2231 } 2232 2233 ssize_t 2234 scf_simple_prop_numvalues(const scf_simple_prop_t *prop) 2235 { 2236 if (prop == NULL) 2237 return (scf_set_error(SCF_ERROR_NOT_SET)); 2238 2239 return (prop->pr_numvalues); 2240 } 2241 2242 2243 scf_type_t 2244 scf_simple_prop_type(const scf_simple_prop_t *prop) 2245 { 2246 if (prop == NULL) 2247 return (scf_set_error(SCF_ERROR_NOT_SET)); 2248 2249 return (prop->pr_type); 2250 } 2251 2252 2253 char * 2254 scf_simple_prop_name(const scf_simple_prop_t *prop) 2255 { 2256 if ((prop == NULL) || (prop->pr_propname == NULL)) { 2257 (void) scf_set_error(SCF_ERROR_NOT_SET); 2258 return (NULL); 2259 } 2260 2261 return (prop->pr_propname); 2262 } 2263 2264 2265 char * 2266 scf_simple_prop_pgname(const scf_simple_prop_t *prop) 2267 { 2268 if ((prop == NULL) || (prop->pr_pgname == NULL)) { 2269 (void) scf_set_error(SCF_ERROR_NOT_SET); 2270 return (NULL); 2271 } 2272 2273 return (prop->pr_pgname); 2274 } 2275 2276 2277 static union scf_simple_prop_val * 2278 scf_next_val(scf_simple_prop_t *prop, scf_type_t type) 2279 { 2280 if (prop == NULL) { 2281 (void) scf_set_error(SCF_ERROR_NOT_SET); 2282 return (NULL); 2283 } 2284 2285 switch (prop->pr_type) { 2286 case SCF_TYPE_USTRING: 2287 case SCF_TYPE_HOST: 2288 case SCF_TYPE_HOSTNAME: 2289 case SCF_TYPE_NET_ADDR_V4: 2290 case SCF_TYPE_NET_ADDR_V6: 2291 case SCF_TYPE_URI: 2292 case SCF_TYPE_FMRI: { 2293 if (type != SCF_TYPE_USTRING) { 2294 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH); 2295 return (NULL); 2296 } 2297 break; 2298 } 2299 default: { 2300 if (type != prop->pr_type) { 2301 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH); 2302 return (NULL); 2303 } 2304 break; 2305 } 2306 } 2307 2308 if (prop->pr_iter >= prop->pr_numvalues) { 2309 (void) scf_set_error(SCF_ERROR_NONE); 2310 return (NULL); 2311 } 2312 2313 return (&prop->pr_vallist[prop->pr_iter++]); 2314 } 2315 2316 2317 uint8_t * 2318 scf_simple_prop_next_boolean(scf_simple_prop_t *prop) 2319 { 2320 union scf_simple_prop_val *ret; 2321 2322 ret = scf_next_val(prop, SCF_TYPE_BOOLEAN); 2323 2324 if (ret == NULL) 2325 return (NULL); 2326 2327 return (&ret->pv_bool); 2328 } 2329 2330 2331 uint64_t * 2332 scf_simple_prop_next_count(scf_simple_prop_t *prop) 2333 { 2334 union scf_simple_prop_val *ret; 2335 2336 ret = scf_next_val(prop, SCF_TYPE_COUNT); 2337 2338 if (ret == NULL) 2339 return (NULL); 2340 2341 return (&ret->pv_uint); 2342 } 2343 2344 2345 int64_t * 2346 scf_simple_prop_next_integer(scf_simple_prop_t *prop) 2347 { 2348 union scf_simple_prop_val *ret; 2349 2350 ret = scf_next_val(prop, SCF_TYPE_INTEGER); 2351 2352 if (ret == NULL) 2353 return (NULL); 2354 2355 return (&ret->pv_int); 2356 } 2357 2358 int64_t * 2359 scf_simple_prop_next_time(scf_simple_prop_t *prop, int32_t *nsec) 2360 { 2361 union scf_simple_prop_val *ret; 2362 2363 ret = scf_next_val(prop, SCF_TYPE_TIME); 2364 2365 if (ret == NULL) 2366 return (NULL); 2367 2368 if (nsec != NULL) 2369 *nsec = ret->pv_time.t_nsec; 2370 2371 return (&ret->pv_time.t_sec); 2372 } 2373 2374 char * 2375 scf_simple_prop_next_astring(scf_simple_prop_t *prop) 2376 { 2377 union scf_simple_prop_val *ret; 2378 2379 ret = scf_next_val(prop, SCF_TYPE_ASTRING); 2380 2381 if (ret == NULL) 2382 return (NULL); 2383 2384 return (ret->pv_str); 2385 } 2386 2387 char * 2388 scf_simple_prop_next_ustring(scf_simple_prop_t *prop) 2389 { 2390 union scf_simple_prop_val *ret; 2391 2392 ret = scf_next_val(prop, SCF_TYPE_USTRING); 2393 2394 if (ret == NULL) 2395 return (NULL); 2396 2397 return (ret->pv_str); 2398 } 2399 2400 void * 2401 scf_simple_prop_next_opaque(scf_simple_prop_t *prop, size_t *length) 2402 { 2403 union scf_simple_prop_val *ret; 2404 2405 ret = scf_next_val(prop, SCF_TYPE_OPAQUE); 2406 2407 if (ret == NULL) { 2408 *length = 0; 2409 return (NULL); 2410 } 2411 2412 *length = ret->pv_opaque.o_size; 2413 return (ret->pv_opaque.o_value); 2414 } 2415 2416 /* 2417 * Generate a filename based on the fmri and the given name and return 2418 * it in the buffer of MAXPATHLEN provided by the caller. 2419 * If temp_filename is non-zero, also generate a temporary, unique filename 2420 * and return it in the temp buffer of MAXPATHLEN provided by the caller. 2421 * The path to the generated pathname is also created. 2422 * Given fmri should begin with a scheme such as "svc:". 2423 * Returns 2424 * 0 on success 2425 * -1 if filename would exceed MAXPATHLEN or 2426 * -2 if unable to create directory to filename path 2427 */ 2428 int 2429 gen_filenms_from_fmri(const char *fmri, const char *name, char *filename, 2430 char *temp_filename) 2431 { 2432 int len; 2433 2434 len = strlen(SMF_SPEEDY_FILES_PATH); 2435 len += strlen(fmri); 2436 len += 2; /* for slash and null */ 2437 len += strlen(name); 2438 len += 6; /* For X's needed for mkstemp */ 2439 2440 if (len > MAXPATHLEN) 2441 return (-1); 2442 2443 /* Construct directory name first - speedy path ends in slash */ 2444 (void) strcpy(filename, SMF_SPEEDY_FILES_PATH); 2445 (void) strcat(filename, fmri); 2446 if (mkdirp(filename, 0755) == -1) { 2447 /* errno is set */ 2448 if (errno != EEXIST) 2449 return (-2); 2450 } 2451 2452 (void) strcat(filename, "/"); 2453 (void) strcat(filename, name); 2454 2455 if (temp_filename) { 2456 (void) strcpy(temp_filename, filename); 2457 (void) strcat(temp_filename, "XXXXXX"); 2458 } 2459 2460 return (0); 2461 } 2462