1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 25 * Copyright 2018 RackTop Systems. 26 * Copyright 2020 Joyent, Inc. 27 * Copyright 2026 Oxide Computer Company 28 */ 29 30 #include "libscf_impl.h" 31 32 #include <assert.h> 33 #include <libuutil.h> 34 #include <stdio.h> 35 #include <string.h> 36 #include <stdlib.h> 37 #include <sys/param.h> 38 #include <errno.h> 39 #include <libgen.h> 40 #include <assert.h> 41 #include "midlevel_impl.h" 42 #include "lowlevel_impl.h" 43 44 #ifndef NDEBUG 45 #define bad_error(func, err) { \ 46 uu_warn("%s:%d: %s failed with unexpected error %d. Aborting.\n", \ 47 __FILE__, __LINE__, func, err); \ 48 abort(); \ 49 } 50 #else 51 #define bad_error(func, err) abort() 52 #endif 53 54 /* Path to speedy files area must end with a slash */ 55 #define SMF_SPEEDY_FILES_PATH "/etc/svc/volatile/" 56 57 void 58 scf_simple_handle_destroy(scf_simple_handle_t *simple_h) 59 { 60 if (simple_h == NULL) 61 return; 62 63 scf_pg_destroy(simple_h->running_pg); 64 scf_pg_destroy(simple_h->editing_pg); 65 scf_snapshot_destroy(simple_h->snap); 66 scf_instance_destroy(simple_h->inst); 67 scf_handle_destroy(simple_h->h); 68 uu_free(simple_h); 69 } 70 71 /* 72 * Given a base service FMRI and the names of a property group and property, 73 * assemble_fmri() merges them into a property FMRI. Note that if the base 74 * FMRI is NULL, assemble_fmri() gets the base FMRI from scf_myname(). 75 */ 76 77 static char * 78 assemble_fmri(scf_handle_t *h, const char *base, const char *pg, 79 const char *prop) 80 { 81 size_t fmri_sz, pglen; 82 ssize_t baselen; 83 char *fmri_buf; 84 85 if (prop == NULL) { 86 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 87 return (NULL); 88 } 89 90 if (pg == NULL) 91 pglen = strlen(SCF_PG_APP_DEFAULT); 92 else 93 pglen = strlen(pg); 94 95 if (base == NULL) { 96 if ((baselen = scf_myname(h, NULL, 0)) == -1) 97 return (NULL); 98 } else { 99 baselen = strlen(base); 100 } 101 102 fmri_sz = baselen + sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1 + 103 pglen + sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1 + 104 strlen(prop) + 1; 105 106 if ((fmri_buf = malloc(fmri_sz)) == NULL) { 107 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 108 return (NULL); 109 } 110 111 if (base == NULL) { 112 if (scf_myname(h, fmri_buf, fmri_sz) == -1) { 113 free(fmri_buf); 114 return (NULL); 115 } 116 } else { 117 (void) strcpy(fmri_buf, base); 118 } 119 120 (void) strcat(fmri_buf, SCF_FMRI_PROPERTYGRP_PREFIX); 121 122 if (pg == NULL) 123 (void) strcat(fmri_buf, SCF_PG_APP_DEFAULT); 124 else 125 (void) strcat(fmri_buf, pg); 126 127 (void) strcat(fmri_buf, SCF_FMRI_PROPERTY_PREFIX); 128 (void) strcat(fmri_buf, prop); 129 return (fmri_buf); 130 } 131 132 /* 133 * Given a property, this function allocates and fills an scf_simple_prop_t 134 * with the data it contains. 135 */ 136 137 static scf_simple_prop_t * 138 fill_prop(scf_property_t *prop, const char *pgname, const char *propname, 139 scf_handle_t *h) 140 { 141 scf_simple_prop_t *ret; 142 scf_iter_t *iter; 143 scf_value_t *val; 144 int iterret, i; 145 ssize_t valsize, numvals; 146 union scf_simple_prop_val *vallist = NULL, *vallist_backup = NULL; 147 148 if ((ret = malloc(sizeof (*ret))) == NULL) { 149 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 150 return (NULL); 151 } 152 153 ret->pr_next = NULL; 154 ret->pr_pg = NULL; 155 ret->pr_iter = 0; 156 157 if (pgname == NULL) 158 ret->pr_pgname = strdup(SCF_PG_APP_DEFAULT); 159 else 160 ret->pr_pgname = strdup(pgname); 161 162 if (ret->pr_pgname == NULL) { 163 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 164 free(ret); 165 return (NULL); 166 } 167 168 if ((ret->pr_propname = strdup(propname)) == NULL) { 169 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 170 free(ret->pr_pgname); 171 free(ret); 172 return (NULL); 173 } 174 175 if (scf_property_type(prop, &ret->pr_type) == -1) 176 goto error3; 177 178 if ((iter = scf_iter_create(h)) == NULL) 179 goto error3; 180 if ((val = scf_value_create(h)) == NULL) { 181 scf_iter_destroy(iter); 182 goto error3; 183 } 184 185 if (scf_iter_property_values(iter, prop) == -1) 186 goto error1; 187 188 for (numvals = 0; (iterret = scf_iter_next_value(iter, val)) == 1; 189 numvals++) { 190 vallist_backup = vallist; 191 if ((vallist = realloc(vallist, (numvals + 1) * 192 sizeof (*vallist))) == NULL) { 193 vallist = vallist_backup; 194 goto error1; 195 } 196 197 switch (ret->pr_type) { 198 case SCF_TYPE_BOOLEAN: 199 if (scf_value_get_boolean(val, 200 &vallist[numvals].pv_bool) == -1) 201 goto error1; 202 break; 203 204 case SCF_TYPE_COUNT: 205 if (scf_value_get_count(val, 206 &vallist[numvals].pv_uint) == -1) 207 goto error1; 208 break; 209 210 case SCF_TYPE_INTEGER: 211 if (scf_value_get_integer(val, 212 &vallist[numvals].pv_int) == -1) 213 goto error1; 214 break; 215 216 case SCF_TYPE_TIME: 217 if (scf_value_get_time(val, 218 &vallist[numvals].pv_time.t_sec, 219 &vallist[numvals].pv_time.t_nsec) == -1) 220 goto error1; 221 break; 222 223 case SCF_TYPE_ASTRING: 224 vallist[numvals].pv_str = NULL; 225 if ((valsize = scf_value_get_astring(val, NULL, 0)) == 226 -1) 227 goto error1; 228 if ((vallist[numvals].pv_str = malloc(valsize+1)) == 229 NULL) { 230 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 231 goto error1; 232 } 233 if (scf_value_get_astring(val, 234 vallist[numvals].pv_str, valsize+1) == -1) { 235 free(vallist[numvals].pv_str); 236 goto error1; 237 } 238 break; 239 240 case SCF_TYPE_USTRING: 241 case SCF_TYPE_HOST: 242 case SCF_TYPE_HOSTNAME: 243 case SCF_TYPE_NET_ADDR: 244 case SCF_TYPE_NET_ADDR_V4: 245 case SCF_TYPE_NET_ADDR_V6: 246 case SCF_TYPE_URI: 247 case SCF_TYPE_FMRI: 248 vallist[numvals].pv_str = NULL; 249 if ((valsize = scf_value_get_ustring(val, NULL, 0)) == 250 -1) 251 goto error1; 252 if ((vallist[numvals].pv_str = malloc(valsize+1)) == 253 NULL) { 254 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 255 goto error1; 256 } 257 if (scf_value_get_ustring(val, 258 vallist[numvals].pv_str, valsize+1) == -1) { 259 free(vallist[numvals].pv_str); 260 goto error1; 261 } 262 break; 263 264 case SCF_TYPE_OPAQUE: 265 vallist[numvals].pv_opaque.o_value = NULL; 266 if ((valsize = scf_value_get_opaque(val, NULL, 0)) == 267 -1) 268 goto error1; 269 if ((vallist[numvals].pv_opaque.o_value = 270 malloc(valsize)) == NULL) { 271 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 272 goto error1; 273 } 274 vallist[numvals].pv_opaque.o_size = valsize; 275 if (scf_value_get_opaque(val, 276 vallist[numvals].pv_opaque.o_value, 277 valsize) == -1) { 278 free(vallist[numvals].pv_opaque.o_value); 279 goto error1; 280 } 281 break; 282 283 default: 284 (void) scf_set_error(SCF_ERROR_INTERNAL); 285 goto error1; 286 287 } 288 } 289 290 if (iterret == -1) { 291 int err = scf_error(); 292 if (err != SCF_ERROR_CONNECTION_BROKEN && 293 err != SCF_ERROR_PERMISSION_DENIED) 294 (void) scf_set_error(SCF_ERROR_INTERNAL); 295 goto error1; 296 } 297 298 ret->pr_vallist = vallist; 299 ret->pr_numvalues = numvals; 300 301 scf_iter_destroy(iter); 302 (void) scf_value_destroy(val); 303 304 return (ret); 305 306 /* 307 * Exit point for a successful call. Below this line are exit points 308 * for failures at various stages during the function. 309 */ 310 311 error1: 312 if (vallist == NULL) 313 goto error2; 314 315 switch (ret->pr_type) { 316 case SCF_TYPE_ASTRING: 317 case SCF_TYPE_USTRING: 318 case SCF_TYPE_HOST: 319 case SCF_TYPE_HOSTNAME: 320 case SCF_TYPE_NET_ADDR: 321 case SCF_TYPE_NET_ADDR_V4: 322 case SCF_TYPE_NET_ADDR_V6: 323 case SCF_TYPE_URI: 324 case SCF_TYPE_FMRI: { 325 for (i = 0; i < numvals; i++) { 326 free(vallist[i].pv_str); 327 } 328 break; 329 } 330 case SCF_TYPE_OPAQUE: { 331 for (i = 0; i < numvals; i++) { 332 free(vallist[i].pv_opaque.o_value); 333 } 334 break; 335 } 336 default: 337 break; 338 } 339 340 free(vallist); 341 342 error2: 343 scf_iter_destroy(iter); 344 (void) scf_value_destroy(val); 345 346 error3: 347 free(ret->pr_pgname); 348 free(ret->pr_propname); 349 free(ret); 350 return (NULL); 351 } 352 353 /* 354 * insert_app_props iterates over a property iterator, getting all the 355 * properties from a property group, and adding or overwriting them into 356 * a simple_app_props_t. This is used by scf_simple_app_props_get to provide 357 * service/instance composition while filling the app_props_t. 358 * insert_app_props iterates over a single property group. 359 */ 360 361 static int 362 insert_app_props(scf_iter_t *propiter, char *pgname, char *propname, struct 363 scf_simple_pg *thispg, scf_property_t *prop, size_t namelen, 364 scf_handle_t *h) 365 { 366 scf_simple_prop_t *thisprop, *prevprop, *newprop; 367 uint8_t found; 368 int propiter_ret; 369 370 while ((propiter_ret = scf_iter_next_property(propiter, prop)) == 1) { 371 372 if (scf_property_get_name(prop, propname, namelen) < 0) { 373 if (scf_error() == SCF_ERROR_NOT_SET) 374 (void) scf_set_error(SCF_ERROR_INTERNAL); 375 return (-1); 376 } 377 378 thisprop = thispg->pg_proplist; 379 prevprop = thispg->pg_proplist; 380 found = 0; 381 382 while ((thisprop != NULL) && (!found)) { 383 if (strcmp(thisprop->pr_propname, propname) == 0) { 384 found = 1; 385 if ((newprop = fill_prop(prop, pgname, 386 propname, h)) == NULL) 387 return (-1); 388 389 if (thisprop == thispg->pg_proplist) 390 thispg->pg_proplist = newprop; 391 else 392 prevprop->pr_next = newprop; 393 394 newprop->pr_pg = thispg; 395 newprop->pr_next = thisprop->pr_next; 396 scf_simple_prop_free(thisprop); 397 thisprop = NULL; 398 } else { 399 if (thisprop != thispg->pg_proplist) 400 prevprop = prevprop->pr_next; 401 thisprop = thisprop->pr_next; 402 } 403 } 404 405 if (!found) { 406 if ((newprop = fill_prop(prop, pgname, propname, h)) == 407 NULL) 408 return (-1); 409 410 if (thispg->pg_proplist == NULL) 411 thispg->pg_proplist = newprop; 412 else 413 prevprop->pr_next = newprop; 414 415 newprop->pr_pg = thispg; 416 } 417 } 418 419 if (propiter_ret == -1) { 420 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 421 (void) scf_set_error(SCF_ERROR_INTERNAL); 422 return (-1); 423 } 424 425 return (0); 426 } 427 428 429 /* 430 * Sets up e in tx to set pname's values. Returns 0 on success or -1 on 431 * failure, with scf_error() set to 432 * SCF_ERROR_HANDLE_MISMATCH - tx & e are derived from different handles 433 * SCF_ERROR_INVALID_ARGUMENT - pname or ty are invalid 434 * SCF_ERROR_NOT_BOUND - handle is not bound 435 * SCF_ERROR_CONNECTION_BROKEN - connection was broken 436 * SCF_ERROR_NOT_SET - tx has not been started 437 * SCF_ERROR_DELETED - the pg tx was started on was deleted 438 */ 439 static int 440 transaction_property_set(scf_transaction_t *tx, scf_transaction_entry_t *e, 441 const char *pname, scf_type_t ty) 442 { 443 for (;;) { 444 if (scf_transaction_property_change_type(tx, e, pname, ty) == 0) 445 return (0); 446 447 switch (scf_error()) { 448 case SCF_ERROR_HANDLE_MISMATCH: 449 case SCF_ERROR_INVALID_ARGUMENT: 450 case SCF_ERROR_NOT_BOUND: 451 case SCF_ERROR_CONNECTION_BROKEN: 452 case SCF_ERROR_NOT_SET: 453 case SCF_ERROR_DELETED: 454 default: 455 return (-1); 456 457 case SCF_ERROR_NOT_FOUND: 458 break; 459 } 460 461 if (scf_transaction_property_new(tx, e, pname, ty) == 0) 462 return (0); 463 464 switch (scf_error()) { 465 case SCF_ERROR_HANDLE_MISMATCH: 466 case SCF_ERROR_INVALID_ARGUMENT: 467 case SCF_ERROR_NOT_BOUND: 468 case SCF_ERROR_CONNECTION_BROKEN: 469 case SCF_ERROR_NOT_SET: 470 case SCF_ERROR_DELETED: 471 default: 472 return (-1); 473 474 case SCF_ERROR_EXISTS: 475 break; 476 } 477 } 478 } 479 480 static int 481 get_inst_enabled(const scf_instance_t *inst, const char *pgname) 482 { 483 scf_propertygroup_t *gpg = NULL; 484 scf_property_t *eprop = NULL; 485 scf_value_t *v = NULL; 486 scf_handle_t *h = NULL; 487 uint8_t enabled; 488 int ret = -1; 489 490 if ((h = scf_instance_handle(inst)) == NULL) 491 return (-1); 492 493 if ((gpg = scf_pg_create(h)) == NULL || 494 (eprop = scf_property_create(h)) == NULL || 495 (v = scf_value_create(h)) == NULL) 496 goto out; 497 498 if (scf_instance_get_pg(inst, pgname, gpg) || 499 scf_pg_get_property(gpg, SCF_PROPERTY_ENABLED, eprop) || 500 scf_property_get_value(eprop, v) || 501 scf_value_get_boolean(v, &enabled)) 502 goto out; 503 ret = enabled; 504 505 out: 506 scf_pg_destroy(gpg); 507 scf_property_destroy(eprop); 508 scf_value_destroy(v); 509 return (ret); 510 } 511 512 /* 513 * set_inst_enabled() is a "master" enable/disable call that takes the 514 * instance and the desired state for the enabled bit in the instance's 515 * named property group. If the group doesn't exist, it's created with the 516 * given flags. Called by smf_{dis,en}able_instance(). 517 * 518 * Note that if we're enabling, comment will be "", and we use that to clear out 519 * any old disabled comment. 520 */ 521 static int 522 set_inst_enabled(const scf_instance_t *inst, uint8_t desired, 523 const char *pgname, uint32_t pgflags, const char *comment) 524 { 525 scf_transaction_t *tx = NULL; 526 scf_transaction_entry_t *ent1 = NULL; 527 scf_transaction_entry_t *ent2 = NULL; 528 scf_propertygroup_t *gpg = NULL; 529 scf_property_t *eprop = NULL; 530 scf_value_t *v1 = NULL; 531 scf_value_t *v2 = NULL; 532 scf_handle_t *h = NULL; 533 int ret = -1; 534 int committed; 535 uint8_t b; 536 537 if ((h = scf_instance_handle(inst)) == NULL) 538 return (-1); 539 540 if ((gpg = scf_pg_create(h)) == NULL || 541 (eprop = scf_property_create(h)) == NULL || 542 (v1 = scf_value_create(h)) == NULL || 543 (v2 = scf_value_create(h)) == NULL || 544 (tx = scf_transaction_create(h)) == NULL || 545 (ent1 = scf_entry_create(h)) == NULL || 546 (ent2 = scf_entry_create(h)) == NULL) 547 goto out; 548 549 general_pg_get: 550 if (scf_instance_get_pg(inst, SCF_PG_GENERAL, gpg) == -1) { 551 if (scf_error() != SCF_ERROR_NOT_FOUND) 552 goto out; 553 554 if (scf_instance_add_pg(inst, SCF_PG_GENERAL, 555 SCF_GROUP_FRAMEWORK, SCF_PG_GENERAL_FLAGS, gpg) == -1) { 556 if (scf_error() != SCF_ERROR_EXISTS) 557 goto out; 558 goto general_pg_get; 559 } 560 } 561 562 if (strcmp(pgname, SCF_PG_GENERAL) != 0) { 563 get: 564 if (scf_instance_get_pg(inst, pgname, gpg) == -1) { 565 if (scf_error() != SCF_ERROR_NOT_FOUND) 566 goto out; 567 568 if (scf_instance_add_pg(inst, pgname, 569 SCF_GROUP_FRAMEWORK, pgflags, gpg) == -1) { 570 if (scf_error() != SCF_ERROR_EXISTS) 571 goto out; 572 goto get; 573 } 574 } 575 } 576 577 if (scf_pg_get_property(gpg, SCF_PROPERTY_ENABLED, eprop) == -1) { 578 if (scf_error() != SCF_ERROR_NOT_FOUND) 579 goto out; 580 else 581 goto set; 582 } 583 584 /* 585 * If it's already set the way we want, forgo the transaction. 586 */ 587 if (scf_property_get_value(eprop, v1) == -1) { 588 switch (scf_error()) { 589 case SCF_ERROR_CONSTRAINT_VIOLATED: 590 case SCF_ERROR_NOT_FOUND: 591 /* Misconfigured, so set anyway. */ 592 goto set; 593 594 default: 595 goto out; 596 } 597 } 598 if (scf_value_get_boolean(v1, &b) == -1) { 599 if (scf_error() != SCF_ERROR_TYPE_MISMATCH) 600 goto out; 601 goto set; 602 } 603 if (b == desired) { 604 ret = 0; 605 goto out; 606 } 607 608 set: 609 do { 610 if (scf_transaction_start(tx, gpg) == -1) 611 goto out; 612 613 if (transaction_property_set(tx, ent1, SCF_PROPERTY_ENABLED, 614 SCF_TYPE_BOOLEAN) != 0) { 615 switch (scf_error()) { 616 case SCF_ERROR_CONNECTION_BROKEN: 617 case SCF_ERROR_DELETED: 618 default: 619 goto out; 620 621 case SCF_ERROR_HANDLE_MISMATCH: 622 case SCF_ERROR_INVALID_ARGUMENT: 623 case SCF_ERROR_NOT_BOUND: 624 case SCF_ERROR_NOT_SET: 625 bad_error("transaction_property_set", 626 scf_error()); 627 } 628 } 629 630 scf_value_set_boolean(v1, desired); 631 if (scf_entry_add_value(ent1, v1) == -1) 632 goto out; 633 634 if (transaction_property_set(tx, ent2, 635 SCF_PROPERTY_COMMENT, SCF_TYPE_ASTRING) != 0) { 636 switch (scf_error()) { 637 case SCF_ERROR_CONNECTION_BROKEN: 638 case SCF_ERROR_DELETED: 639 default: 640 goto out; 641 642 case SCF_ERROR_HANDLE_MISMATCH: 643 case SCF_ERROR_INVALID_ARGUMENT: 644 case SCF_ERROR_NOT_BOUND: 645 case SCF_ERROR_NOT_SET: 646 bad_error("transaction_property_set", 647 scf_error()); 648 } 649 } 650 651 if (scf_value_set_astring(v2, comment) == -1) 652 goto out; 653 654 if (scf_entry_add_value(ent2, v2) == -1) 655 goto out; 656 657 committed = scf_transaction_commit(tx); 658 if (committed == -1) 659 goto out; 660 661 scf_transaction_reset(tx); 662 663 if (committed == 0) { /* out-of-sync */ 664 if (scf_pg_update(gpg) == -1) 665 goto out; 666 } 667 } while (committed == 0); 668 669 ret = 0; 670 671 out: 672 scf_value_destroy(v1); 673 scf_value_destroy(v2); 674 scf_entry_destroy(ent1); 675 scf_entry_destroy(ent2); 676 scf_transaction_destroy(tx); 677 scf_property_destroy(eprop); 678 scf_pg_destroy(gpg); 679 680 return (ret); 681 } 682 683 static int 684 delete_inst_enabled(const scf_instance_t *inst, const char *pgname) 685 { 686 scf_transaction_t *tx = NULL; 687 scf_transaction_entry_t *ent1 = NULL; 688 scf_transaction_entry_t *ent2 = NULL; 689 scf_propertygroup_t *gpg = NULL; 690 scf_handle_t *h = NULL; 691 int ret = -1; 692 int committed; 693 694 if ((h = scf_instance_handle(inst)) == NULL) 695 return (-1); 696 697 if ((gpg = scf_pg_create(h)) == NULL || 698 (tx = scf_transaction_create(h)) == NULL || 699 (ent1 = scf_entry_create(h)) == NULL || 700 (ent2 = scf_entry_create(h)) == NULL) 701 goto out; 702 703 if (scf_instance_get_pg(inst, pgname, gpg) != 0) 704 goto error; 705 do { 706 if (scf_transaction_start(tx, gpg) == -1) 707 goto error; 708 709 ret = scf_transaction_property_delete(tx, ent1, 710 SCF_PROPERTY_ENABLED); 711 712 if (ret == -1 && scf_error() != SCF_ERROR_DELETED && 713 scf_error() != SCF_ERROR_NOT_FOUND) 714 goto error; 715 716 ret = scf_transaction_property_delete(tx, ent2, 717 SCF_PROPERTY_COMMENT); 718 719 if (ret == -1 && scf_error() != SCF_ERROR_DELETED && 720 scf_error() != SCF_ERROR_NOT_FOUND) 721 goto error; 722 723 if ((committed = scf_transaction_commit(tx)) == -1) 724 goto error; 725 726 scf_transaction_reset(tx); 727 728 if (committed == 0 && scf_pg_update(gpg) == -1) 729 goto error; 730 } while (committed == 0); 731 732 ret = 0; 733 goto out; 734 735 error: 736 switch (scf_error()) { 737 case SCF_ERROR_DELETED: 738 case SCF_ERROR_NOT_FOUND: 739 /* success */ 740 ret = 0; 741 } 742 743 out: 744 scf_entry_destroy(ent1); 745 scf_entry_destroy(ent2); 746 scf_transaction_destroy(tx); 747 scf_pg_destroy(gpg); 748 749 return (ret); 750 } 751 752 /* 753 * Returns 0 on success or -1 on failure. On failure leaves scf_error() set to 754 * SCF_ERROR_HANDLE_DESTROYED - inst's handle has been destroyed 755 * SCF_ERROR_NOT_BOUND - inst's handle is not bound 756 * SCF_ERROR_CONNECTION_BROKEN - the repository connection was broken 757 * SCF_ERROR_NOT_SET - inst is not set 758 * SCF_ERROR_DELETED - inst was deleted 759 * SCF_ERROR_PERMISSION_DENIED 760 * SCF_ERROR_BACKEND_ACCESS 761 * SCF_ERROR_BACKEND_READONLY 762 */ 763 static int 764 set_inst_action_inst(scf_instance_t *inst, const char *action) 765 { 766 scf_handle_t *h; 767 scf_transaction_t *tx = NULL; 768 scf_transaction_entry_t *ent = NULL; 769 scf_propertygroup_t *pg = NULL; 770 scf_property_t *prop = NULL; 771 scf_value_t *v = NULL; 772 int trans, ret = -1; 773 int64_t t; 774 hrtime_t timestamp; 775 776 if ((h = scf_instance_handle(inst)) == NULL || 777 (pg = scf_pg_create(h)) == NULL || 778 (prop = scf_property_create(h)) == NULL || 779 (v = scf_value_create(h)) == NULL || 780 (tx = scf_transaction_create(h)) == NULL || 781 (ent = scf_entry_create(h)) == NULL) 782 goto out; 783 784 get: 785 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER_ACTIONS, pg) == -1) { 786 switch (scf_error()) { 787 case SCF_ERROR_NOT_BOUND: 788 case SCF_ERROR_CONNECTION_BROKEN: 789 case SCF_ERROR_NOT_SET: 790 case SCF_ERROR_DELETED: 791 default: 792 goto out; 793 794 case SCF_ERROR_NOT_FOUND: 795 break; 796 797 case SCF_ERROR_HANDLE_MISMATCH: 798 case SCF_ERROR_INVALID_ARGUMENT: 799 bad_error("scf_instance_get_pg", scf_error()); 800 } 801 802 /* Try creating the restarter_actions property group. */ 803 add: 804 if (scf_instance_add_pg(inst, SCF_PG_RESTARTER_ACTIONS, 805 SCF_PG_RESTARTER_ACTIONS_TYPE, 806 SCF_PG_RESTARTER_ACTIONS_FLAGS, pg) == -1) { 807 switch (scf_error()) { 808 case SCF_ERROR_NOT_BOUND: 809 case SCF_ERROR_CONNECTION_BROKEN: 810 case SCF_ERROR_NOT_SET: 811 case SCF_ERROR_DELETED: 812 case SCF_ERROR_PERMISSION_DENIED: 813 case SCF_ERROR_BACKEND_ACCESS: 814 case SCF_ERROR_BACKEND_READONLY: 815 default: 816 goto out; 817 818 case SCF_ERROR_EXISTS: 819 goto get; 820 821 case SCF_ERROR_HANDLE_MISMATCH: 822 case SCF_ERROR_INVALID_ARGUMENT: 823 bad_error("scf_instance_add_pg", scf_error()); 824 } 825 } 826 } 827 828 for (;;) { 829 timestamp = gethrtime(); 830 831 if (scf_pg_get_property(pg, action, prop) != 0) { 832 switch (scf_error()) { 833 case SCF_ERROR_CONNECTION_BROKEN: 834 default: 835 goto out; 836 837 case SCF_ERROR_DELETED: 838 goto add; 839 840 case SCF_ERROR_NOT_FOUND: 841 break; 842 843 case SCF_ERROR_HANDLE_MISMATCH: 844 case SCF_ERROR_INVALID_ARGUMENT: 845 case SCF_ERROR_NOT_BOUND: 846 case SCF_ERROR_NOT_SET: 847 bad_error("scf_pg_get_property", scf_error()); 848 } 849 } else if (scf_property_get_value(prop, v) != 0) { 850 switch (scf_error()) { 851 case SCF_ERROR_CONNECTION_BROKEN: 852 default: 853 goto out; 854 855 case SCF_ERROR_DELETED: 856 goto add; 857 858 case SCF_ERROR_CONSTRAINT_VIOLATED: 859 case SCF_ERROR_NOT_FOUND: 860 break; 861 862 case SCF_ERROR_HANDLE_MISMATCH: 863 case SCF_ERROR_NOT_BOUND: 864 case SCF_ERROR_NOT_SET: 865 bad_error("scf_property_get_value", 866 scf_error()); 867 } 868 } else if (scf_value_get_integer(v, &t) != 0) { 869 bad_error("scf_value_get_integer", scf_error()); 870 } else if (t > timestamp) { 871 break; 872 } 873 874 if (scf_transaction_start(tx, pg) == -1) { 875 switch (scf_error()) { 876 case SCF_ERROR_NOT_BOUND: 877 case SCF_ERROR_CONNECTION_BROKEN: 878 case SCF_ERROR_PERMISSION_DENIED: 879 case SCF_ERROR_BACKEND_ACCESS: 880 case SCF_ERROR_BACKEND_READONLY: 881 default: 882 goto out; 883 884 case SCF_ERROR_DELETED: 885 goto add; 886 887 case SCF_ERROR_HANDLE_MISMATCH: 888 case SCF_ERROR_NOT_SET: 889 case SCF_ERROR_IN_USE: 890 bad_error("scf_transaction_start", scf_error()); 891 } 892 } 893 894 if (transaction_property_set(tx, ent, action, 895 SCF_TYPE_INTEGER) != 0) { 896 switch (scf_error()) { 897 case SCF_ERROR_NOT_BOUND: 898 case SCF_ERROR_CONNECTION_BROKEN: 899 case SCF_ERROR_DELETED: 900 default: 901 goto out; 902 903 case SCF_ERROR_HANDLE_MISMATCH: 904 case SCF_ERROR_INVALID_ARGUMENT: 905 case SCF_ERROR_NOT_SET: 906 bad_error("transaction_property_set", 907 scf_error()); 908 } 909 } 910 911 scf_value_set_integer(v, timestamp); 912 if (scf_entry_add_value(ent, v) == -1) 913 bad_error("scf_entry_add_value", scf_error()); 914 915 trans = scf_transaction_commit(tx); 916 if (trans == 1) 917 break; 918 919 if (trans != 0) { 920 switch (scf_error()) { 921 case SCF_ERROR_CONNECTION_BROKEN: 922 case SCF_ERROR_PERMISSION_DENIED: 923 case SCF_ERROR_BACKEND_ACCESS: 924 case SCF_ERROR_BACKEND_READONLY: 925 default: 926 goto out; 927 928 case SCF_ERROR_DELETED: 929 scf_transaction_reset(tx); 930 goto add; 931 932 case SCF_ERROR_INVALID_ARGUMENT: 933 case SCF_ERROR_NOT_BOUND: 934 case SCF_ERROR_NOT_SET: 935 bad_error("scf_transaction_commit", 936 scf_error()); 937 } 938 } 939 940 scf_transaction_reset(tx); 941 if (scf_pg_update(pg) == -1) { 942 switch (scf_error()) { 943 case SCF_ERROR_CONNECTION_BROKEN: 944 default: 945 goto out; 946 947 case SCF_ERROR_DELETED: 948 goto add; 949 950 case SCF_ERROR_NOT_SET: 951 case SCF_ERROR_NOT_BOUND: 952 bad_error("scf_pg_update", scf_error()); 953 } 954 } 955 } 956 957 ret = 0; 958 959 out: 960 scf_value_destroy(v); 961 scf_entry_destroy(ent); 962 scf_transaction_destroy(tx); 963 scf_property_destroy(prop); 964 scf_pg_destroy(pg); 965 return (ret); 966 } 967 968 static int 969 set_inst_action(const char *fmri, const char *action) 970 { 971 scf_handle_t *h; 972 scf_instance_t *inst; 973 int ret = -1; 974 975 h = _scf_handle_create_and_bind(SCF_VERSION); 976 if (h == NULL) 977 return (-1); 978 979 inst = scf_instance_create(h); 980 981 if (inst != NULL) { 982 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, 983 NULL, SCF_DECODE_FMRI_EXACT) == 0) { 984 ret = set_inst_action_inst(inst, action); 985 if (ret == -1 && scf_error() == SCF_ERROR_DELETED) 986 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 987 } else { 988 switch (scf_error()) { 989 case SCF_ERROR_CONSTRAINT_VIOLATED: 990 (void) scf_set_error( 991 SCF_ERROR_INVALID_ARGUMENT); 992 break; 993 case SCF_ERROR_DELETED: 994 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 995 break; 996 } 997 } 998 999 scf_instance_destroy(inst); 1000 } 1001 1002 scf_handle_destroy(h); 1003 1004 return (ret); 1005 } 1006 1007 1008 /* 1009 * get_inst_state() gets the state string from an instance, and returns 1010 * the SCF_STATE_* constant that coincides with the instance's current state. 1011 */ 1012 1013 static int 1014 get_inst_state(scf_instance_t *inst, scf_handle_t *h) 1015 { 1016 scf_propertygroup_t *pg = NULL; 1017 scf_property_t *prop = NULL; 1018 scf_value_t *val = NULL; 1019 char state[MAX_SCF_STATE_STRING_SZ]; 1020 int ret = -1; 1021 1022 if (((pg = scf_pg_create(h)) == NULL) || 1023 ((prop = scf_property_create(h)) == NULL) || 1024 ((val = scf_value_create(h)) == NULL)) 1025 goto out; 1026 1027 /* Pull the state property from the instance */ 1028 1029 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) == -1 || 1030 scf_pg_get_property(pg, SCF_PROPERTY_STATE, prop) == -1 || 1031 scf_property_get_value(prop, val) == -1) { 1032 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 1033 (void) scf_set_error(SCF_ERROR_INTERNAL); 1034 goto out; 1035 } 1036 1037 if (scf_value_get_astring(val, state, sizeof (state)) <= 0) { 1038 (void) scf_set_error(SCF_ERROR_INTERNAL); 1039 goto out; 1040 } 1041 1042 if (strcmp(state, SCF_STATE_STRING_UNINIT) == 0) { 1043 ret = SCF_STATE_UNINIT; 1044 } else if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) { 1045 ret = SCF_STATE_MAINT; 1046 } else if (strcmp(state, SCF_STATE_STRING_OFFLINE) == 0) { 1047 ret = SCF_STATE_OFFLINE; 1048 } else if (strcmp(state, SCF_STATE_STRING_DISABLED) == 0) { 1049 ret = SCF_STATE_DISABLED; 1050 } else if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0) { 1051 ret = SCF_STATE_ONLINE; 1052 } else if (strcmp(state, SCF_STATE_STRING_DEGRADED) == 0) { 1053 ret = SCF_STATE_DEGRADED; 1054 } 1055 1056 out: 1057 scf_pg_destroy(pg); 1058 scf_property_destroy(prop); 1059 (void) scf_value_destroy(val); 1060 1061 return (ret); 1062 } 1063 1064 /* 1065 * Sets an instance to be enabled or disabled after reboot, using the 1066 * temporary (overriding) general_ovr property group to reflect the 1067 * present state, if it is different. 1068 */ 1069 static int 1070 set_inst_enabled_atboot(scf_instance_t *inst, uint8_t desired, 1071 const char *comment) 1072 { 1073 int enabled; 1074 int persistent; 1075 int ret = -1; 1076 1077 if ((persistent = get_inst_enabled(inst, SCF_PG_GENERAL)) < 0) { 1078 if (scf_error() != SCF_ERROR_NOT_FOUND) 1079 goto out; 1080 persistent = B_FALSE; 1081 } 1082 if ((enabled = get_inst_enabled(inst, SCF_PG_GENERAL_OVR)) < 0) { 1083 enabled = persistent; 1084 if (persistent != desired) { 1085 /* 1086 * Temporarily store the present enabled state. 1087 */ 1088 if (set_inst_enabled(inst, persistent, 1089 SCF_PG_GENERAL_OVR, SCF_PG_GENERAL_OVR_FLAGS, 1090 comment)) 1091 goto out; 1092 } 1093 } 1094 if (persistent != desired) 1095 if (set_inst_enabled(inst, desired, SCF_PG_GENERAL, 1096 SCF_PG_GENERAL_FLAGS, comment)) 1097 goto out; 1098 if (enabled == desired) 1099 ret = delete_inst_enabled(inst, SCF_PG_GENERAL_OVR); 1100 else 1101 ret = 0; 1102 1103 out: 1104 return (ret); 1105 } 1106 1107 static int 1108 set_instance_enabled_inst(scf_instance_t *inst, int flags, uint8_t desired, 1109 const char *comment) 1110 { 1111 int ret = -1; 1112 1113 if (flags & ~(SMF_TEMPORARY | SMF_AT_NEXT_BOOT) || 1114 flags & SMF_TEMPORARY && flags & SMF_AT_NEXT_BOOT) { 1115 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 1116 } 1117 1118 if (flags & SMF_AT_NEXT_BOOT) { 1119 ret = set_inst_enabled_atboot(inst, desired, comment); 1120 } else { 1121 if (set_inst_enabled(inst, desired, flags & SMF_TEMPORARY ? 1122 SCF_PG_GENERAL_OVR : SCF_PG_GENERAL, flags & SMF_TEMPORARY ? 1123 SCF_PG_GENERAL_OVR_FLAGS : SCF_PG_GENERAL_FLAGS, comment)) 1124 goto out; 1125 1126 /* 1127 * Make the persistent value effective by deleting the 1128 * temporary one. 1129 */ 1130 if (flags & SMF_TEMPORARY) 1131 ret = 0; 1132 else 1133 ret = delete_inst_enabled(inst, SCF_PG_GENERAL_OVR); 1134 } 1135 1136 out: 1137 if (ret == -1 && scf_error() == SCF_ERROR_DELETED) 1138 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 1139 return (ret); 1140 } 1141 1142 static int 1143 set_inst_enabled_flags(const char *fmri, int flags, uint8_t desired, 1144 const char *comment) 1145 { 1146 int ret = -1; 1147 scf_handle_t *h; 1148 scf_instance_t *inst; 1149 1150 if ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL) 1151 return (ret); 1152 1153 if ((inst = scf_instance_create(h)) == NULL) { 1154 scf_handle_destroy(h); 1155 return (ret); 1156 } 1157 1158 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, NULL, 1159 SCF_DECODE_FMRI_EXACT) == -1) { 1160 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) 1161 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1162 goto out; 1163 } 1164 1165 ret = set_instance_enabled_inst(inst, flags, desired, comment); 1166 1167 out: 1168 scf_instance_destroy(inst); 1169 scf_handle_destroy(h); 1170 return (ret); 1171 } 1172 1173 /* 1174 * Create and return a pg from the instance associated with the given handle. 1175 * This function is only called in scf_transaction_setup and 1176 * scf_transaction_restart where the h->rh_instance pointer is properly filled 1177 * in by scf_general_setup_pg(). 1178 */ 1179 static scf_propertygroup_t * 1180 get_instance_pg(scf_simple_handle_t *simple_h) 1181 { 1182 scf_propertygroup_t *ret_pg = scf_pg_create(simple_h->h); 1183 char *pg_name; 1184 ssize_t namelen; 1185 1186 if (ret_pg == NULL) { 1187 return (NULL); 1188 } 1189 1190 namelen = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1; 1191 assert(namelen > 0); 1192 1193 if ((pg_name = malloc(namelen)) == NULL) { 1194 if (scf_error() == SCF_ERROR_NOT_SET) { 1195 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1196 } 1197 return (NULL); 1198 } 1199 1200 if (scf_pg_get_name(simple_h->running_pg, pg_name, namelen) < 0) { 1201 if (scf_error() == SCF_ERROR_NOT_SET) { 1202 (void) scf_set_error(SCF_ERROR_INTERNAL); 1203 } 1204 return (NULL); 1205 } 1206 1207 /* Get pg from instance */ 1208 if (scf_instance_get_pg(simple_h->inst, pg_name, ret_pg) == -1) { 1209 return (NULL); 1210 } 1211 1212 return (ret_pg); 1213 } 1214 1215 int 1216 smf_enable_instance(const char *fmri, int flags) 1217 { 1218 return (set_inst_enabled_flags(fmri, flags, B_TRUE, "")); 1219 } 1220 1221 int 1222 smf_enable_instance_by_instance(scf_instance_t *inst, int flags, 1223 const char *comment) 1224 { 1225 if (comment == NULL) 1226 comment = ""; 1227 return (set_instance_enabled_inst(inst, flags, B_TRUE, comment)); 1228 } 1229 1230 int 1231 smf_disable_instance_with_comment(const char *fmri, int flags, 1232 const char *comment) 1233 { 1234 return (set_inst_enabled_flags(fmri, flags, B_FALSE, comment)); 1235 } 1236 1237 int 1238 smf_disable_instance(const char *fmri, int flags) 1239 { 1240 return (set_inst_enabled_flags(fmri, flags, B_FALSE, "")); 1241 } 1242 1243 int 1244 smf_disable_instance_by_instance(scf_instance_t *inst, int flags, 1245 const char *comment) 1246 { 1247 if (comment == NULL) 1248 comment = ""; 1249 return (set_instance_enabled_inst(inst, flags, B_FALSE, comment)); 1250 } 1251 1252 int 1253 smf_refresh_all_instances(scf_service_t *s) 1254 { 1255 scf_handle_t *h = scf_service_handle(s); 1256 scf_instance_t *i = scf_instance_create(h); 1257 scf_iter_t *it = scf_iter_create(h); 1258 int err, r = -1; 1259 1260 if (h == NULL || i == NULL || it == NULL) 1261 goto error; 1262 1263 if (scf_iter_service_instances(it, s) != 0) 1264 goto error; 1265 1266 while ((err = scf_iter_next_instance(it, i)) == 1) 1267 if (smf_refresh_instance_by_instance(i) != 0) 1268 goto error; 1269 1270 if (err == -1) 1271 goto error; 1272 1273 r = 0; 1274 error: 1275 scf_instance_destroy(i); 1276 scf_iter_destroy(it); 1277 1278 return (r); 1279 } 1280 1281 int 1282 smf_refresh_instance(const char *instance) 1283 { 1284 return (set_inst_action(instance, SCF_PROPERTY_REFRESH)); 1285 } 1286 1287 /* 1288 * The tools svccfg needs the uncommited name for this. 1289 */ 1290 #pragma weak _smf_refresh_instance_i = smf_refresh_instance_by_instance 1291 int 1292 smf_refresh_instance_by_instance(scf_instance_t *inst) 1293 { 1294 return (set_inst_action_inst(inst, SCF_PROPERTY_REFRESH)); 1295 } 1296 1297 int 1298 smf_restart_instance(const char *instance) 1299 { 1300 return (set_inst_action(instance, SCF_PROPERTY_RESTART)); 1301 } 1302 1303 int 1304 smf_restart_instance_by_instance(scf_instance_t *inst) 1305 { 1306 return (set_inst_action_inst(inst, SCF_PROPERTY_RESTART)); 1307 } 1308 1309 int 1310 smf_maintain_instance(const char *instance, int flags) 1311 { 1312 if (flags & SMF_TEMPORARY) 1313 return (set_inst_action(instance, 1314 (flags & SMF_IMMEDIATE) ? 1315 SCF_PROPERTY_MAINT_ON_IMMTEMP : 1316 SCF_PROPERTY_MAINT_ON_TEMPORARY)); 1317 else 1318 return (set_inst_action(instance, 1319 (flags & SMF_IMMEDIATE) ? 1320 SCF_PROPERTY_MAINT_ON_IMMEDIATE : 1321 SCF_PROPERTY_MAINT_ON)); 1322 } 1323 1324 int 1325 smf_maintain_instance_by_instance(scf_instance_t *inst, int flags) 1326 { 1327 if (flags & SMF_TEMPORARY) 1328 return (set_inst_action_inst(inst, 1329 (flags & SMF_IMMEDIATE) ? 1330 SCF_PROPERTY_MAINT_ON_IMMTEMP : 1331 SCF_PROPERTY_MAINT_ON_TEMPORARY)); 1332 else 1333 return (set_inst_action_inst(inst, 1334 (flags & SMF_IMMEDIATE) ? 1335 SCF_PROPERTY_MAINT_ON_IMMEDIATE : 1336 SCF_PROPERTY_MAINT_ON)); 1337 } 1338 1339 int 1340 smf_degrade_instance(const char *instance, int flags) 1341 { 1342 scf_simple_prop_t *prop; 1343 const char *state_str; 1344 1345 if (flags & SMF_TEMPORARY) 1346 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 1347 1348 if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER, 1349 SCF_PROPERTY_STATE)) == NULL) 1350 return (SCF_FAILED); 1351 1352 if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) { 1353 scf_simple_prop_free(prop); 1354 return (SCF_FAILED); 1355 } 1356 1357 if (strcmp(state_str, SCF_STATE_STRING_ONLINE) != 0) { 1358 scf_simple_prop_free(prop); 1359 return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED)); 1360 } 1361 scf_simple_prop_free(prop); 1362 1363 return (set_inst_action(instance, (flags & SMF_IMMEDIATE) ? 1364 SCF_PROPERTY_DEGRADE_IMMEDIATE : SCF_PROPERTY_DEGRADED)); 1365 } 1366 1367 int 1368 smf_degrade_instance_by_instance(scf_instance_t *inst, int flags) 1369 { 1370 char *state; 1371 1372 if (flags & SMF_TEMPORARY) 1373 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 1374 1375 if ((state = smf_get_state_by_instance(inst)) == NULL) { 1376 return (SCF_FAILED); 1377 } 1378 1379 if (strcmp(state, SCF_STATE_STRING_ONLINE) != 0) { 1380 free(state); 1381 return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED)); 1382 } 1383 free(state); 1384 1385 return (set_inst_action_inst(inst, (flags & SMF_IMMEDIATE) ? 1386 SCF_PROPERTY_DEGRADE_IMMEDIATE : SCF_PROPERTY_DEGRADED)); 1387 } 1388 1389 int 1390 smf_restore_instance(const char *instance) 1391 { 1392 scf_simple_prop_t *prop; 1393 const char *state_str; 1394 int ret; 1395 1396 if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER, 1397 SCF_PROPERTY_STATE)) == NULL) 1398 return (SCF_FAILED); 1399 1400 if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) { 1401 scf_simple_prop_free(prop); 1402 return (SCF_FAILED); 1403 } 1404 1405 if (strcmp(state_str, SCF_STATE_STRING_MAINT) == 0) { 1406 ret = set_inst_action(instance, SCF_PROPERTY_MAINT_OFF); 1407 } else if (strcmp(state_str, SCF_STATE_STRING_DEGRADED) == 0) { 1408 ret = set_inst_action(instance, SCF_PROPERTY_RESTORE); 1409 } else { 1410 ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED); 1411 } 1412 1413 scf_simple_prop_free(prop); 1414 return (ret); 1415 } 1416 1417 int 1418 smf_restore_instance_by_instance(scf_instance_t *inst) 1419 { 1420 char *state; 1421 int ret; 1422 1423 if ((state = smf_get_state_by_instance(inst)) == NULL) { 1424 return (SCF_FAILED); 1425 } 1426 1427 if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) { 1428 ret = set_inst_action_inst(inst, SCF_PROPERTY_MAINT_OFF); 1429 } else if (strcmp(state, SCF_STATE_STRING_DEGRADED) == 0) { 1430 ret = set_inst_action_inst(inst, SCF_PROPERTY_RESTORE); 1431 } else { 1432 ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED); 1433 } 1434 1435 free(state); 1436 return (ret); 1437 } 1438 1439 char * 1440 smf_get_state(const char *instance) 1441 { 1442 scf_simple_prop_t *prop; 1443 const char *state_str; 1444 char *ret; 1445 1446 if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER, 1447 SCF_PROPERTY_STATE)) == NULL) 1448 return (NULL); 1449 1450 if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) { 1451 scf_simple_prop_free(prop); 1452 return (NULL); 1453 } 1454 1455 if ((ret = strdup(state_str)) == NULL) 1456 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1457 1458 scf_simple_prop_free(prop); 1459 return (ret); 1460 } 1461 1462 char * 1463 smf_get_state_by_instance(scf_instance_t *inst) 1464 { 1465 scf_propertygroup_t *pg = NULL; 1466 scf_property_t *prop = NULL; 1467 scf_value_t *value = NULL; 1468 char *ret = NULL; 1469 ssize_t slen, alen; 1470 scf_handle_t *h = NULL; 1471 1472 if ((h = scf_instance_handle(inst)) == NULL) 1473 return (NULL); 1474 1475 if ((pg = scf_pg_create(h)) == NULL || 1476 (prop = scf_property_create(h)) == NULL || 1477 (value = scf_value_create(h)) == NULL) { 1478 goto out; 1479 } 1480 1481 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != 0 || 1482 scf_pg_get_property(pg, SCF_PROPERTY_STATE, prop) != 0 || 1483 scf_property_get_value(prop, value) != 0) { 1484 goto out; 1485 } 1486 1487 slen = scf_value_get_as_string(value, NULL, 0); 1488 if (slen == -1) { 1489 goto out; 1490 } 1491 1492 ret = malloc((size_t)slen + 1); 1493 if (ret == NULL) { 1494 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1495 goto out; 1496 } 1497 1498 /* 1499 * Given that this worked previously we don't expect it to fail again; 1500 * however, if for some reason we get a different length string or 1501 * something else goes wrong, we want to make sure that we flag that. We 1502 * use SCF_ERROR_INTERNAL for a string mismatch as there's really no 1503 * other good descriptor for this kind of case where in reality we 1504 * should probably instead call upanic(2). 1505 */ 1506 alen = scf_value_get_as_string(value, ret, slen + 1); 1507 if (alen == -1) { 1508 free(ret); 1509 ret = NULL; 1510 } else if (alen != slen) { 1511 (void) scf_set_error(SCF_ERROR_INTERNAL); 1512 free(ret); 1513 ret = NULL; 1514 } 1515 out: 1516 scf_value_destroy(value); 1517 scf_property_destroy(prop); 1518 scf_pg_destroy(pg); 1519 return (ret); 1520 } 1521 1522 /* 1523 * scf_general_pg_setup(fmri, pg_name) 1524 * Create a scf_simple_handle_t and fill in the instance, snapshot, and 1525 * property group fields associated with the given fmri and property group 1526 * name. 1527 * Returns: 1528 * Handle on success 1529 * Null on error with scf_error set to: 1530 * SCF_ERROR_HANDLE_MISMATCH, 1531 * SCF_ERROR_INVALID_ARGUMENT, 1532 * SCF_ERROR_CONSTRAINT_VIOLATED, 1533 * SCF_ERROR_NOT_FOUND, 1534 * SCF_ERROR_NOT_SET, 1535 * SCF_ERROR_DELETED, 1536 * SCF_ERROR_NOT_BOUND, 1537 * SCF_ERROR_CONNECTION_BROKEN, 1538 * SCF_ERROR_INTERNAL, 1539 * SCF_ERROR_NO_RESOURCES, 1540 * SCF_ERROR_BACKEND_ACCESS 1541 */ 1542 scf_simple_handle_t * 1543 scf_general_pg_setup(const char *fmri, const char *pg_name) 1544 { 1545 scf_simple_handle_t *ret; 1546 1547 ret = uu_zalloc(sizeof (*ret)); 1548 if (ret == NULL) { 1549 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1550 return (NULL); 1551 } else { 1552 1553 ret->h = _scf_handle_create_and_bind(SCF_VERSION); 1554 ret->inst = scf_instance_create(ret->h); 1555 ret->snap = scf_snapshot_create(ret->h); 1556 ret->running_pg = scf_pg_create(ret->h); 1557 } 1558 1559 if ((ret->h == NULL) || (ret->inst == NULL) || 1560 (ret->snap == NULL) || (ret->running_pg == NULL)) { 1561 goto out; 1562 } 1563 1564 if (scf_handle_decode_fmri(ret->h, fmri, NULL, NULL, ret->inst, 1565 NULL, NULL, 0) == -1) { 1566 goto out; 1567 } 1568 1569 if ((scf_instance_get_snapshot(ret->inst, "running", ret->snap)) 1570 != 0) { 1571 goto out; 1572 } 1573 1574 if (scf_instance_get_pg_composed(ret->inst, ret->snap, pg_name, 1575 ret->running_pg) != 0) { 1576 goto out; 1577 } 1578 1579 return (ret); 1580 1581 out: 1582 scf_simple_handle_destroy(ret); 1583 return (NULL); 1584 } 1585 1586 /* 1587 * scf_transaction_setup(h) 1588 * creates and starts the transaction 1589 * Returns: 1590 * transaction on success 1591 * NULL on failure with scf_error set to: 1592 * SCF_ERROR_NO_MEMORY, 1593 * SCF_ERROR_INVALID_ARGUMENT, 1594 * SCF_ERROR_HANDLE_DESTROYED, 1595 * SCF_ERROR_INTERNAL, 1596 * SCF_ERROR_NO_RESOURCES, 1597 * SCF_ERROR_NOT_BOUND, 1598 * SCF_ERROR_CONNECTION_BROKEN, 1599 * SCF_ERROR_NOT_SET, 1600 * SCF_ERROR_DELETED, 1601 * SCF_ERROR_CONSTRAINT_VIOLATED, 1602 * SCF_ERROR_HANDLE_MISMATCH, 1603 * SCF_ERROR_BACKEND_ACCESS, 1604 * SCF_ERROR_IN_USE 1605 */ 1606 scf_transaction_t * 1607 scf_transaction_setup(scf_simple_handle_t *simple_h) 1608 { 1609 scf_transaction_t *tx = NULL; 1610 1611 if ((tx = scf_transaction_create(simple_h->h)) == NULL) { 1612 return (NULL); 1613 } 1614 1615 if ((simple_h->editing_pg = get_instance_pg(simple_h)) == NULL) { 1616 return (NULL); 1617 } 1618 1619 if (scf_transaction_start(tx, simple_h->editing_pg) == -1) { 1620 scf_pg_destroy(simple_h->editing_pg); 1621 simple_h->editing_pg = NULL; 1622 return (NULL); 1623 } 1624 1625 return (tx); 1626 } 1627 1628 int 1629 scf_transaction_restart(scf_simple_handle_t *simple_h, scf_transaction_t *tx) 1630 { 1631 scf_transaction_reset(tx); 1632 1633 if (scf_pg_update(simple_h->editing_pg) == -1) { 1634 return (SCF_FAILED); 1635 } 1636 1637 if (scf_transaction_start(tx, simple_h->editing_pg) == -1) { 1638 return (SCF_FAILED); 1639 } 1640 1641 return (SCF_SUCCESS); 1642 } 1643 1644 /* 1645 * scf_read_count_property(scf_simple_handle_t *simple_h, char *prop_name, 1646 * uint64_t *ret_count) 1647 * 1648 * For the given property name, return the count value. 1649 * RETURNS: 1650 * SCF_SUCCESS 1651 * SCF_FAILED on failure with scf_error() set to: 1652 * SCF_ERROR_HANDLE_DESTROYED 1653 * SCF_ERROR_INTERNAL 1654 * SCF_ERROR_NO_RESOURCES 1655 * SCF_ERROR_NO_MEMORY 1656 * SCF_ERROR_HANDLE_MISMATCH 1657 * SCF_ERROR_INVALID_ARGUMENT 1658 * SCF_ERROR_NOT_BOUND 1659 * SCF_ERROR_CONNECTION_BROKEN 1660 * SCF_ERROR_NOT_SET 1661 * SCF_ERROR_DELETED 1662 * SCF_ERROR_BACKEND_ACCESS 1663 * SCF_ERROR_CONSTRAINT_VIOLATED 1664 * SCF_ERROR_TYPE_MISMATCH 1665 */ 1666 int 1667 scf_read_count_property( 1668 scf_simple_handle_t *simple_h, 1669 char *prop_name, 1670 uint64_t *ret_count) 1671 { 1672 scf_property_t *prop = scf_property_create(simple_h->h); 1673 scf_value_t *val = scf_value_create(simple_h->h); 1674 int ret = SCF_FAILED; 1675 1676 if ((val == NULL) || (prop == NULL)) { 1677 goto out; 1678 } 1679 1680 /* 1681 * Get the property struct that goes with this property group and 1682 * property name. 1683 */ 1684 if (scf_pg_get_property(simple_h->running_pg, prop_name, prop) != 0) { 1685 goto out; 1686 } 1687 1688 /* Get the value structure */ 1689 if (scf_property_get_value(prop, val) == -1) { 1690 goto out; 1691 } 1692 1693 /* 1694 * Now get the count value. 1695 */ 1696 if (scf_value_get_count(val, ret_count) == -1) { 1697 goto out; 1698 } 1699 1700 ret = SCF_SUCCESS; 1701 1702 out: 1703 scf_property_destroy(prop); 1704 scf_value_destroy(val); 1705 return (ret); 1706 } 1707 1708 /* 1709 * scf_trans_add_count_property(trans, propname, count, create_flag) 1710 * 1711 * Set a count property transaction entry into the pending SMF transaction. 1712 * The transaction is created and committed outside of this function. 1713 * Returns: 1714 * SCF_SUCCESS 1715 * SCF_FAILED on failure with scf_error() set to: 1716 * SCF_ERROR_HANDLE_DESTROYED, 1717 * SCF_ERROR_INVALID_ARGUMENT, 1718 * SCF_ERROR_NO_MEMORY, 1719 * SCF_ERROR_HANDLE_MISMATCH, 1720 * SCF_ERROR_NOT_SET, 1721 * SCF_ERROR_IN_USE, 1722 * SCF_ERROR_NOT_FOUND, 1723 * SCF_ERROR_EXISTS, 1724 * SCF_ERROR_TYPE_MISMATCH, 1725 * SCF_ERROR_NOT_BOUND, 1726 * SCF_ERROR_CONNECTION_BROKEN, 1727 * SCF_ERROR_INTERNAL, 1728 * SCF_ERROR_DELETED, 1729 * SCF_ERROR_NO_RESOURCES, 1730 * SCF_ERROR_BACKEND_ACCESS 1731 */ 1732 int 1733 scf_set_count_property( 1734 scf_transaction_t *trans, 1735 char *propname, 1736 uint64_t count, 1737 boolean_t create_flag) 1738 { 1739 scf_handle_t *handle = scf_transaction_handle(trans); 1740 scf_value_t *value = scf_value_create(handle); 1741 scf_transaction_entry_t *entry = scf_entry_create(handle); 1742 1743 if ((value == NULL) || (entry == NULL)) { 1744 return (SCF_FAILED); 1745 } 1746 1747 /* 1748 * Property must be set in transaction and won't take 1749 * effect until the transaction is committed. 1750 * 1751 * Attempt to change the current value. However, create new property 1752 * if it doesn't exist and the create flag is set. 1753 */ 1754 if (scf_transaction_property_change(trans, entry, propname, 1755 SCF_TYPE_COUNT) == 0) { 1756 scf_value_set_count(value, count); 1757 if (scf_entry_add_value(entry, value) == 0) { 1758 return (SCF_SUCCESS); 1759 } 1760 } else { 1761 if ((create_flag == B_TRUE) && 1762 (scf_error() == SCF_ERROR_NOT_FOUND)) { 1763 if (scf_transaction_property_new(trans, entry, propname, 1764 SCF_TYPE_COUNT) == 0) { 1765 scf_value_set_count(value, count); 1766 if (scf_entry_add_value(entry, value) == 0) { 1767 return (SCF_SUCCESS); 1768 } 1769 } 1770 } 1771 } 1772 1773 /* 1774 * cleanup if there were any errors that didn't leave these 1775 * values where they would be cleaned up later. 1776 */ 1777 if (value != NULL) 1778 scf_value_destroy(value); 1779 if (entry != NULL) 1780 scf_entry_destroy(entry); 1781 return (SCF_FAILED); 1782 } 1783 1784 int 1785 scf_simple_walk_instances(uint_t state_flags, void *private, 1786 int (*inst_callback)(scf_handle_t *, scf_instance_t *, void *)) 1787 { 1788 scf_scope_t *scope = NULL; 1789 scf_service_t *svc = NULL; 1790 scf_instance_t *inst = NULL; 1791 scf_iter_t *svc_iter = NULL, *inst_iter = NULL; 1792 scf_handle_t *h = NULL; 1793 int ret = SCF_FAILED; 1794 int svc_iter_ret, inst_iter_ret; 1795 int inst_state; 1796 1797 if ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL) 1798 return (ret); 1799 1800 if (((scope = scf_scope_create(h)) == NULL) || 1801 ((svc = scf_service_create(h)) == NULL) || 1802 ((inst = scf_instance_create(h)) == NULL) || 1803 ((svc_iter = scf_iter_create(h)) == NULL) || 1804 ((inst_iter = scf_iter_create(h)) == NULL)) 1805 goto out; 1806 1807 /* 1808 * Get the local scope, and set up nested iteration through every 1809 * local service, and every instance of every service. 1810 */ 1811 1812 if ((scf_handle_get_local_scope(h, scope) != SCF_SUCCESS) || 1813 (scf_iter_scope_services(svc_iter, scope) != SCF_SUCCESS)) 1814 goto out; 1815 1816 while ((svc_iter_ret = scf_iter_next_service(svc_iter, svc)) > 0) { 1817 1818 if ((scf_iter_service_instances(inst_iter, svc)) != 1819 SCF_SUCCESS) 1820 goto out; 1821 1822 while ((inst_iter_ret = 1823 scf_iter_next_instance(inst_iter, inst)) > 0) { 1824 /* 1825 * If get_inst_state fails from an internal error, 1826 * IE, being unable to get the property group or 1827 * property containing the state of the instance, 1828 * we continue instead of failing, as this might just 1829 * be an improperly configured instance. 1830 */ 1831 if ((inst_state = get_inst_state(inst, h)) == -1) { 1832 if (scf_error() == SCF_ERROR_INTERNAL) { 1833 continue; 1834 } else { 1835 goto out; 1836 } 1837 } 1838 1839 if ((uint_t)inst_state & state_flags) { 1840 if (inst_callback(h, inst, private) != 1841 SCF_SUCCESS) { 1842 (void) scf_set_error( 1843 SCF_ERROR_CALLBACK_FAILED); 1844 goto out; 1845 } 1846 } 1847 } 1848 1849 if (inst_iter_ret == -1) 1850 goto out; 1851 scf_iter_reset(inst_iter); 1852 } 1853 1854 if (svc_iter_ret != -1) 1855 ret = SCF_SUCCESS; 1856 1857 out: 1858 scf_scope_destroy(scope); 1859 scf_service_destroy(svc); 1860 scf_instance_destroy(inst); 1861 scf_iter_destroy(svc_iter); 1862 scf_iter_destroy(inst_iter); 1863 scf_handle_destroy(h); 1864 1865 return (ret); 1866 } 1867 1868 1869 scf_simple_prop_t * 1870 scf_simple_prop_get(scf_handle_t *hin, const char *instance, const char *pgname, 1871 const char *propname) 1872 { 1873 char *fmri_buf, *svcfmri = NULL; 1874 ssize_t fmri_sz; 1875 scf_property_t *prop = NULL; 1876 scf_service_t *svc = NULL; 1877 scf_simple_prop_t *ret; 1878 scf_handle_t *h = NULL; 1879 boolean_t local_h = B_TRUE; 1880 1881 /* If the user passed in a handle, use it. */ 1882 if (hin != NULL) { 1883 h = hin; 1884 local_h = B_FALSE; 1885 } 1886 1887 if (local_h && ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL)) 1888 return (NULL); 1889 1890 if ((fmri_buf = assemble_fmri(h, instance, pgname, propname)) == NULL) { 1891 if (local_h) 1892 scf_handle_destroy(h); 1893 return (NULL); 1894 } 1895 1896 if ((svc = scf_service_create(h)) == NULL || 1897 (prop = scf_property_create(h)) == NULL) 1898 goto error1; 1899 if (scf_handle_decode_fmri(h, fmri_buf, NULL, NULL, NULL, NULL, prop, 1900 SCF_DECODE_FMRI_REQUIRE_INSTANCE) == -1) { 1901 switch (scf_error()) { 1902 /* 1903 * If the property isn't found in the instance, we grab the 1904 * underlying service, create an FMRI out of it, and then 1905 * query the datastore again at the service level for the 1906 * property. 1907 */ 1908 case SCF_ERROR_NOT_FOUND: 1909 if (scf_handle_decode_fmri(h, fmri_buf, NULL, svc, 1910 NULL, NULL, NULL, SCF_DECODE_FMRI_TRUNCATE) == -1) 1911 goto error1; 1912 1913 fmri_sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH) + 1; 1914 assert(fmri_sz > 0); 1915 1916 if (scf_service_to_fmri(svc, fmri_buf, fmri_sz) == -1) 1917 goto error1; 1918 if ((svcfmri = assemble_fmri(h, fmri_buf, pgname, 1919 propname)) == NULL) 1920 goto error1; 1921 if (scf_handle_decode_fmri(h, svcfmri, NULL, NULL, 1922 NULL, NULL, prop, 0) == -1) { 1923 free(svcfmri); 1924 goto error1; 1925 } 1926 free(svcfmri); 1927 break; 1928 case SCF_ERROR_CONSTRAINT_VIOLATED: 1929 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1930 default: 1931 goto error1; 1932 } 1933 } 1934 /* 1935 * At this point, we've successfully pulled the property from the 1936 * datastore, and simply need to copy its innards into an 1937 * scf_simple_prop_t. 1938 */ 1939 if ((ret = fill_prop(prop, pgname, propname, h)) == NULL) 1940 goto error1; 1941 1942 scf_service_destroy(svc); 1943 scf_property_destroy(prop); 1944 free(fmri_buf); 1945 if (local_h) 1946 scf_handle_destroy(h); 1947 return (ret); 1948 1949 /* 1950 * Exit point for a successful call. Below this line are exit points 1951 * for failures at various stages during the function. 1952 */ 1953 1954 error1: 1955 scf_service_destroy(svc); 1956 scf_property_destroy(prop); 1957 free(fmri_buf); 1958 if (local_h) 1959 scf_handle_destroy(h); 1960 return (NULL); 1961 } 1962 1963 1964 void 1965 scf_simple_prop_free(scf_simple_prop_t *prop) 1966 { 1967 int i; 1968 1969 if (prop == NULL) 1970 return; 1971 1972 free(prop->pr_propname); 1973 free(prop->pr_pgname); 1974 switch (prop->pr_type) { 1975 case SCF_TYPE_OPAQUE: { 1976 for (i = 0; i < prop->pr_numvalues; i++) { 1977 free(prop->pr_vallist[i].pv_opaque.o_value); 1978 } 1979 break; 1980 } 1981 case SCF_TYPE_ASTRING: 1982 case SCF_TYPE_USTRING: 1983 case SCF_TYPE_HOST: 1984 case SCF_TYPE_HOSTNAME: 1985 case SCF_TYPE_NET_ADDR: 1986 case SCF_TYPE_NET_ADDR_V4: 1987 case SCF_TYPE_NET_ADDR_V6: 1988 case SCF_TYPE_URI: 1989 case SCF_TYPE_FMRI: { 1990 for (i = 0; i < prop->pr_numvalues; i++) { 1991 free(prop->pr_vallist[i].pv_str); 1992 } 1993 break; 1994 } 1995 default: 1996 break; 1997 } 1998 free(prop->pr_vallist); 1999 free(prop); 2000 } 2001 2002 2003 scf_simple_app_props_t * 2004 scf_simple_app_props_get(scf_handle_t *hin, const char *inst_fmri) 2005 { 2006 scf_instance_t *inst = NULL; 2007 scf_service_t *svc = NULL; 2008 scf_propertygroup_t *pg = NULL; 2009 scf_property_t *prop = NULL; 2010 scf_simple_app_props_t *ret = NULL; 2011 scf_iter_t *pgiter = NULL, *propiter = NULL; 2012 struct scf_simple_pg *thispg = NULL, *nextpg; 2013 scf_simple_prop_t *thisprop, *nextprop; 2014 scf_handle_t *h = NULL; 2015 int pgiter_ret, propiter_ret; 2016 ssize_t namelen; 2017 char *propname = NULL, *pgname = NULL, *sys_fmri; 2018 uint8_t found; 2019 boolean_t local_h = B_TRUE; 2020 2021 /* If the user passed in a handle, use it. */ 2022 if (hin != NULL) { 2023 h = hin; 2024 local_h = B_FALSE; 2025 } 2026 2027 if (local_h && ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL)) 2028 return (NULL); 2029 2030 if (inst_fmri == NULL) { 2031 if ((namelen = scf_myname(h, NULL, 0)) == -1) { 2032 if (local_h) 2033 scf_handle_destroy(h); 2034 return (NULL); 2035 } 2036 if ((sys_fmri = malloc(namelen + 1)) == NULL) { 2037 if (local_h) 2038 scf_handle_destroy(h); 2039 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2040 return (NULL); 2041 } 2042 if (scf_myname(h, sys_fmri, namelen + 1) == -1) { 2043 if (local_h) 2044 scf_handle_destroy(h); 2045 free(sys_fmri); 2046 return (NULL); 2047 } 2048 } else { 2049 if ((sys_fmri = strdup(inst_fmri)) == NULL) { 2050 if (local_h) 2051 scf_handle_destroy(h); 2052 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2053 return (NULL); 2054 } 2055 } 2056 2057 namelen = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1; 2058 assert(namelen > 0); 2059 2060 if ((inst = scf_instance_create(h)) == NULL || 2061 (svc = scf_service_create(h)) == NULL || 2062 (pgiter = scf_iter_create(h)) == NULL || 2063 (propiter = scf_iter_create(h)) == NULL || 2064 (pg = scf_pg_create(h)) == NULL || 2065 (prop = scf_property_create(h)) == NULL) { 2066 free(sys_fmri); 2067 goto error2; 2068 } 2069 2070 if (scf_handle_decode_fmri(h, sys_fmri, NULL, svc, inst, NULL, NULL, 2071 SCF_DECODE_FMRI_REQUIRE_INSTANCE) == -1) { 2072 free(sys_fmri); 2073 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) 2074 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 2075 goto error2; 2076 } 2077 2078 if ((ret = malloc(sizeof (*ret))) == NULL || 2079 (thispg = malloc(sizeof (*thispg))) == NULL || 2080 (propname = malloc(namelen)) == NULL || 2081 (pgname = malloc(namelen)) == NULL) { 2082 free(thispg); 2083 free(ret); 2084 free(sys_fmri); 2085 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2086 goto error2; 2087 } 2088 2089 ret->ap_fmri = sys_fmri; 2090 thispg->pg_name = NULL; 2091 thispg->pg_proplist = NULL; 2092 thispg->pg_next = NULL; 2093 ret->ap_pglist = thispg; 2094 2095 if (scf_iter_service_pgs_typed(pgiter, svc, SCF_GROUP_APPLICATION) != 2096 0) { 2097 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 2098 (void) scf_set_error(SCF_ERROR_INTERNAL); 2099 goto error1; 2100 } 2101 2102 while ((pgiter_ret = scf_iter_next_pg(pgiter, pg)) == 1) { 2103 if (thispg->pg_name != NULL) { 2104 if ((nextpg = malloc(sizeof (*nextpg))) == NULL) { 2105 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2106 goto error1; 2107 } 2108 nextpg->pg_name = NULL; 2109 nextpg->pg_next = NULL; 2110 nextpg->pg_proplist = NULL; 2111 thispg->pg_next = nextpg; 2112 thispg = nextpg; 2113 } else { 2114 /* This is the first iteration */ 2115 nextpg = thispg; 2116 } 2117 2118 if ((nextpg->pg_name = malloc(namelen)) == NULL) { 2119 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2120 goto error1; 2121 } 2122 2123 if (scf_pg_get_name(pg, nextpg->pg_name, namelen) < 0) { 2124 if (scf_error() == SCF_ERROR_NOT_SET) 2125 (void) scf_set_error(SCF_ERROR_INTERNAL); 2126 goto error1; 2127 } 2128 2129 thisprop = NULL; 2130 2131 scf_iter_reset(propiter); 2132 2133 if (scf_iter_pg_properties(propiter, pg) != 0) { 2134 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 2135 (void) scf_set_error(SCF_ERROR_INTERNAL); 2136 goto error1; 2137 } 2138 2139 while ((propiter_ret = scf_iter_next_property(propiter, prop)) 2140 == 1) { 2141 if (scf_property_get_name(prop, propname, namelen) < 2142 0) { 2143 if (scf_error() == SCF_ERROR_NOT_SET) 2144 (void) scf_set_error( 2145 SCF_ERROR_INTERNAL); 2146 goto error1; 2147 } 2148 if (thisprop != NULL) { 2149 if ((nextprop = fill_prop(prop, 2150 nextpg->pg_name, propname, h)) == NULL) 2151 goto error1; 2152 thisprop->pr_next = nextprop; 2153 thisprop = nextprop; 2154 } else { 2155 /* This is the first iteration */ 2156 if ((thisprop = fill_prop(prop, 2157 nextpg->pg_name, propname, h)) == NULL) 2158 goto error1; 2159 nextpg->pg_proplist = thisprop; 2160 nextprop = thisprop; 2161 } 2162 nextprop->pr_pg = nextpg; 2163 nextprop->pr_next = NULL; 2164 } 2165 2166 if (propiter_ret == -1) { 2167 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 2168 (void) scf_set_error(SCF_ERROR_INTERNAL); 2169 goto error1; 2170 } 2171 } 2172 2173 if (pgiter_ret == -1) { 2174 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 2175 (void) scf_set_error(SCF_ERROR_INTERNAL); 2176 goto error1; 2177 } 2178 2179 /* 2180 * At this point, we've filled the scf_simple_app_props_t with all the 2181 * properties at the service level. Now we iterate over all the 2182 * properties at the instance level, overwriting any duplicate 2183 * properties, in order to provide service/instance composition. 2184 */ 2185 2186 scf_iter_reset(pgiter); 2187 scf_iter_reset(propiter); 2188 2189 if (scf_iter_instance_pgs_typed(pgiter, inst, SCF_GROUP_APPLICATION) 2190 != 0) { 2191 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 2192 (void) scf_set_error(SCF_ERROR_INTERNAL); 2193 goto error1; 2194 } 2195 2196 while ((pgiter_ret = scf_iter_next_pg(pgiter, pg)) == 1) { 2197 2198 thispg = ret->ap_pglist; 2199 found = 0; 2200 2201 /* 2202 * Find either the end of the list, so we can append the 2203 * property group, or an existing property group that matches 2204 * it, so we can insert/overwrite its properties. 2205 */ 2206 2207 if (scf_pg_get_name(pg, pgname, namelen) < 0) { 2208 if (scf_error() == SCF_ERROR_NOT_SET) 2209 (void) scf_set_error(SCF_ERROR_INTERNAL); 2210 goto error1; 2211 } 2212 2213 while ((thispg != NULL) && (thispg->pg_name != NULL)) { 2214 if (strcmp(thispg->pg_name, pgname) == 0) { 2215 found = 1; 2216 break; 2217 } 2218 if (thispg->pg_next == NULL) 2219 break; 2220 2221 thispg = thispg->pg_next; 2222 } 2223 2224 scf_iter_reset(propiter); 2225 2226 if (scf_iter_pg_properties(propiter, pg) != 0) { 2227 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 2228 (void) scf_set_error(SCF_ERROR_INTERNAL); 2229 goto error1; 2230 } 2231 2232 if (found) { 2233 /* 2234 * insert_app_props inserts or overwrites the 2235 * properties in thispg. 2236 */ 2237 2238 if (insert_app_props(propiter, pgname, propname, 2239 thispg, prop, namelen, h) == -1) 2240 goto error1; 2241 2242 } else { 2243 /* 2244 * If the property group wasn't found, we're adding 2245 * a newly allocated property group to the end of the 2246 * list. 2247 */ 2248 2249 if ((nextpg = malloc(sizeof (*nextpg))) == NULL) { 2250 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2251 goto error1; 2252 } 2253 nextpg->pg_next = NULL; 2254 nextpg->pg_proplist = NULL; 2255 thisprop = NULL; 2256 2257 if ((nextpg->pg_name = strdup(pgname)) == NULL) { 2258 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2259 free(nextpg); 2260 goto error1; 2261 } 2262 2263 if (thispg->pg_name == NULL) { 2264 free(thispg); 2265 ret->ap_pglist = nextpg; 2266 } else { 2267 thispg->pg_next = nextpg; 2268 } 2269 2270 while ((propiter_ret = 2271 scf_iter_next_property(propiter, prop)) == 1) { 2272 if (scf_property_get_name(prop, propname, 2273 namelen) < 0) { 2274 if (scf_error() == SCF_ERROR_NOT_SET) 2275 (void) scf_set_error( 2276 SCF_ERROR_INTERNAL); 2277 goto error1; 2278 } 2279 if (thisprop != NULL) { 2280 if ((nextprop = fill_prop(prop, 2281 pgname, propname, h)) == 2282 NULL) 2283 goto error1; 2284 thisprop->pr_next = nextprop; 2285 thisprop = nextprop; 2286 } else { 2287 /* This is the first iteration */ 2288 if ((thisprop = fill_prop(prop, 2289 pgname, propname, h)) == 2290 NULL) 2291 goto error1; 2292 nextpg->pg_proplist = thisprop; 2293 nextprop = thisprop; 2294 } 2295 nextprop->pr_pg = nextpg; 2296 nextprop->pr_next = NULL; 2297 } 2298 2299 if (propiter_ret == -1) { 2300 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 2301 (void) scf_set_error( 2302 SCF_ERROR_INTERNAL); 2303 goto error1; 2304 } 2305 } 2306 2307 } 2308 2309 if (pgiter_ret == -1) { 2310 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 2311 (void) scf_set_error(SCF_ERROR_INTERNAL); 2312 goto error1; 2313 } 2314 2315 if (ret->ap_pglist->pg_name == NULL) 2316 goto error1; 2317 2318 scf_iter_destroy(pgiter); 2319 scf_iter_destroy(propiter); 2320 scf_pg_destroy(pg); 2321 scf_property_destroy(prop); 2322 scf_instance_destroy(inst); 2323 scf_service_destroy(svc); 2324 free(propname); 2325 free(pgname); 2326 if (local_h) 2327 scf_handle_destroy(h); 2328 2329 return (ret); 2330 2331 /* 2332 * Exit point for a successful call. Below this line are exit points 2333 * for failures at various stages during the function. 2334 */ 2335 2336 error1: 2337 scf_simple_app_props_free(ret); 2338 2339 error2: 2340 scf_iter_destroy(pgiter); 2341 scf_iter_destroy(propiter); 2342 scf_pg_destroy(pg); 2343 scf_property_destroy(prop); 2344 scf_instance_destroy(inst); 2345 scf_service_destroy(svc); 2346 free(propname); 2347 free(pgname); 2348 if (local_h) 2349 scf_handle_destroy(h); 2350 return (NULL); 2351 } 2352 2353 2354 void 2355 scf_simple_app_props_free(scf_simple_app_props_t *propblock) 2356 { 2357 struct scf_simple_pg *pgthis, *pgnext; 2358 scf_simple_prop_t *propthis, *propnext; 2359 2360 if ((propblock == NULL) || (propblock->ap_pglist == NULL)) 2361 return; 2362 2363 for (pgthis = propblock->ap_pglist; pgthis != NULL; pgthis = pgnext) { 2364 pgnext = pgthis->pg_next; 2365 2366 propthis = pgthis->pg_proplist; 2367 2368 while (propthis != NULL) { 2369 propnext = propthis->pr_next; 2370 scf_simple_prop_free(propthis); 2371 propthis = propnext; 2372 } 2373 2374 free(pgthis->pg_name); 2375 free(pgthis); 2376 } 2377 2378 free(propblock->ap_fmri); 2379 free(propblock); 2380 } 2381 2382 const scf_simple_prop_t * 2383 scf_simple_app_props_next(const scf_simple_app_props_t *propblock, 2384 scf_simple_prop_t *last) 2385 { 2386 struct scf_simple_pg *this; 2387 2388 if (propblock == NULL) { 2389 (void) scf_set_error(SCF_ERROR_NOT_SET); 2390 return (NULL); 2391 } 2392 2393 this = propblock->ap_pglist; 2394 2395 /* 2396 * We're looking for the first property in this block if last is 2397 * NULL 2398 */ 2399 2400 if (last == NULL) { 2401 /* An empty pglist is legal, it just means no properties */ 2402 if (this == NULL) { 2403 (void) scf_set_error(SCF_ERROR_NONE); 2404 return (NULL); 2405 } 2406 /* 2407 * Walk until we find a pg with a property in it, or we run 2408 * out of property groups. 2409 */ 2410 while ((this->pg_proplist == NULL) && (this->pg_next != NULL)) 2411 this = this->pg_next; 2412 2413 if (this->pg_proplist == NULL) { 2414 (void) scf_set_error(SCF_ERROR_NONE); 2415 return (NULL); 2416 } 2417 2418 return (this->pg_proplist); 2419 2420 } 2421 /* 2422 * If last isn't NULL, then return the next prop in the property group, 2423 * or walk the property groups until we find another property, or 2424 * run out of property groups. 2425 */ 2426 if (last->pr_next != NULL) 2427 return (last->pr_next); 2428 2429 if (last->pr_pg->pg_next == NULL) { 2430 (void) scf_set_error(SCF_ERROR_NONE); 2431 return (NULL); 2432 } 2433 2434 this = last->pr_pg->pg_next; 2435 2436 while ((this->pg_proplist == NULL) && (this->pg_next != NULL)) 2437 this = this->pg_next; 2438 2439 if (this->pg_proplist == NULL) { 2440 (void) scf_set_error(SCF_ERROR_NONE); 2441 return (NULL); 2442 } 2443 2444 return (this->pg_proplist); 2445 } 2446 2447 const scf_simple_prop_t * 2448 scf_simple_app_props_search(const scf_simple_app_props_t *propblock, 2449 const char *pgname, const char *propname) 2450 { 2451 struct scf_simple_pg *pg; 2452 scf_simple_prop_t *prop; 2453 2454 if ((propblock == NULL) || (propname == NULL)) { 2455 (void) scf_set_error(SCF_ERROR_NOT_SET); 2456 return (NULL); 2457 } 2458 2459 pg = propblock->ap_pglist; 2460 2461 /* 2462 * If pgname is NULL, we're searching the default application 2463 * property group, otherwise we look for the specified group. 2464 */ 2465 if (pgname == NULL) { 2466 while ((pg != NULL) && 2467 (strcmp(SCF_PG_APP_DEFAULT, pg->pg_name) != 0)) 2468 pg = pg->pg_next; 2469 } else { 2470 while ((pg != NULL) && (strcmp(pgname, pg->pg_name) != 0)) 2471 pg = pg->pg_next; 2472 } 2473 2474 if (pg == NULL) { 2475 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 2476 return (NULL); 2477 } 2478 2479 prop = pg->pg_proplist; 2480 2481 while ((prop != NULL) && (strcmp(propname, prop->pr_propname) != 0)) 2482 prop = prop->pr_next; 2483 2484 if (prop == NULL) { 2485 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 2486 return (NULL); 2487 } 2488 2489 return (prop); 2490 } 2491 2492 void 2493 scf_simple_prop_next_reset(scf_simple_prop_t *prop) 2494 { 2495 if (prop == NULL) 2496 return; 2497 prop->pr_iter = 0; 2498 } 2499 2500 ssize_t 2501 scf_simple_prop_numvalues(const scf_simple_prop_t *prop) 2502 { 2503 if (prop == NULL) 2504 return (scf_set_error(SCF_ERROR_NOT_SET)); 2505 2506 return (prop->pr_numvalues); 2507 } 2508 2509 2510 scf_type_t 2511 scf_simple_prop_type(const scf_simple_prop_t *prop) 2512 { 2513 if (prop == NULL) 2514 return (scf_set_error(SCF_ERROR_NOT_SET)); 2515 2516 return (prop->pr_type); 2517 } 2518 2519 2520 char * 2521 scf_simple_prop_name(const scf_simple_prop_t *prop) 2522 { 2523 if ((prop == NULL) || (prop->pr_propname == NULL)) { 2524 (void) scf_set_error(SCF_ERROR_NOT_SET); 2525 return (NULL); 2526 } 2527 2528 return (prop->pr_propname); 2529 } 2530 2531 2532 char * 2533 scf_simple_prop_pgname(const scf_simple_prop_t *prop) 2534 { 2535 if ((prop == NULL) || (prop->pr_pgname == NULL)) { 2536 (void) scf_set_error(SCF_ERROR_NOT_SET); 2537 return (NULL); 2538 } 2539 2540 return (prop->pr_pgname); 2541 } 2542 2543 2544 static union scf_simple_prop_val * 2545 scf_next_val(scf_simple_prop_t *prop, scf_type_t type) 2546 { 2547 if (prop == NULL) { 2548 (void) scf_set_error(SCF_ERROR_NOT_SET); 2549 return (NULL); 2550 } 2551 2552 switch (prop->pr_type) { 2553 case SCF_TYPE_USTRING: 2554 case SCF_TYPE_HOST: 2555 case SCF_TYPE_HOSTNAME: 2556 case SCF_TYPE_NET_ADDR: 2557 case SCF_TYPE_NET_ADDR_V4: 2558 case SCF_TYPE_NET_ADDR_V6: 2559 case SCF_TYPE_URI: 2560 case SCF_TYPE_FMRI: { 2561 if (type != SCF_TYPE_USTRING) { 2562 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH); 2563 return (NULL); 2564 } 2565 break; 2566 } 2567 default: { 2568 if (type != prop->pr_type) { 2569 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH); 2570 return (NULL); 2571 } 2572 break; 2573 } 2574 } 2575 2576 if (prop->pr_iter >= prop->pr_numvalues) { 2577 (void) scf_set_error(SCF_ERROR_NONE); 2578 return (NULL); 2579 } 2580 2581 return (&prop->pr_vallist[prop->pr_iter++]); 2582 } 2583 2584 2585 uint8_t * 2586 scf_simple_prop_next_boolean(scf_simple_prop_t *prop) 2587 { 2588 union scf_simple_prop_val *ret; 2589 2590 ret = scf_next_val(prop, SCF_TYPE_BOOLEAN); 2591 2592 if (ret == NULL) 2593 return (NULL); 2594 2595 return (&ret->pv_bool); 2596 } 2597 2598 2599 uint64_t * 2600 scf_simple_prop_next_count(scf_simple_prop_t *prop) 2601 { 2602 union scf_simple_prop_val *ret; 2603 2604 ret = scf_next_val(prop, SCF_TYPE_COUNT); 2605 2606 if (ret == NULL) 2607 return (NULL); 2608 2609 return (&ret->pv_uint); 2610 } 2611 2612 2613 int64_t * 2614 scf_simple_prop_next_integer(scf_simple_prop_t *prop) 2615 { 2616 union scf_simple_prop_val *ret; 2617 2618 ret = scf_next_val(prop, SCF_TYPE_INTEGER); 2619 2620 if (ret == NULL) 2621 return (NULL); 2622 2623 return (&ret->pv_int); 2624 } 2625 2626 int64_t * 2627 scf_simple_prop_next_time(scf_simple_prop_t *prop, int32_t *nsec) 2628 { 2629 union scf_simple_prop_val *ret; 2630 2631 ret = scf_next_val(prop, SCF_TYPE_TIME); 2632 2633 if (ret == NULL) 2634 return (NULL); 2635 2636 if (nsec != NULL) 2637 *nsec = ret->pv_time.t_nsec; 2638 2639 return (&ret->pv_time.t_sec); 2640 } 2641 2642 char * 2643 scf_simple_prop_next_astring(scf_simple_prop_t *prop) 2644 { 2645 union scf_simple_prop_val *ret; 2646 2647 ret = scf_next_val(prop, SCF_TYPE_ASTRING); 2648 2649 if (ret == NULL) 2650 return (NULL); 2651 2652 return (ret->pv_str); 2653 } 2654 2655 char * 2656 scf_simple_prop_next_ustring(scf_simple_prop_t *prop) 2657 { 2658 union scf_simple_prop_val *ret; 2659 2660 ret = scf_next_val(prop, SCF_TYPE_USTRING); 2661 2662 if (ret == NULL) 2663 return (NULL); 2664 2665 return (ret->pv_str); 2666 } 2667 2668 void * 2669 scf_simple_prop_next_opaque(scf_simple_prop_t *prop, size_t *length) 2670 { 2671 union scf_simple_prop_val *ret; 2672 2673 ret = scf_next_val(prop, SCF_TYPE_OPAQUE); 2674 2675 if (ret == NULL) { 2676 *length = 0; 2677 return (NULL); 2678 } 2679 2680 *length = ret->pv_opaque.o_size; 2681 return (ret->pv_opaque.o_value); 2682 } 2683 2684 /* 2685 * Generate a filename based on the fmri and the given name and return 2686 * it in the buffer of MAXPATHLEN provided by the caller. 2687 * If temp_filename is non-zero, also generate a temporary, unique filename 2688 * and return it in the temp buffer of MAXPATHLEN provided by the caller. 2689 * The path to the generated pathname is also created. 2690 * Given fmri should begin with a scheme such as "svc:". 2691 * Returns 2692 * 0 on success 2693 * -1 if filename would exceed MAXPATHLEN or 2694 * -2 if unable to create directory to filename path 2695 */ 2696 int 2697 gen_filenms_from_fmri(const char *fmri, const char *name, char *filename, 2698 char *temp_filename) 2699 { 2700 int len; 2701 2702 len = strlen(SMF_SPEEDY_FILES_PATH); 2703 len += strlen(fmri); 2704 len += 2; /* for slash and null */ 2705 len += strlen(name); 2706 len += 6; /* For X's needed for mkstemp */ 2707 2708 if (len > MAXPATHLEN) 2709 return (-1); 2710 2711 /* Construct directory name first - speedy path ends in slash */ 2712 (void) strcpy(filename, SMF_SPEEDY_FILES_PATH); 2713 (void) strcat(filename, fmri); 2714 if (mkdirp(filename, 0755) == -1) { 2715 /* errno is set */ 2716 if (errno != EEXIST) 2717 return (-2); 2718 } 2719 2720 (void) strcat(filename, "/"); 2721 (void) strcat(filename, name); 2722 2723 if (temp_filename) { 2724 (void) strcpy(temp_filename, filename); 2725 (void) strcat(temp_filename, "XXXXXX"); 2726 } 2727 2728 return (0); 2729 } 2730 2731 scf_type_t 2732 scf_true_base_type(scf_type_t type) 2733 { 2734 scf_type_t base = type; 2735 2736 do { 2737 type = base; 2738 (void) scf_type_base_type(type, &base); 2739 } while (base != type); 2740 2741 return (base); 2742 } 2743 2744 /* 2745 * Convenience routine which frees all strings and opaque data 2746 * allocated by scf_read_propvec. 2747 * 2748 * Like free(3C), this function preserves the value of errno. 2749 */ 2750 void 2751 scf_clean_propvec(scf_propvec_t *propvec) 2752 { 2753 int saved_errno = errno; 2754 scf_propvec_t *prop; 2755 2756 for (prop = propvec; prop->pv_prop != NULL; prop++) { 2757 assert(prop->pv_type != SCF_TYPE_INVALID); 2758 if (prop->pv_type == SCF_TYPE_OPAQUE) { 2759 scf_opaque_t *o = prop->pv_ptr; 2760 2761 if (o->so_addr != NULL) 2762 free(o->so_addr); 2763 } else if (scf_true_base_type(prop->pv_type) == 2764 SCF_TYPE_ASTRING) { 2765 if (*(char **)prop->pv_ptr != NULL) 2766 free(*(char **)prop->pv_ptr); 2767 } 2768 } 2769 2770 errno = saved_errno; 2771 } 2772 2773 static int 2774 count_props(scf_propvec_t *props) 2775 { 2776 int count = 0; 2777 2778 for (; props->pv_prop != NULL; props++) 2779 count++; 2780 return (count); 2781 } 2782 2783 /* 2784 * Reads a vector of properties from the specified fmri/property group. 2785 * If 'running' is true, reads from the running snapshot instead of the 2786 * editing snapshot. 2787 * 2788 * For string types, a buffer is allocated using malloc(3C) to hold the 2789 * zero-terminated string, a pointer to which is stored in the 2790 * caller-provided char **. It is the caller's responsbility to free 2791 * this string. To simplify error handling, unread strings are 2792 * initialized to NULL. 2793 * 2794 * For opaque types, a buffer is allocated using malloc(3C) to hold the 2795 * opaque data. A pointer to this buffer and its size are stored in 2796 * the caller-provided scf_opaque_t. It is the caller's responsibility 2797 * to free this buffer. To simplify error handling, the address fields 2798 * for unread opaque data are initialized to NULL. 2799 * 2800 * All other data is stored directly in caller-provided variables or 2801 * structures. 2802 * 2803 * If this function fails to read a specific property, *badprop is set 2804 * to point at that property's entry in the properties array. 2805 * 2806 * On all failures, all memory allocated by this function is freed. 2807 */ 2808 int 2809 scf_read_propvec(const char *fmri, const char *pgname, boolean_t running, 2810 scf_propvec_t *properties, scf_propvec_t **badprop) 2811 { 2812 scf_handle_t *h = _scf_handle_create_and_bind(SCF_VERSION); 2813 scf_service_t *s = scf_service_create(h); 2814 scf_instance_t *i = scf_instance_create(h); 2815 scf_snapshot_t *snap = running ? scf_snapshot_create(h) : NULL; 2816 scf_propertygroup_t *pg = scf_pg_create(h); 2817 scf_property_t *p = scf_property_create(h); 2818 scf_value_t *v = scf_value_create(h); 2819 boolean_t instance = B_TRUE; 2820 scf_propvec_t *prop; 2821 int error = 0; 2822 2823 for (prop = properties; prop->pv_prop != NULL; prop++) { 2824 if (prop->pv_type == SCF_TYPE_OPAQUE) 2825 ((scf_opaque_t *)prop->pv_ptr)->so_addr = NULL; 2826 else if (scf_true_base_type(prop->pv_type) == SCF_TYPE_ASTRING) 2827 *((char **)prop->pv_ptr) = NULL; 2828 } 2829 2830 if (h == NULL || s == NULL || i == NULL || (running && snap == NULL) || 2831 pg == NULL || p == NULL || v == NULL) 2832 goto scferror; 2833 2834 if (scf_handle_decode_fmri(h, fmri, NULL, s, i, NULL, NULL, 0) == -1) 2835 goto scferror; 2836 2837 if (scf_instance_to_fmri(i, NULL, 0) == -1) { 2838 if (scf_error() != SCF_ERROR_NOT_SET) 2839 goto scferror; 2840 instance = B_FALSE; 2841 } 2842 2843 if (running) { 2844 if (!instance) { 2845 error = SCF_ERROR_TYPE_MISMATCH; 2846 goto out; 2847 } 2848 2849 if (scf_instance_get_snapshot(i, "running", snap) != 2850 SCF_SUCCESS) 2851 goto scferror; 2852 } 2853 2854 if ((instance ? scf_instance_get_pg_composed(i, snap, pgname, pg) : 2855 scf_service_get_pg(s, pgname, pg)) == -1) 2856 goto scferror; 2857 2858 for (prop = properties; prop->pv_prop != NULL; prop++) { 2859 int ret = 0; 2860 2861 if (scf_pg_get_property(pg, prop->pv_prop, p) == -1 || 2862 scf_property_get_value(p, v) == -1) { 2863 *badprop = prop; 2864 goto scferror; 2865 } 2866 switch (prop->pv_type) { 2867 case SCF_TYPE_BOOLEAN: { 2868 uint8_t b; 2869 2870 ret = scf_value_get_boolean(v, &b); 2871 if (ret == -1) 2872 break; 2873 if (prop->pv_aux != 0) { 2874 uint64_t *bits = prop->pv_ptr; 2875 *bits = b ? (*bits | prop->pv_aux) : 2876 (*bits & ~prop->pv_aux); 2877 } else { 2878 boolean_t *bool = prop->pv_ptr; 2879 *bool = b ? B_TRUE : B_FALSE; 2880 } 2881 break; 2882 } 2883 case SCF_TYPE_COUNT: 2884 ret = scf_value_get_count(v, prop->pv_ptr); 2885 break; 2886 case SCF_TYPE_INTEGER: 2887 ret = scf_value_get_integer(v, prop->pv_ptr); 2888 break; 2889 case SCF_TYPE_TIME: { 2890 scf_time_t *time = prop->pv_ptr; 2891 2892 ret = scf_value_get_time(v, &time->t_seconds, 2893 &time->t_ns); 2894 break; 2895 } 2896 case SCF_TYPE_OPAQUE: { 2897 scf_opaque_t *opaque = prop->pv_ptr; 2898 ssize_t size = scf_value_get_opaque(v, NULL, 0); 2899 2900 if (size == -1) { 2901 *badprop = prop; 2902 goto scferror; 2903 } 2904 if ((opaque->so_addr = malloc(size)) == NULL) { 2905 error = SCF_ERROR_NO_MEMORY; 2906 goto out; 2907 } 2908 opaque->so_size = size; 2909 ret = scf_value_get_opaque(v, opaque->so_addr, size); 2910 break; 2911 } 2912 default: { 2913 char *s; 2914 ssize_t size; 2915 2916 assert(scf_true_base_type(prop->pv_type) == 2917 SCF_TYPE_ASTRING); 2918 2919 size = scf_value_get_astring(v, NULL, 0); 2920 if (size == -1) { 2921 *badprop = prop; 2922 goto scferror; 2923 } 2924 if ((s = malloc(++size)) == NULL) { 2925 error = SCF_ERROR_NO_MEMORY; 2926 goto out; 2927 } 2928 ret = scf_value_get_astring(v, s, size); 2929 *(char **)prop->pv_ptr = s; 2930 } 2931 2932 if (ret == -1) { 2933 *badprop = prop; 2934 goto scferror; 2935 } 2936 2937 } 2938 } 2939 2940 goto out; 2941 2942 scferror: 2943 error = scf_error(); 2944 scf_clean_propvec(properties); 2945 2946 out: 2947 scf_value_destroy(v); 2948 scf_property_destroy(p); 2949 scf_pg_destroy(pg); 2950 scf_snapshot_destroy(snap); 2951 scf_instance_destroy(i); 2952 scf_service_destroy(s); 2953 scf_handle_destroy(h); 2954 2955 if (error != 0) { 2956 (void) scf_set_error(error); 2957 return (SCF_FAILED); 2958 } 2959 2960 return (SCF_SUCCESS); 2961 } 2962 2963 /* 2964 * Writes a vector of properties to the specified fmri/property group. 2965 * 2966 * If this function fails to write a specific property, *badprop is set 2967 * to point at that property's entry in the properties array. 2968 * 2969 * One significant difference between this function and the 2970 * scf_read_propvec function is that for string types, pv_ptr is a 2971 * char *, not a char **. This means that you can't write a propvec 2972 * you just read, but makes other uses (hopefully the majority) simpler. 2973 */ 2974 int 2975 scf_write_propvec(const char *fmri, const char *pgname, 2976 scf_propvec_t *properties, scf_propvec_t **badprop) 2977 { 2978 scf_handle_t *h = _scf_handle_create_and_bind(SCF_VERSION); 2979 scf_service_t *s = scf_service_create(h); 2980 scf_instance_t *inst = scf_instance_create(h); 2981 scf_snapshot_t *snap = scf_snapshot_create(h); 2982 scf_propertygroup_t *pg = scf_pg_create(h); 2983 scf_property_t *p = scf_property_create(h); 2984 scf_transaction_t *tx = scf_transaction_create(h); 2985 scf_value_t **v = NULL; 2986 scf_transaction_entry_t **e = NULL; 2987 boolean_t instance = B_TRUE; 2988 int i, n; 2989 scf_propvec_t *prop; 2990 int error = 0, ret; 2991 2992 n = count_props(properties); 2993 v = calloc(n, sizeof (scf_value_t *)); 2994 e = calloc(n, sizeof (scf_transaction_entry_t *)); 2995 2996 if (v == NULL || e == NULL) { 2997 error = SCF_ERROR_NO_MEMORY; 2998 goto out; 2999 } 3000 3001 if (h == NULL || s == NULL || inst == NULL || pg == NULL || p == NULL || 3002 tx == NULL) 3003 goto scferror; 3004 3005 for (i = 0; i < n; i++) { 3006 v[i] = scf_value_create(h); 3007 e[i] = scf_entry_create(h); 3008 if (v[i] == NULL || e[i] == NULL) 3009 goto scferror; 3010 } 3011 3012 if (scf_handle_decode_fmri(h, fmri, NULL, s, inst, NULL, NULL, 0) 3013 != SCF_SUCCESS) 3014 goto scferror; 3015 3016 if (scf_instance_to_fmri(inst, NULL, 0) == -1) { 3017 if (scf_error() != SCF_ERROR_NOT_SET) 3018 goto scferror; 3019 instance = B_FALSE; 3020 } 3021 3022 if ((instance ? scf_instance_get_pg(inst, pgname, pg) : 3023 scf_service_get_pg(s, pgname, pg)) == -1) 3024 goto scferror; 3025 3026 top: 3027 if (scf_transaction_start(tx, pg) == -1) 3028 goto scferror; 3029 3030 for (prop = properties, i = 0; prop->pv_prop != NULL; prop++, i++) { 3031 ret = scf_transaction_property_change(tx, e[i], prop->pv_prop, 3032 prop->pv_type); 3033 if (ret == -1 && scf_error() == SCF_ERROR_NOT_FOUND) 3034 ret = scf_transaction_property_new(tx, e[i], 3035 prop->pv_prop, prop->pv_type); 3036 3037 if (ret == -1) { 3038 *badprop = prop; 3039 goto scferror; 3040 } 3041 3042 switch (prop->pv_type) { 3043 case SCF_TYPE_BOOLEAN: { 3044 boolean_t b = (prop->pv_aux != 0) ? 3045 (*(uint64_t *)prop->pv_ptr & prop->pv_aux) != 0 : 3046 *(boolean_t *)prop->pv_ptr; 3047 3048 scf_value_set_boolean(v[i], b ? 1 : 0); 3049 break; 3050 } 3051 case SCF_TYPE_COUNT: 3052 scf_value_set_count(v[i], *(uint64_t *)prop->pv_ptr); 3053 break; 3054 case SCF_TYPE_INTEGER: 3055 scf_value_set_integer(v[i], *(int64_t *)prop->pv_ptr); 3056 break; 3057 case SCF_TYPE_TIME: { 3058 scf_time_t *time = prop->pv_ptr; 3059 3060 ret = scf_value_set_time(v[i], time->t_seconds, 3061 time->t_ns); 3062 break; 3063 } 3064 case SCF_TYPE_OPAQUE: { 3065 scf_opaque_t *opaque = prop->pv_ptr; 3066 3067 ret = scf_value_set_opaque(v[i], opaque->so_addr, 3068 opaque->so_size); 3069 break; 3070 } 3071 case SCF_TYPE_ASTRING: 3072 ret = scf_value_set_astring(v[i], 3073 (const char *)prop->pv_ptr); 3074 break; 3075 default: 3076 ret = scf_value_set_from_string(v[i], prop->pv_type, 3077 (const char *)prop->pv_ptr); 3078 } 3079 3080 if (ret == -1 || scf_entry_add_value(e[i], v[i]) == -1) { 3081 *badprop = prop; 3082 goto scferror; 3083 } 3084 } 3085 3086 ret = scf_transaction_commit(tx); 3087 if (ret == 1) 3088 goto out; 3089 3090 if (ret == 0 && scf_pg_update(pg) != -1) { 3091 scf_transaction_reset(tx); 3092 goto top; 3093 } 3094 3095 scferror: 3096 error = scf_error(); 3097 3098 out: 3099 if (v != NULL) { 3100 for (i = 0; i < n; i++) 3101 scf_value_destroy(v[i]); 3102 free(v); 3103 } 3104 3105 if (e != NULL) { 3106 for (i = 0; i < n; i++) 3107 scf_entry_destroy(e[i]); 3108 free(e); 3109 } 3110 3111 scf_transaction_destroy(tx); 3112 scf_property_destroy(p); 3113 scf_pg_destroy(pg); 3114 scf_snapshot_destroy(snap); 3115 scf_instance_destroy(inst); 3116 scf_service_destroy(s); 3117 scf_handle_destroy(h); 3118 3119 if (error != 0) { 3120 (void) scf_set_error(error); 3121 return (SCF_FAILED); 3122 } 3123 3124 return (SCF_SUCCESS); 3125 } 3126 3127 /* 3128 * Returns 3129 * 0 - success 3130 * ECONNABORTED - repository connection broken 3131 * ECANCELED - inst was deleted 3132 * EPERM 3133 * EACCES 3134 * EROFS 3135 * ENOMEM 3136 */ 3137 int 3138 scf_instance_delete_prop(scf_instance_t *inst, const char *pgname, 3139 const char *pname) 3140 { 3141 scf_handle_t *h; 3142 scf_propertygroup_t *pg; 3143 scf_transaction_t *tx; 3144 scf_transaction_entry_t *e; 3145 int error = 0, ret = 1, r; 3146 3147 h = scf_instance_handle(inst); 3148 3149 if ((pg = scf_pg_create(h)) == NULL) { 3150 return (ENOMEM); 3151 } 3152 3153 if (scf_instance_get_pg(inst, pgname, pg) != 0) { 3154 error = scf_error(); 3155 scf_pg_destroy(pg); 3156 switch (error) { 3157 case SCF_ERROR_NOT_FOUND: 3158 return (SCF_SUCCESS); 3159 3160 case SCF_ERROR_DELETED: 3161 return (ECANCELED); 3162 3163 case SCF_ERROR_CONNECTION_BROKEN: 3164 default: 3165 return (ECONNABORTED); 3166 3167 case SCF_ERROR_NOT_SET: 3168 bad_error("scf_instance_get_pg", scf_error()); 3169 } 3170 } 3171 3172 tx = scf_transaction_create(h); 3173 e = scf_entry_create(h); 3174 if (tx == NULL || e == NULL) { 3175 ret = ENOMEM; 3176 goto out; 3177 } 3178 3179 for (;;) { 3180 if (scf_transaction_start(tx, pg) != 0) { 3181 goto scferror; 3182 } 3183 3184 if (scf_transaction_property_delete(tx, e, pname) != 0) { 3185 goto scferror; 3186 } 3187 3188 if ((r = scf_transaction_commit(tx)) == 1) { 3189 ret = 0; 3190 goto out; 3191 } 3192 3193 if (r == -1) { 3194 goto scferror; 3195 } 3196 3197 scf_transaction_reset(tx); 3198 if (scf_pg_update(pg) == -1) { 3199 goto scferror; 3200 } 3201 } 3202 3203 scferror: 3204 switch (scf_error()) { 3205 case SCF_ERROR_DELETED: 3206 case SCF_ERROR_NOT_FOUND: 3207 ret = 0; 3208 break; 3209 3210 case SCF_ERROR_PERMISSION_DENIED: 3211 ret = EPERM; 3212 break; 3213 3214 case SCF_ERROR_BACKEND_ACCESS: 3215 ret = EACCES; 3216 break; 3217 3218 case SCF_ERROR_BACKEND_READONLY: 3219 ret = EROFS; 3220 break; 3221 3222 case SCF_ERROR_CONNECTION_BROKEN: 3223 default: 3224 ret = ECONNABORTED; 3225 break; 3226 3227 case SCF_ERROR_HANDLE_MISMATCH: 3228 case SCF_ERROR_INVALID_ARGUMENT: 3229 case SCF_ERROR_NOT_BOUND: 3230 case SCF_ERROR_NOT_SET: 3231 bad_error("scf_instance_delete_prop", scf_error()); 3232 } 3233 3234 out: 3235 scf_transaction_destroy(tx); 3236 scf_entry_destroy(e); 3237 scf_pg_destroy(pg); 3238 3239 return (ret); 3240 } 3241 3242 /* 3243 * Check the "application/auto_enable" property for the passed FMRI. 3244 * scf_simple_prop_get() should find the property on an instance 3245 * or on the service FMRI. The routine returns: 3246 * -1: inconclusive (likely no such property or FMRI) 3247 * 0: auto_enable is false 3248 * 1: auto_enable is true 3249 */ 3250 static int 3251 is_auto_enabled(char *fmri) 3252 { 3253 scf_simple_prop_t *prop; 3254 int retval = -1; 3255 uint8_t *ret; 3256 3257 prop = scf_simple_prop_get(NULL, fmri, SCF_GROUP_APPLICATION, 3258 "auto_enable"); 3259 if (!prop) 3260 return (retval); 3261 ret = scf_simple_prop_next_boolean(prop); 3262 retval = (*ret != 0); 3263 scf_simple_prop_free(prop); 3264 return (retval); 3265 } 3266 3267 /* 3268 * Check an array of services and enable any that don't have the 3269 * "application/auto_enable" property set to "false", which is 3270 * the interface to turn off this behaviour (see PSARC 2004/739). 3271 */ 3272 void 3273 _check_services(char **svcs) 3274 { 3275 char *s; 3276 3277 for (; *svcs; svcs++) { 3278 if (is_auto_enabled(*svcs) == 0) 3279 continue; 3280 if ((s = smf_get_state(*svcs)) != NULL) { 3281 if (strcmp(SCF_STATE_STRING_DISABLED, s) == 0) 3282 (void) smf_enable_instance(*svcs, 3283 SMF_TEMPORARY); 3284 free(s); 3285 } 3286 } 3287 } 3288 3289 /*ARGSUSED*/ 3290 static int 3291 str_compare(const char *s1, const char *s2, size_t n) 3292 { 3293 return (strcmp(s1, s2)); 3294 } 3295 3296 static int 3297 str_n_compare(const char *s1, const char *s2, size_t n) 3298 { 3299 return (strncmp(s1, s2, n)); 3300 } 3301 3302 int32_t 3303 state_from_string(const char *state, size_t l) 3304 { 3305 int (*str_cmp)(const char *, const char *, size_t); 3306 3307 if (l == 0) 3308 str_cmp = str_compare; 3309 else 3310 str_cmp = str_n_compare; 3311 3312 if (str_cmp(SCF_STATE_STRING_UNINIT, state, l) == 0) 3313 return (SCF_STATE_UNINIT); 3314 else if (str_cmp(SCF_STATE_STRING_MAINT, state, l) == 0) 3315 return (SCF_STATE_MAINT); 3316 else if (str_cmp(SCF_STATE_STRING_OFFLINE, state, l) == 0) 3317 return (SCF_STATE_OFFLINE); 3318 else if (str_cmp(SCF_STATE_STRING_DISABLED, state, l) == 0) 3319 return (SCF_STATE_DISABLED); 3320 else if (str_cmp(SCF_STATE_STRING_ONLINE, state, l) == 0) 3321 return (SCF_STATE_ONLINE); 3322 else if (str_cmp(SCF_STATE_STRING_DEGRADED, state, l) == 0) 3323 return (SCF_STATE_DEGRADED); 3324 else if (str_cmp("all", state, l) == 0) 3325 return (SCF_STATE_ALL); 3326 else 3327 return (-1); 3328 } 3329 3330 /* 3331 * int32_t smf_state_from_string() 3332 * return the value of the macro SCF_STATE_* for the corresponding state 3333 * it returns SCF_STATE_ALL if "all" is passed. -1 if the string passed doesn't 3334 * correspond to any valid state. 3335 */ 3336 int32_t 3337 smf_state_from_string(const char *state) 3338 { 3339 return (state_from_string(state, 0)); 3340 } 3341 3342 /* 3343 * smf_state_to_string() 3344 * Takes an int32_t representing an SMF state and returns 3345 * the corresponding string. The string is read only and need not to be 3346 * freed. 3347 * returns NULL on invalid input. 3348 */ 3349 const char * 3350 smf_state_to_string(int32_t s) 3351 { 3352 switch (s) { 3353 case SCF_STATE_UNINIT: 3354 return (SCF_STATE_STRING_UNINIT); 3355 case SCF_STATE_MAINT: 3356 return (SCF_STATE_STRING_MAINT); 3357 case SCF_STATE_OFFLINE: 3358 return (SCF_STATE_STRING_OFFLINE); 3359 case SCF_STATE_DISABLED: 3360 return (SCF_STATE_STRING_DISABLED); 3361 case SCF_STATE_ONLINE: 3362 return (SCF_STATE_STRING_ONLINE); 3363 case SCF_STATE_DEGRADED: 3364 return (SCF_STATE_STRING_DEGRADED); 3365 case SCF_STATE_ALL: 3366 return ("all"); 3367 default: 3368 return (NULL); 3369 } 3370 } 3371