1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/contract/process.h> 30 #include <assert.h> 31 #include <errno.h> 32 #include <libscf.h> 33 #include <libscf_priv.h> 34 #include <poll.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <unistd.h> 38 39 #include "startd.h" 40 41 #define SMF_SNAPSHOT_RUNNING "running" 42 43 char * 44 inst_fmri_to_svc_fmri(const char *fmri) 45 { 46 char *buf, *sfmri; 47 const char *scope, *svc; 48 int r; 49 boolean_t local; 50 51 buf = startd_alloc(max_scf_fmri_size); 52 sfmri = startd_alloc(max_scf_fmri_size); 53 54 (void) strcpy(buf, fmri); 55 56 r = scf_parse_svc_fmri(buf, &scope, &svc, NULL, NULL, NULL); 57 assert(r == 0); 58 59 local = strcmp(scope, SCF_SCOPE_LOCAL) == 0; 60 61 (void) snprintf(sfmri, max_scf_fmri_size, "svc:%s%s/%s", 62 local ? "" : "//", local ? "" : scope, svc); 63 64 startd_free(buf, max_scf_fmri_size); 65 66 return (sfmri); 67 } 68 69 /* 70 * Wrapper for the scf_*_create() functions. On SCF_ERROR_NO_MEMORY and 71 * SCF_ERROR_NO_RESOURCES, retries or dies. So this can only fail with 72 * SCF_ERROR_INVALID_ARGUMENT, if h is NULL. 73 */ 74 void * 75 libscf_object_create(void *f(scf_handle_t *), scf_handle_t *h) 76 { 77 void *o; 78 uint_t try, msecs; 79 scf_error_t err; 80 81 o = f(h); 82 if (o != NULL) 83 return (o); 84 err = scf_error(); 85 if (err != SCF_ERROR_NO_MEMORY && err != SCF_ERROR_NO_RESOURCES) 86 return (NULL); 87 88 msecs = ALLOC_DELAY; 89 90 for (try = 0; try < ALLOC_RETRY; ++try) { 91 (void) poll(NULL, 0, msecs); 92 msecs *= ALLOC_DELAY_MULT; 93 o = f(h); 94 if (o != NULL) 95 return (o); 96 err = scf_error(); 97 if (err != SCF_ERROR_NO_MEMORY && err != SCF_ERROR_NO_RESOURCES) 98 return (NULL); 99 } 100 101 uu_die("Insufficient memory.\n"); 102 /* NOTREACHED */ 103 } 104 105 scf_snapshot_t * 106 libscf_get_running_snapshot(scf_instance_t *inst) 107 { 108 scf_handle_t *h; 109 scf_snapshot_t *snap; 110 111 h = scf_instance_handle(inst); 112 if (h == NULL) 113 return (NULL); 114 115 snap = scf_snapshot_create(h); 116 if (snap == NULL) 117 return (NULL); 118 119 if (scf_instance_get_snapshot(inst, SMF_SNAPSHOT_RUNNING, snap) == 0) 120 return (snap); 121 122 scf_snapshot_destroy(snap); 123 return (NULL); 124 } 125 126 /* 127 * Make sure a service has a "running" snapshot. If it doesn't, make one from 128 * the editing configuration. 129 */ 130 scf_snapshot_t * 131 libscf_get_or_make_running_snapshot(scf_instance_t *inst, const char *fmri, 132 boolean_t retake) 133 { 134 scf_handle_t *h; 135 scf_snapshot_t *snap; 136 137 h = scf_instance_handle(inst); 138 139 snap = scf_snapshot_create(h); 140 if (snap == NULL) 141 goto err; 142 143 if (scf_instance_get_snapshot(inst, SMF_SNAPSHOT_RUNNING, snap) == 0) 144 return (snap); 145 146 switch (scf_error()) { 147 case SCF_ERROR_NOT_FOUND: 148 break; 149 150 case SCF_ERROR_DELETED: 151 scf_snapshot_destroy(snap); 152 return (NULL); 153 154 default: 155 err: 156 log_error(LOG_NOTICE, 157 "Could not check for running snapshot of %s (%s).\n", fmri, 158 scf_strerror(scf_error())); 159 scf_snapshot_destroy(snap); 160 return (NULL); 161 } 162 163 if (_scf_snapshot_take_new(inst, SMF_SNAPSHOT_RUNNING, snap) == 0) { 164 log_framework(LOG_DEBUG, "Took running snapshot for %s.\n", 165 fmri); 166 } else { 167 if (retake && scf_error() == SCF_ERROR_BACKEND_READONLY) 168 restarter_mark_pending_snapshot(fmri, 169 RINST_RETAKE_RUNNING); 170 else 171 log_error(LOG_DEBUG, 172 "Could not create running snapshot for %s " 173 "(%s).\n", fmri, scf_strerror(scf_error())); 174 175 scf_snapshot_destroy(snap); 176 snap = NULL; 177 } 178 179 return (snap); 180 } 181 182 /* 183 * When a service comes up, point the "start" snapshot at the "running" 184 * snapshot. Returns 0 on success, ENOTSUP if fmri designates something other 185 * than an instance, ECONNABORTED, ENOENT if the instance does not exist, or 186 * EACCES. 187 */ 188 int 189 libscf_snapshots_poststart(scf_handle_t *h, const char *fmri, boolean_t retake) 190 { 191 scf_instance_t *inst = NULL; 192 scf_snapshot_t *running, *start = NULL; 193 int ret = 0, r; 194 195 r = libscf_fmri_get_instance(h, fmri, &inst); 196 switch (r) { 197 case 0: 198 break; 199 200 case ENOTSUP: 201 case ECONNABORTED: 202 case ENOENT: 203 return (r); 204 205 case EINVAL: 206 default: 207 assert(0); 208 abort(); 209 } 210 211 start = safe_scf_snapshot_create(h); 212 213 again: 214 running = libscf_get_or_make_running_snapshot(inst, fmri, retake); 215 if (running == NULL) { 216 ret = 0; 217 goto out; 218 } 219 220 lookup: 221 if (scf_instance_get_snapshot(inst, "start", start) != 0) { 222 switch (scf_error()) { 223 case SCF_ERROR_CONNECTION_BROKEN: 224 default: 225 ret = ECONNABORTED; 226 goto out; 227 228 case SCF_ERROR_NOT_FOUND: 229 if (_scf_snapshot_take_new(inst, "start", start) != 0) { 230 switch (scf_error()) { 231 case SCF_ERROR_CONNECTION_BROKEN: 232 default: 233 ret = ECONNABORTED; 234 goto out; 235 236 case SCF_ERROR_DELETED: 237 ret = ENOENT; 238 goto out; 239 240 case SCF_ERROR_EXISTS: 241 goto lookup; 242 243 case SCF_ERROR_NO_RESOURCES: 244 uu_die("Repository server out of " 245 "resources.\n"); 246 /* NOTREACHED */ 247 248 case SCF_ERROR_BACKEND_READONLY: 249 goto readonly; 250 251 case SCF_ERROR_PERMISSION_DENIED: 252 uu_die("Insufficient privileges.\n"); 253 /* NOTREACHED */ 254 255 case SCF_ERROR_BACKEND_ACCESS: 256 ret = EACCES; 257 goto out; 258 259 case SCF_ERROR_HANDLE_MISMATCH: 260 case SCF_ERROR_INVALID_ARGUMENT: 261 case SCF_ERROR_NOT_SET: 262 bad_error("_scf_snapshot_take_new", 263 scf_error()); 264 } 265 } 266 break; 267 268 case SCF_ERROR_DELETED: 269 ret = ENOENT; 270 goto out; 271 272 case SCF_ERROR_HANDLE_MISMATCH: 273 case SCF_ERROR_NOT_SET: 274 case SCF_ERROR_INVALID_ARGUMENT: 275 bad_error("scf_instance_get_snapshot", scf_error()); 276 } 277 } 278 279 if (_scf_snapshot_attach(running, start) == 0) { 280 log_framework(LOG_DEBUG, "Updated \"start\" snapshot for %s.\n", 281 fmri); 282 } else { 283 switch (scf_error()) { 284 case SCF_ERROR_CONNECTION_BROKEN: 285 default: 286 ret = ECONNABORTED; 287 goto out; 288 289 case SCF_ERROR_DELETED: 290 scf_snapshot_destroy(running); 291 goto again; 292 293 case SCF_ERROR_NO_RESOURCES: 294 uu_die("Repository server out of resources.\n"); 295 /* NOTREACHED */ 296 297 case SCF_ERROR_PERMISSION_DENIED: 298 uu_die("Insufficient privileges.\n"); 299 /* NOTREACHED */ 300 301 case SCF_ERROR_BACKEND_ACCESS: 302 ret = EACCES; 303 goto out; 304 305 case SCF_ERROR_BACKEND_READONLY: 306 readonly: 307 if (retake) 308 restarter_mark_pending_snapshot(fmri, 309 RINST_RETAKE_START); 310 break; 311 312 case SCF_ERROR_HANDLE_MISMATCH: 313 case SCF_ERROR_NOT_SET: 314 bad_error("_scf_snapshot_attach", scf_error()); 315 } 316 } 317 318 out: 319 scf_snapshot_destroy(start); 320 scf_snapshot_destroy(running); 321 scf_instance_destroy(inst); 322 323 return (ret); 324 } 325 326 /* 327 * Before a refresh, update the "running" snapshot from the editing 328 * configuration. 329 * 330 * Returns 0 on success and -1 on failure. 331 */ 332 int 333 libscf_snapshots_refresh(scf_instance_t *inst, const char *fmri) 334 { 335 scf_handle_t *h; 336 scf_snapshot_t *snap; 337 boolean_t err = 1; 338 339 h = scf_instance_handle(inst); 340 if (h == NULL) 341 goto out; 342 343 snap = scf_snapshot_create(h); 344 if (snap == NULL) 345 goto out; 346 347 if (scf_instance_get_snapshot(inst, SMF_SNAPSHOT_RUNNING, snap) == 0) { 348 if (_scf_snapshot_take_attach(inst, snap) == 0) 349 err = 0; 350 } else { 351 switch (scf_error()) { 352 case SCF_ERROR_DELETED: 353 err = 0; 354 goto out; 355 356 case SCF_ERROR_NOT_FOUND: 357 break; 358 359 case SCF_ERROR_NOT_SET: 360 assert(0); 361 abort(); 362 /* NOTREACHED */ 363 364 default: 365 goto out; 366 } 367 368 log_error(LOG_DEBUG, 369 "Service %s has no %s snapshot; creating one.\n", fmri, 370 SMF_SNAPSHOT_RUNNING); 371 372 if (_scf_snapshot_take_new(inst, SMF_SNAPSHOT_RUNNING, 373 snap) == 0) 374 err = 0; 375 } 376 377 out: 378 scf_snapshot_destroy(snap); 379 380 if (!err) 381 return (0); 382 383 log_error(LOG_WARNING, 384 "Could not update \"running\" snapshot for refresh of %s.\n", fmri); 385 return (-1); 386 } 387 388 /* 389 * int libscf_read_single_astring() 390 * Reads a single astring value of the requested property into the 391 * pre-allocated buffer (conventionally of size max_scf_value_size). 392 * Multiple values constitute an error. 393 * 394 * Returns 0 on success or LIBSCF_PROPERTY_ABSENT or LIBSCF_PROPERTY_ERROR. 395 */ 396 static int 397 libscf_read_single_astring(scf_handle_t *h, scf_property_t *prop, char **ret) 398 { 399 scf_value_t *val = safe_scf_value_create(h); 400 int r = 0; 401 402 if (scf_property_get_value(prop, val) == -1) { 403 if (scf_error() == SCF_ERROR_NOT_FOUND) 404 r = LIBSCF_PROPERTY_ABSENT; 405 else 406 r = LIBSCF_PROPERTY_ERROR; 407 goto read_single_astring_fail; 408 } 409 410 if (scf_value_get_astring(val, *ret, max_scf_value_size) <= 0) { 411 r = LIBSCF_PROPERTY_ERROR; 412 goto read_single_astring_fail; 413 } 414 415 read_single_astring_fail: 416 scf_value_destroy(val); 417 return (r); 418 } 419 420 static int 421 libscf_read_state(const scf_propertygroup_t *pg, const char *prop_name, 422 restarter_instance_state_t *state) 423 { 424 scf_handle_t *h; 425 scf_property_t *prop; 426 char *char_state = startd_alloc(max_scf_value_size); 427 int ret = 0; 428 429 h = scf_pg_handle(pg); 430 prop = safe_scf_property_create(h); 431 432 if (scf_pg_get_property(pg, prop_name, prop) == -1) { 433 if (scf_error() == SCF_ERROR_NOT_FOUND) 434 ret = LIBSCF_PROPERTY_ABSENT; 435 else 436 ret = LIBSCF_PROPERTY_ERROR; 437 } else { 438 ret = libscf_read_single_astring(h, prop, &char_state); 439 if (ret != 0) { 440 if (ret != LIBSCF_PROPERTY_ABSENT) 441 ret = LIBSCF_PROPERTY_ERROR; 442 } else { 443 *state = restarter_string_to_state(char_state); 444 ret = 0; 445 } 446 } 447 448 startd_free(char_state, max_scf_value_size); 449 scf_property_destroy(prop); 450 return (ret); 451 } 452 453 /* 454 * int libscf_read_states(const scf_propertygroup_t *, 455 * restarter_instance_state_t *, restarter_instance_state_t *) 456 * 457 * Set the current state and next_state values for the given service instance. 458 * Returns 0 on success, or a libscf error code on failure. 459 */ 460 int 461 libscf_read_states(const scf_propertygroup_t *pg, 462 restarter_instance_state_t *state, restarter_instance_state_t *next_state) 463 { 464 int state_ret, next_state_ret, ret; 465 466 state_ret = libscf_read_state(pg, SCF_PROPERTY_STATE, state); 467 next_state_ret = libscf_read_state(pg, SCF_PROPERTY_NEXT_STATE, 468 next_state); 469 470 if (state_ret == LIBSCF_PROPERTY_ERROR || 471 next_state_ret == LIBSCF_PROPERTY_ERROR) { 472 ret = LIBSCF_PROPERTY_ERROR; 473 } else if (state_ret == 0 && next_state_ret == 0) { 474 ret = 0; 475 } else if (state_ret == LIBSCF_PROPERTY_ABSENT && 476 next_state_ret == LIBSCF_PROPERTY_ABSENT) { 477 *state = RESTARTER_STATE_UNINIT; 478 *next_state = RESTARTER_STATE_NONE; 479 ret = 0; 480 } else if (state_ret == LIBSCF_PROPERTY_ABSENT || 481 next_state_ret == LIBSCF_PROPERTY_ABSENT) { 482 log_framework(LOG_DEBUG, 483 "Only one repository state exists, setting " 484 "restarter states to MAINTENANCE and NONE\n"); 485 *state = RESTARTER_STATE_MAINT; 486 *next_state = RESTARTER_STATE_NONE; 487 ret = 0; 488 } else { 489 ret = LIBSCF_PROPERTY_ERROR; 490 } 491 492 read_states_out: 493 return (ret); 494 } 495 496 /* 497 * depgroup_empty() 498 * 499 * Returns 0 if not empty. 500 * Returns 1 if empty. 501 * Returns -1 on error (check scf_error()). 502 */ 503 int 504 depgroup_empty(scf_handle_t *h, scf_propertygroup_t *pg) 505 { 506 int empty = 1; 507 scf_iter_t *iter; 508 scf_property_t *prop; 509 int ret; 510 511 iter = safe_scf_iter_create(h); 512 prop = safe_scf_property_create(h); 513 514 iter = safe_scf_iter_create(h); 515 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 516 return (-1); 517 518 ret = scf_iter_next_property(iter, prop); 519 if (ret < 0) 520 return (-1); 521 522 if (ret == 1) 523 empty = 0; 524 525 scf_property_destroy(prop); 526 scf_iter_destroy(iter); 527 528 return (empty); 529 } 530 531 gv_type_t 532 depgroup_read_scheme(scf_handle_t *h, scf_propertygroup_t *pg) 533 { 534 scf_property_t *prop; 535 char *scheme = startd_alloc(max_scf_value_size); 536 gv_type_t ret; 537 538 prop = safe_scf_property_create(h); 539 540 if (scf_pg_get_property(pg, SCF_PROPERTY_TYPE, prop) == -1 || 541 libscf_read_single_astring(h, prop, &scheme) != 0) { 542 scf_property_destroy(prop); 543 startd_free(scheme, max_scf_value_size); 544 return (GVT_UNSUPPORTED); 545 } 546 547 if (strcmp(scheme, "service") == 0) 548 ret = GVT_INST; 549 else if (strcmp(scheme, "path") == 0) 550 ret = GVT_FILE; 551 else 552 ret = GVT_UNSUPPORTED; 553 554 startd_free(scheme, max_scf_value_size); 555 scf_property_destroy(prop); 556 return (ret); 557 } 558 559 depgroup_type_t 560 depgroup_read_grouping(scf_handle_t *h, scf_propertygroup_t *pg) 561 { 562 char *grouping = startd_alloc(max_scf_value_size); 563 depgroup_type_t ret; 564 scf_property_t *prop = safe_scf_property_create(h); 565 566 if (scf_pg_get_property(pg, SCF_PROPERTY_GROUPING, prop) == -1 || 567 libscf_read_single_astring(h, prop, &grouping) != 0) { 568 scf_property_destroy(prop); 569 startd_free(grouping, max_scf_value_size); 570 return (DEPGRP_UNSUPPORTED); 571 } 572 573 if (strcmp(grouping, SCF_DEP_REQUIRE_ANY) == 0) 574 ret = DEPGRP_REQUIRE_ANY; 575 else if (strcmp(grouping, SCF_DEP_REQUIRE_ALL) == 0) 576 ret = DEPGRP_REQUIRE_ALL; 577 else if (strcmp(grouping, SCF_DEP_OPTIONAL_ALL) == 0) 578 ret = DEPGRP_OPTIONAL_ALL; 579 else if (strcmp(grouping, SCF_DEP_EXCLUDE_ALL) == 0) 580 ret = DEPGRP_EXCLUDE_ALL; 581 else { 582 ret = DEPGRP_UNSUPPORTED; 583 } 584 startd_free(grouping, max_scf_value_size); 585 scf_property_destroy(prop); 586 return (ret); 587 } 588 589 restarter_error_t 590 depgroup_read_restart(scf_handle_t *h, scf_propertygroup_t *pg) 591 { 592 scf_property_t *prop = safe_scf_property_create(h); 593 char *restart_on = startd_alloc(max_scf_value_size); 594 restarter_error_t ret; 595 596 if (scf_pg_get_property(pg, SCF_PROPERTY_RESTART_ON, prop) == -1 || 597 libscf_read_single_astring(h, prop, &restart_on) != 0) { 598 startd_free(restart_on, max_scf_value_size); 599 scf_property_destroy(prop); 600 return (RERR_UNSUPPORTED); 601 } 602 603 if (strcmp(restart_on, SCF_DEP_RESET_ON_ERROR) == 0) 604 ret = RERR_FAULT; 605 else if (strcmp(restart_on, SCF_DEP_RESET_ON_RESTART) == 0) 606 ret = RERR_RESTART; 607 else if (strcmp(restart_on, SCF_DEP_RESET_ON_REFRESH) == 0) 608 ret = RERR_REFRESH; 609 else if (strcmp(restart_on, SCF_DEP_RESET_ON_NONE) == 0) 610 ret = RERR_NONE; 611 else 612 ret = RERR_UNSUPPORTED; 613 614 startd_free(restart_on, max_scf_value_size); 615 scf_property_destroy(prop); 616 return (ret); 617 } 618 619 /* 620 * int get_boolean() 621 * Fetches the value of a boolean property of the given property group. 622 * Returns 623 * 0 - success 624 * ECONNABORTED - repository connection broken 625 * ECANCELED - pg was deleted 626 * ENOENT - the property doesn't exist or has no values 627 * EINVAL - the property has the wrong type 628 * the property is not single-valued 629 */ 630 static int 631 get_boolean(scf_propertygroup_t *pg, const char *propname, uint8_t *valuep) 632 { 633 scf_handle_t *h; 634 scf_property_t *prop; 635 scf_value_t *val; 636 int ret = 0, r; 637 scf_type_t type; 638 639 h = scf_pg_handle(pg); 640 prop = safe_scf_property_create(h); 641 val = safe_scf_value_create(h); 642 643 if (scf_pg_get_property(pg, propname, prop) != 0) { 644 switch (scf_error()) { 645 case SCF_ERROR_CONNECTION_BROKEN: 646 default: 647 ret = ECONNABORTED; 648 goto out; 649 650 case SCF_ERROR_DELETED: 651 ret = ECANCELED; 652 goto out; 653 654 case SCF_ERROR_NOT_FOUND: 655 ret = ENOENT; 656 goto out; 657 658 case SCF_ERROR_HANDLE_MISMATCH: 659 case SCF_ERROR_INVALID_ARGUMENT: 660 case SCF_ERROR_NOT_SET: 661 bad_error("scf_pg_get_property", scf_error()); 662 } 663 } 664 665 if (scf_property_type(prop, &type) != 0) { 666 switch (scf_error()) { 667 case SCF_ERROR_CONNECTION_BROKEN: 668 default: 669 ret = ECONNABORTED; 670 goto out; 671 672 case SCF_ERROR_DELETED: 673 ret = ENOENT; 674 goto out; 675 676 case SCF_ERROR_NOT_SET: 677 bad_error("scf_property_type", scf_error()); 678 } 679 } 680 681 if (type != SCF_TYPE_BOOLEAN) { 682 ret = EINVAL; 683 goto out; 684 } 685 686 if (scf_property_get_value(prop, val) != 0) { 687 switch (scf_error()) { 688 case SCF_ERROR_CONNECTION_BROKEN: 689 default: 690 ret = ECONNABORTED; 691 goto out; 692 693 case SCF_ERROR_DELETED: 694 case SCF_ERROR_NOT_FOUND: 695 ret = ENOENT; 696 goto out; 697 698 case SCF_ERROR_CONSTRAINT_VIOLATED: 699 ret = EINVAL; 700 goto out; 701 702 case SCF_ERROR_NOT_SET: 703 bad_error("scf_property_get_value", scf_error()); 704 } 705 } 706 707 r = scf_value_get_boolean(val, valuep); 708 assert(r == 0); 709 710 out: 711 scf_value_destroy(val); 712 scf_property_destroy(prop); 713 return (ret); 714 } 715 716 /* 717 * int get_count() 718 * Fetches the value of a count property of the given property group. 719 * Returns 720 * 0 - success 721 * ECONNABORTED - repository connection broken 722 * unknown libscf error 723 * ECANCELED - pg was deleted 724 * ENOENT - the property doesn't exist or has no values 725 * EINVAL - the property has the wrong type 726 * the property is not single-valued 727 */ 728 static int 729 get_count(scf_propertygroup_t *pg, const char *propname, uint64_t *valuep) 730 { 731 scf_handle_t *h; 732 scf_property_t *prop; 733 scf_value_t *val; 734 int ret = 0, r; 735 736 h = scf_pg_handle(pg); 737 prop = safe_scf_property_create(h); 738 val = safe_scf_value_create(h); 739 740 if (scf_pg_get_property(pg, propname, prop) != 0) { 741 switch (scf_error()) { 742 case SCF_ERROR_CONNECTION_BROKEN: 743 default: 744 ret = ECONNABORTED; 745 goto out; 746 747 case SCF_ERROR_DELETED: 748 ret = ECANCELED; 749 goto out; 750 751 case SCF_ERROR_NOT_FOUND: 752 ret = ENOENT; 753 goto out; 754 755 case SCF_ERROR_HANDLE_MISMATCH: 756 case SCF_ERROR_INVALID_ARGUMENT: 757 case SCF_ERROR_NOT_SET: 758 bad_error("scf_pg_get_property", scf_error()); 759 } 760 } 761 762 if (scf_property_is_type(prop, SCF_TYPE_COUNT) != 0) { 763 switch (scf_error()) { 764 case SCF_ERROR_CONNECTION_BROKEN: 765 default: 766 ret = ECONNABORTED; 767 goto out; 768 769 case SCF_ERROR_TYPE_MISMATCH: 770 ret = EINVAL; 771 goto out; 772 773 case SCF_ERROR_DELETED: 774 ret = ECANCELED; 775 goto out; 776 777 case SCF_ERROR_INVALID_ARGUMENT: 778 case SCF_ERROR_NOT_BOUND: 779 case SCF_ERROR_NOT_SET: 780 bad_error("scf_property_is_type", scf_error()); 781 } 782 } 783 784 if (scf_property_get_value(prop, val) != 0) { 785 switch (scf_error()) { 786 case SCF_ERROR_CONNECTION_BROKEN: 787 default: 788 ret = ECONNABORTED; 789 goto out; 790 791 case SCF_ERROR_DELETED: 792 ret = ECANCELED; 793 goto out; 794 795 case SCF_ERROR_NOT_FOUND: 796 ret = ENOENT; 797 goto out; 798 799 case SCF_ERROR_CONSTRAINT_VIOLATED: 800 ret = EINVAL; 801 goto out; 802 803 case SCF_ERROR_NOT_SET: 804 bad_error("scf_property_get_value", scf_error()); 805 } 806 } 807 808 r = scf_value_get_count(val, valuep); 809 assert(r == 0); 810 811 out: 812 scf_value_destroy(val); 813 scf_property_destroy(prop); 814 return (ret); 815 } 816 817 818 static void 819 get_restarter(scf_handle_t *h, scf_propertygroup_t *pg, char **restarter) 820 { 821 scf_property_t *prop = safe_scf_property_create(h); 822 823 if (scf_pg_get_property(pg, SCF_PROPERTY_RESTARTER, prop) == -1 || 824 libscf_read_single_astring(h, prop, restarter) != 0) 825 *restarter[0] = '\0'; 826 827 scf_property_destroy(prop); 828 } 829 830 /* 831 * int libscf_instance_get_fmri(scf_instance_t *, char **) 832 * Give a valid SCF instance, return its FMRI. Returns 0 on success, 833 * ECONNABORTED, or ECANCELED if inst is deleted. 834 */ 835 int 836 libscf_instance_get_fmri(scf_instance_t *inst, char **retp) 837 { 838 char *inst_fmri = startd_alloc(max_scf_fmri_size); 839 840 inst_fmri[0] = 0; 841 if (scf_instance_to_fmri(inst, inst_fmri, max_scf_fmri_size) <= 0) { 842 startd_free(inst_fmri, max_scf_fmri_size); 843 switch (scf_error()) { 844 case SCF_ERROR_CONNECTION_BROKEN: 845 default: 846 return (ECONNABORTED); 847 848 case SCF_ERROR_DELETED: 849 return (ECANCELED); 850 851 case SCF_ERROR_NOT_SET: 852 assert(0); 853 abort(); 854 } 855 } 856 857 *retp = inst_fmri; 858 return (0); 859 } 860 861 /* 862 * int libscf_fmri_get_instance(scf_handle_t *, const char *, 863 * scf_instance_t **) 864 * Given a valid SCF handle and an FMRI, return the SCF instance that matches 865 * exactly. The instance must be released using scf_instance_destroy(). 866 * Returns 0 on success, EINVAL if the FMRI is invalid, ENOTSUP if the FMRI 867 * is valid but designates something other than an instance, ECONNABORTED if 868 * the repository connection is broken, or ENOENT if the instance does not 869 * exist. 870 */ 871 int 872 libscf_fmri_get_instance(scf_handle_t *h, const char *fmri, 873 scf_instance_t **instp) 874 { 875 scf_instance_t *inst; 876 int r; 877 878 inst = safe_scf_instance_create(h); 879 880 r = libscf_lookup_instance(fmri, inst); 881 882 if (r == 0) 883 *instp = inst; 884 else 885 scf_instance_destroy(inst); 886 887 return (r); 888 } 889 890 int 891 libscf_lookup_instance(const char *fmri, scf_instance_t *inst) 892 { 893 if (scf_handle_decode_fmri(scf_instance_handle(inst), fmri, NULL, NULL, 894 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 895 switch (scf_error()) { 896 case SCF_ERROR_INVALID_ARGUMENT: 897 return (EINVAL); 898 899 case SCF_ERROR_CONSTRAINT_VIOLATED: 900 return (ENOTSUP); 901 902 case SCF_ERROR_CONNECTION_BROKEN: 903 return (ECONNABORTED); 904 905 case SCF_ERROR_NOT_FOUND: 906 return (ENOENT); 907 908 case SCF_ERROR_HANDLE_MISMATCH: 909 default: 910 bad_error("scf_handle_decode_fmri", scf_error()); 911 } 912 } 913 914 return (0); 915 } 916 917 /* 918 * void libscf_get_basic_instance_data() 919 * Read enabled, enabled_ovr, and restarter_fmri (into an allocated 920 * buffer) for inst. Returns 0, ECONNABORTED if the connection to the 921 * repository is broken, ECANCELED if inst is deleted, or ENOENT if inst 922 * has no general property group. 923 * 924 * On success, restarter_fmri may be NULL. If general/enabled was missing 925 * or invalid, *enabledp will be -1 and a debug message is logged. 926 */ 927 int 928 libscf_get_basic_instance_data(scf_handle_t *h, scf_instance_t *inst, 929 const char *fmri, int *enabledp, int *enabled_ovrp, char **restarter_fmri) 930 { 931 scf_propertygroup_t *pg; 932 int r; 933 uint8_t enabled_8; 934 935 pg = safe_scf_pg_create(h); 936 937 if (enabled_ovrp == NULL) 938 goto enabled; 939 940 if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_GENERAL_OVR, pg) != 941 0) { 942 switch (scf_error()) { 943 case SCF_ERROR_CONNECTION_BROKEN: 944 default: 945 scf_pg_destroy(pg); 946 return (ECONNABORTED); 947 948 case SCF_ERROR_DELETED: 949 scf_pg_destroy(pg); 950 return (ECANCELED); 951 952 case SCF_ERROR_NOT_FOUND: 953 *enabled_ovrp = -1; 954 break; 955 956 case SCF_ERROR_HANDLE_MISMATCH: 957 case SCF_ERROR_INVALID_ARGUMENT: 958 case SCF_ERROR_NOT_SET: 959 bad_error("scf_instance_get_pg_composed", scf_error()); 960 } 961 } else { 962 switch (r = get_boolean(pg, SCF_PROPERTY_ENABLED, &enabled_8)) { 963 case 0: 964 *enabled_ovrp = enabled_8; 965 break; 966 967 case ECONNABORTED: 968 case ECANCELED: 969 scf_pg_destroy(pg); 970 return (r); 971 972 case ENOENT: 973 case EINVAL: 974 *enabled_ovrp = -1; 975 break; 976 977 default: 978 bad_error("get_boolean", r); 979 } 980 } 981 982 enabled: 983 /* 984 * Since general/restarter can be at the service level, we must do 985 * a composed lookup. These properties are immediate, though, so we 986 * must use the "editing" snapshot. Technically enabled shouldn't be 987 * at the service level, but looking it up composed, too, doesn't 988 * hurt. 989 */ 990 if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_GENERAL, pg) != 0) { 991 scf_pg_destroy(pg); 992 switch (scf_error()) { 993 case SCF_ERROR_CONNECTION_BROKEN: 994 default: 995 return (ECONNABORTED); 996 997 case SCF_ERROR_DELETED: 998 return (ECANCELED); 999 1000 case SCF_ERROR_NOT_FOUND: 1001 return (ENOENT); 1002 1003 case SCF_ERROR_NOT_SET: 1004 bad_error("scf_instance_get_pg_composed", scf_error()); 1005 } 1006 } 1007 1008 switch (r = get_boolean(pg, SCF_PROPERTY_ENABLED, &enabled_8)) { 1009 case 0: 1010 *enabledp = enabled_8; 1011 break; 1012 1013 case ECONNABORTED: 1014 case ECANCELED: 1015 scf_pg_destroy(pg); 1016 return (r); 1017 1018 case ENOENT: 1019 /* 1020 * DEBUG because this happens when svccfg import creates 1021 * a temporary service. 1022 */ 1023 log_framework(LOG_DEBUG, 1024 "general/enabled property of %s is missing.\n", fmri); 1025 *enabledp = -1; 1026 break; 1027 1028 case EINVAL: 1029 log_framework(LOG_ERR, 1030 "general/enabled property of %s is invalid.\n", fmri); 1031 *enabledp = -1; 1032 break; 1033 1034 default: 1035 bad_error("get_boolean", r); 1036 } 1037 1038 if (restarter_fmri != NULL) 1039 get_restarter(h, pg, restarter_fmri); 1040 1041 scf_pg_destroy(pg); 1042 1043 return (0); 1044 } 1045 1046 1047 /* 1048 * Sets pg to the name property group of s_inst. If it doesn't exist, it is 1049 * added. 1050 * 1051 * Fails with 1052 * ECONNABORTED - repository disconnection or unknown libscf error 1053 * ECANCELED - inst is deleted 1054 * EPERM - permission is denied 1055 * EACCES - backend denied access 1056 * EROFS - backend readonly 1057 */ 1058 int 1059 libscf_inst_get_or_add_pg(scf_instance_t *inst, const char *name, 1060 const char *type, uint32_t flags, scf_propertygroup_t *pg) 1061 { 1062 uint32_t f; 1063 1064 again: 1065 if (scf_instance_get_pg(inst, name, pg) == 0) { 1066 if (scf_pg_get_flags(pg, &f) != 0) { 1067 switch (scf_error()) { 1068 case SCF_ERROR_CONNECTION_BROKEN: 1069 default: 1070 return (ECONNABORTED); 1071 1072 case SCF_ERROR_DELETED: 1073 goto add; 1074 1075 case SCF_ERROR_NOT_SET: 1076 bad_error("scf_pg_get_flags", scf_error()); 1077 } 1078 } 1079 1080 if (f == flags) 1081 return (0); 1082 1083 if (scf_pg_delete(pg) != 0) { 1084 switch (scf_error()) { 1085 case SCF_ERROR_CONNECTION_BROKEN: 1086 default: 1087 return (ECONNABORTED); 1088 1089 case SCF_ERROR_DELETED: 1090 break; 1091 1092 case SCF_ERROR_PERMISSION_DENIED: 1093 return (EPERM); 1094 1095 case SCF_ERROR_BACKEND_ACCESS: 1096 return (EACCES); 1097 1098 case SCF_ERROR_BACKEND_READONLY: 1099 return (EROFS); 1100 1101 case SCF_ERROR_NOT_SET: 1102 bad_error("scf_pg_delete", scf_error()); 1103 } 1104 } 1105 } else { 1106 switch (scf_error()) { 1107 case SCF_ERROR_CONNECTION_BROKEN: 1108 default: 1109 return (ECONNABORTED); 1110 1111 case SCF_ERROR_DELETED: 1112 return (ECANCELED); 1113 1114 case SCF_ERROR_NOT_FOUND: 1115 break; 1116 1117 case SCF_ERROR_HANDLE_MISMATCH: 1118 case SCF_ERROR_INVALID_ARGUMENT: 1119 case SCF_ERROR_NOT_SET: 1120 bad_error("scf_instance_get_pg", scf_error()); 1121 } 1122 } 1123 1124 add: 1125 if (scf_instance_add_pg(inst, name, type, flags, pg) == 0) 1126 return (0); 1127 1128 switch (scf_error()) { 1129 case SCF_ERROR_CONNECTION_BROKEN: 1130 default: 1131 return (ECONNABORTED); 1132 1133 case SCF_ERROR_DELETED: 1134 return (ECANCELED); 1135 1136 case SCF_ERROR_EXISTS: 1137 goto again; 1138 1139 case SCF_ERROR_PERMISSION_DENIED: 1140 return (EPERM); 1141 1142 case SCF_ERROR_BACKEND_ACCESS: 1143 return (EACCES); 1144 1145 case SCF_ERROR_BACKEND_READONLY: 1146 return (EROFS); 1147 1148 case SCF_ERROR_HANDLE_MISMATCH: 1149 case SCF_ERROR_INVALID_ARGUMENT: 1150 case SCF_ERROR_NOT_SET: 1151 bad_error("scf_instance_add_pg", scf_error()); 1152 /* NOTREACHED */ 1153 } 1154 } 1155 1156 /* 1157 * Returns 1158 * 0 - success 1159 * ECONNABORTED - repository connection broken 1160 * - unknown libscf error 1161 * ECANCELED 1162 */ 1163 static scf_error_t 1164 transaction_add_set(scf_transaction_t *tx, scf_transaction_entry_t *ent, 1165 const char *pname, scf_type_t ty) 1166 { 1167 for (;;) { 1168 if (scf_transaction_property_change_type(tx, ent, pname, 1169 ty) == 0) 1170 return (0); 1171 1172 switch (scf_error()) { 1173 case SCF_ERROR_CONNECTION_BROKEN: 1174 default: 1175 return (ECONNABORTED); 1176 1177 case SCF_ERROR_DELETED: 1178 return (ECANCELED); 1179 1180 case SCF_ERROR_NOT_FOUND: 1181 break; 1182 1183 case SCF_ERROR_HANDLE_MISMATCH: 1184 case SCF_ERROR_INVALID_ARGUMENT: 1185 case SCF_ERROR_IN_USE: 1186 case SCF_ERROR_NOT_SET: 1187 bad_error("scf_transaction_property_change_type", 1188 scf_error()); 1189 } 1190 1191 if (scf_transaction_property_new(tx, ent, pname, ty) == 0) 1192 return (0); 1193 1194 switch (scf_error()) { 1195 case SCF_ERROR_CONNECTION_BROKEN: 1196 default: 1197 return (ECONNABORTED); 1198 1199 case SCF_ERROR_DELETED: 1200 return (ECANCELED); 1201 1202 case SCF_ERROR_EXISTS: 1203 break; 1204 1205 case SCF_ERROR_HANDLE_MISMATCH: 1206 case SCF_ERROR_INVALID_ARGUMENT: 1207 case SCF_ERROR_IN_USE: 1208 case SCF_ERROR_NOT_SET: 1209 bad_error("scf_transaction_property_new", scf_error()); 1210 /* NOTREACHED */ 1211 } 1212 } 1213 } 1214 1215 /* 1216 * Returns 1217 * 0 - success 1218 * ECONNABORTED - repository connection broken 1219 * - unknown libscf error 1220 * ECANCELED - pg was deleted 1221 * EPERM 1222 * EACCES 1223 * EROFS 1224 */ 1225 static int 1226 pg_set_prop_value(scf_propertygroup_t *pg, const char *pname, scf_value_t *v) 1227 { 1228 scf_handle_t *h; 1229 scf_transaction_t *tx; 1230 scf_transaction_entry_t *e; 1231 scf_type_t ty; 1232 scf_error_t scfe; 1233 int ret, r; 1234 1235 h = scf_pg_handle(pg); 1236 tx = safe_scf_transaction_create(h); 1237 e = safe_scf_entry_create(h); 1238 1239 ty = scf_value_type(v); 1240 assert(ty != SCF_TYPE_INVALID); 1241 1242 for (;;) { 1243 if (scf_transaction_start(tx, pg) != 0) { 1244 switch (scf_error()) { 1245 case SCF_ERROR_CONNECTION_BROKEN: 1246 default: 1247 ret = ECONNABORTED; 1248 goto out; 1249 1250 case SCF_ERROR_DELETED: 1251 ret = ECANCELED; 1252 goto out; 1253 1254 case SCF_ERROR_PERMISSION_DENIED: 1255 ret = EPERM; 1256 goto out; 1257 1258 case SCF_ERROR_BACKEND_ACCESS: 1259 ret = EACCES; 1260 goto out; 1261 1262 case SCF_ERROR_BACKEND_READONLY: 1263 ret = EROFS; 1264 goto out; 1265 1266 case SCF_ERROR_NOT_SET: 1267 bad_error("scf_transaction_start", ret); 1268 } 1269 } 1270 1271 ret = transaction_add_set(tx, e, pname, ty); 1272 switch (ret) { 1273 case 0: 1274 break; 1275 1276 case ECONNABORTED: 1277 case ECANCELED: 1278 goto out; 1279 1280 default: 1281 bad_error("transaction_add_set", ret); 1282 } 1283 1284 r = scf_entry_add_value(e, v); 1285 assert(r == 0); 1286 1287 r = scf_transaction_commit(tx); 1288 if (r == 1) 1289 break; 1290 if (r != 0) { 1291 scfe = scf_error(); 1292 scf_transaction_reset(tx); 1293 switch (scfe) { 1294 case SCF_ERROR_CONNECTION_BROKEN: 1295 default: 1296 ret = ECONNABORTED; 1297 goto out; 1298 1299 case SCF_ERROR_DELETED: 1300 ret = ECANCELED; 1301 goto out; 1302 1303 case SCF_ERROR_PERMISSION_DENIED: 1304 ret = EPERM; 1305 goto out; 1306 1307 case SCF_ERROR_BACKEND_ACCESS: 1308 ret = EACCES; 1309 goto out; 1310 1311 case SCF_ERROR_BACKEND_READONLY: 1312 ret = EROFS; 1313 goto out; 1314 1315 case SCF_ERROR_NOT_SET: 1316 bad_error("scf_transaction_commit", scfe); 1317 } 1318 } 1319 1320 scf_transaction_reset(tx); 1321 1322 if (scf_pg_update(pg) == -1) { 1323 switch (scf_error()) { 1324 case SCF_ERROR_CONNECTION_BROKEN: 1325 default: 1326 ret = ECONNABORTED; 1327 goto out; 1328 1329 case SCF_ERROR_DELETED: 1330 ret = ECANCELED; 1331 goto out; 1332 1333 case SCF_ERROR_NOT_SET: 1334 bad_error("scf_pg_update", scf_error()); 1335 } 1336 } 1337 } 1338 1339 ret = 0; 1340 1341 out: 1342 scf_transaction_destroy(tx); 1343 scf_entry_destroy(e); 1344 return (ret); 1345 } 1346 1347 /* 1348 * Returns 1349 * 0 - success 1350 * ECONNABORTED - repository connection broken 1351 * - unknown libscf error 1352 * ECANCELED - inst was deleted 1353 * EPERM 1354 * EACCES 1355 * EROFS 1356 */ 1357 int 1358 libscf_inst_set_boolean_prop(scf_instance_t *inst, const char *pgname, 1359 const char *pgtype, uint32_t pgflags, const char *pname, int val) 1360 { 1361 scf_handle_t *h; 1362 scf_propertygroup_t *pg = NULL; 1363 scf_value_t *v; 1364 int ret = 0; 1365 1366 h = scf_instance_handle(inst); 1367 pg = safe_scf_pg_create(h); 1368 v = safe_scf_value_create(h); 1369 1370 ret = libscf_inst_get_or_add_pg(inst, pgname, pgtype, pgflags, pg); 1371 switch (ret) { 1372 case 0: 1373 break; 1374 1375 case ECONNABORTED: 1376 case ECANCELED: 1377 case EPERM: 1378 case EACCES: 1379 case EROFS: 1380 goto out; 1381 1382 default: 1383 bad_error("libscf_inst_get_or_add_pg", ret); 1384 } 1385 1386 scf_value_set_boolean(v, val); 1387 1388 ret = pg_set_prop_value(pg, pname, v); 1389 switch (ret) { 1390 case 0: 1391 case ECONNABORTED: 1392 case ECANCELED: 1393 case EPERM: 1394 case EACCES: 1395 case EROFS: 1396 break; 1397 1398 default: 1399 bad_error("pg_set_prop_value", ret); 1400 } 1401 1402 out: 1403 scf_pg_destroy(pg); 1404 scf_value_destroy(v); 1405 return (ret); 1406 } 1407 1408 /* 1409 * Returns 1410 * 0 - success 1411 * ECONNABORTED - repository connection broken 1412 * - unknown libscf error 1413 * ECANCELED - inst was deleted 1414 * EPERM 1415 * EACCES 1416 * EROFS 1417 */ 1418 int 1419 libscf_inst_set_count_prop(scf_instance_t *inst, const char *pgname, 1420 const char *pgtype, uint32_t pgflags, const char *pname, uint64_t count) 1421 { 1422 scf_handle_t *h; 1423 scf_propertygroup_t *pg = NULL; 1424 scf_value_t *v; 1425 int ret = 0; 1426 1427 h = scf_instance_handle(inst); 1428 pg = safe_scf_pg_create(h); 1429 v = safe_scf_value_create(h); 1430 1431 ret = libscf_inst_get_or_add_pg(inst, pgname, pgtype, pgflags, pg); 1432 switch (ret) { 1433 case 0: 1434 break; 1435 1436 case ECONNABORTED: 1437 case ECANCELED: 1438 case EPERM: 1439 case EACCES: 1440 case EROFS: 1441 goto out; 1442 1443 default: 1444 bad_error("libscf_inst_get_or_add_pg", ret); 1445 } 1446 1447 scf_value_set_count(v, count); 1448 1449 ret = pg_set_prop_value(pg, pname, v); 1450 switch (ret) { 1451 case 0: 1452 case ECONNABORTED: 1453 case ECANCELED: 1454 case EPERM: 1455 case EACCES: 1456 case EROFS: 1457 break; 1458 1459 default: 1460 bad_error("pg_set_prop_value", ret); 1461 } 1462 1463 out: 1464 scf_pg_destroy(pg); 1465 scf_value_destroy(v); 1466 return (ret); 1467 } 1468 1469 /* 1470 * Returns 0 on success, ECONNABORTED if the repository connection is broken, 1471 * ECANCELED if inst is deleted, EROFS if the backend is readonly, or EPERM if 1472 * permission was denied. 1473 */ 1474 int 1475 libscf_set_enable_ovr(scf_instance_t *inst, int enable) 1476 { 1477 return (libscf_inst_set_boolean_prop(inst, SCF_PG_GENERAL_OVR, 1478 SCF_PG_GENERAL_OVR_TYPE, SCF_PG_GENERAL_OVR_FLAGS, 1479 SCF_PROPERTY_ENABLED, enable)); 1480 } 1481 1482 /* 1483 * Returns 1484 * 0 - success 1485 * ECONNABORTED - repository connection broken 1486 * ECANCELED - inst was deleted 1487 * EPERM 1488 * EACCES 1489 * EROFS 1490 */ 1491 int 1492 libscf_inst_delete_prop(scf_instance_t *inst, const char *pgname, 1493 const char *pname) 1494 { 1495 scf_handle_t *h; 1496 scf_propertygroup_t *pg; 1497 scf_transaction_t *tx; 1498 scf_transaction_entry_t *e; 1499 scf_error_t serr; 1500 int ret = 0, r; 1501 1502 h = scf_instance_handle(inst); 1503 pg = safe_scf_pg_create(h); 1504 1505 if (scf_instance_get_pg(inst, pgname, pg) != 0) { 1506 scf_pg_destroy(pg); 1507 switch (scf_error()) { 1508 case SCF_ERROR_CONNECTION_BROKEN: 1509 default: 1510 return (ECONNABORTED); 1511 1512 case SCF_ERROR_DELETED: 1513 return (ECANCELED); 1514 1515 case SCF_ERROR_NOT_FOUND: 1516 return (0); 1517 1518 case SCF_ERROR_NOT_SET: 1519 bad_error("scf_instance_get_pg", scf_error()); 1520 } 1521 } 1522 1523 tx = safe_scf_transaction_create(h); 1524 e = safe_scf_entry_create(h); 1525 1526 for (;;) { 1527 if (scf_transaction_start(tx, pg) != 0) { 1528 switch (scf_error()) { 1529 case SCF_ERROR_CONNECTION_BROKEN: 1530 default: 1531 ret = ECONNABORTED; 1532 goto out; 1533 1534 case SCF_ERROR_DELETED: 1535 ret = 0; 1536 goto out; 1537 1538 case SCF_ERROR_PERMISSION_DENIED: 1539 ret = EPERM; 1540 goto out; 1541 1542 case SCF_ERROR_BACKEND_ACCESS: 1543 ret = EACCES; 1544 goto out; 1545 1546 case SCF_ERROR_BACKEND_READONLY: 1547 ret = EROFS; 1548 goto out; 1549 1550 case SCF_ERROR_HANDLE_MISMATCH: 1551 case SCF_ERROR_INVALID_ARGUMENT: 1552 case SCF_ERROR_NOT_SET: 1553 bad_error("scf_transaction_start", scf_error()); 1554 } 1555 } 1556 1557 if (scf_transaction_property_delete(tx, e, pname) != 0) { 1558 switch (scf_error()) { 1559 case SCF_ERROR_CONNECTION_BROKEN: 1560 default: 1561 ret = ECONNABORTED; 1562 goto out; 1563 1564 case SCF_ERROR_DELETED: 1565 case SCF_ERROR_NOT_FOUND: 1566 ret = 0; 1567 goto out; 1568 1569 case SCF_ERROR_NOT_SET: 1570 case SCF_ERROR_HANDLE_MISMATCH: 1571 case SCF_ERROR_NOT_BOUND: 1572 case SCF_ERROR_INVALID_ARGUMENT: 1573 bad_error("scf_transaction_property_delete", 1574 scf_error()); 1575 } 1576 } 1577 1578 r = scf_transaction_commit(tx); 1579 if (r == 1) 1580 break; 1581 if (r != 0) { 1582 serr = scf_error(); 1583 scf_transaction_reset(tx); 1584 switch (serr) { 1585 case SCF_ERROR_CONNECTION_BROKEN: 1586 default: 1587 ret = ECONNABORTED; 1588 goto out; 1589 1590 case SCF_ERROR_DELETED: 1591 ret = 0; 1592 goto out; 1593 1594 case SCF_ERROR_PERMISSION_DENIED: 1595 ret = EPERM; 1596 goto out; 1597 1598 case SCF_ERROR_BACKEND_ACCESS: 1599 ret = EACCES; 1600 goto out; 1601 1602 case SCF_ERROR_BACKEND_READONLY: 1603 ret = EROFS; 1604 goto out; 1605 1606 case SCF_ERROR_NOT_SET: 1607 case SCF_ERROR_INVALID_ARGUMENT: 1608 case SCF_ERROR_NOT_BOUND: 1609 bad_error("scf_transaction_commit", serr); 1610 } 1611 } 1612 1613 scf_transaction_reset(tx); 1614 1615 if (scf_pg_update(pg) == -1) { 1616 switch (scf_error()) { 1617 case SCF_ERROR_CONNECTION_BROKEN: 1618 default: 1619 ret = ECONNABORTED; 1620 goto out; 1621 1622 case SCF_ERROR_DELETED: 1623 ret = 0; 1624 goto out; 1625 1626 case SCF_ERROR_NOT_SET: 1627 case SCF_ERROR_NOT_BOUND: 1628 bad_error("scf_pg_update", scf_error()); 1629 } 1630 } 1631 } 1632 1633 out: 1634 scf_transaction_destroy(tx); 1635 (void) scf_entry_destroy(e); 1636 scf_pg_destroy(pg); 1637 return (ret); 1638 } 1639 1640 /* 1641 * Returns 0, ECONNABORTED, ECANCELED, or EPERM. 1642 */ 1643 int 1644 libscf_delete_enable_ovr(scf_instance_t *inst) 1645 { 1646 return (libscf_inst_delete_prop(inst, SCF_PG_GENERAL_OVR, 1647 SCF_PROPERTY_ENABLED)); 1648 } 1649 1650 /* 1651 * Fails with 1652 * ECONNABORTED - repository connection was broken 1653 * ECANCELED - pg was deleted 1654 * ENOENT - pg has no milestone property 1655 * EINVAL - the milestone property is misconfigured 1656 */ 1657 static int 1658 pg_get_milestone(scf_propertygroup_t *pg, scf_property_t *prop, 1659 scf_value_t *val, char *buf, size_t buf_sz) 1660 { 1661 if (scf_pg_get_property(pg, SCF_PROPERTY_MILESTONE, prop) != 0) { 1662 switch (scf_error()) { 1663 case SCF_ERROR_CONNECTION_BROKEN: 1664 default: 1665 return (ECONNABORTED); 1666 1667 case SCF_ERROR_DELETED: 1668 return (ECANCELED); 1669 1670 case SCF_ERROR_NOT_FOUND: 1671 return (ENOENT); 1672 1673 case SCF_ERROR_HANDLE_MISMATCH: 1674 case SCF_ERROR_INVALID_ARGUMENT: 1675 case SCF_ERROR_NOT_SET: 1676 bad_error("scf_pg_get_property", scf_error()); 1677 } 1678 } 1679 1680 if (scf_property_get_value(prop, val) != 0) { 1681 switch (scf_error()) { 1682 case SCF_ERROR_CONNECTION_BROKEN: 1683 default: 1684 return (ECONNABORTED); 1685 1686 case SCF_ERROR_DELETED: 1687 case SCF_ERROR_CONSTRAINT_VIOLATED: 1688 case SCF_ERROR_NOT_FOUND: 1689 return (EINVAL); 1690 1691 case SCF_ERROR_NOT_SET: 1692 bad_error("scf_property_get_value", scf_error()); 1693 } 1694 } 1695 1696 if (scf_value_get_astring(val, buf, buf_sz) < 0) { 1697 switch (scf_error()) { 1698 case SCF_ERROR_TYPE_MISMATCH: 1699 return (EINVAL); 1700 1701 case SCF_ERROR_NOT_SET: 1702 default: 1703 bad_error("scf_value_get_astring", scf_error()); 1704 } 1705 } 1706 1707 return (0); 1708 } 1709 1710 /* 1711 * Fails with 1712 * ECONNABORTED - repository connection was broken 1713 * ECANCELED - inst was deleted 1714 * ENOENT - inst has no milestone property 1715 * EINVAL - the milestone property is misconfigured 1716 */ 1717 int 1718 libscf_get_milestone(scf_instance_t *inst, scf_property_t *prop, 1719 scf_value_t *val, char *buf, size_t buf_sz) 1720 { 1721 scf_propertygroup_t *pg; 1722 int r; 1723 1724 pg = safe_scf_pg_create(scf_instance_handle(inst)); 1725 1726 if (scf_instance_get_pg(inst, SCF_PG_OPTIONS_OVR, pg) == 0) { 1727 switch (r = pg_get_milestone(pg, prop, val, buf, buf_sz)) { 1728 case 0: 1729 case ECONNABORTED: 1730 case EINVAL: 1731 goto out; 1732 1733 case ECANCELED: 1734 case ENOENT: 1735 break; 1736 1737 default: 1738 bad_error("pg_get_milestone", r); 1739 } 1740 } else { 1741 switch (scf_error()) { 1742 case SCF_ERROR_CONNECTION_BROKEN: 1743 default: 1744 r = ECONNABORTED; 1745 goto out; 1746 1747 case SCF_ERROR_DELETED: 1748 r = ECANCELED; 1749 goto out; 1750 1751 case SCF_ERROR_NOT_FOUND: 1752 break; 1753 1754 case SCF_ERROR_HANDLE_MISMATCH: 1755 case SCF_ERROR_INVALID_ARGUMENT: 1756 case SCF_ERROR_NOT_SET: 1757 bad_error("scf_instance_get_pg", scf_error()); 1758 } 1759 } 1760 1761 if (scf_instance_get_pg(inst, SCF_PG_OPTIONS, pg) == 0) { 1762 r = pg_get_milestone(pg, prop, val, buf, buf_sz); 1763 } else { 1764 switch (scf_error()) { 1765 case SCF_ERROR_CONNECTION_BROKEN: 1766 default: 1767 r = ECONNABORTED; 1768 goto out; 1769 1770 case SCF_ERROR_DELETED: 1771 r = ECANCELED; 1772 goto out; 1773 1774 case SCF_ERROR_NOT_FOUND: 1775 r = ENOENT; 1776 break; 1777 1778 case SCF_ERROR_HANDLE_MISMATCH: 1779 case SCF_ERROR_INVALID_ARGUMENT: 1780 case SCF_ERROR_NOT_SET: 1781 bad_error("scf_instance_get_pg", scf_error()); 1782 } 1783 } 1784 1785 out: 1786 scf_pg_destroy(pg); 1787 1788 return (r); 1789 } 1790 1791 /* 1792 * Get the runlevel character from the runlevel property of the given property 1793 * group. Fails with 1794 * ECONNABORTED - repository connection was broken 1795 * ECANCELED - prop's property group was deleted 1796 * ENOENT - the property has no values 1797 * EINVAL - the property has more than one value 1798 * the property is of the wrong type 1799 * the property value is malformed 1800 */ 1801 int 1802 libscf_extract_runlevel(scf_property_t *prop, char *rlp) 1803 { 1804 scf_value_t *val; 1805 char buf[2]; 1806 1807 val = safe_scf_value_create(scf_property_handle(prop)); 1808 1809 if (scf_property_get_value(prop, val) != 0) { 1810 switch (scf_error()) { 1811 case SCF_ERROR_CONNECTION_BROKEN: 1812 return (ECONNABORTED); 1813 1814 case SCF_ERROR_NOT_SET: 1815 return (ENOENT); 1816 1817 case SCF_ERROR_DELETED: 1818 return (ECANCELED); 1819 1820 case SCF_ERROR_CONSTRAINT_VIOLATED: 1821 return (EINVAL); 1822 1823 case SCF_ERROR_NOT_FOUND: 1824 return (ENOENT); 1825 1826 case SCF_ERROR_HANDLE_MISMATCH: 1827 case SCF_ERROR_NOT_BOUND: 1828 default: 1829 bad_error("scf_property_get_value", scf_error()); 1830 } 1831 } 1832 1833 if (scf_value_get_astring(val, buf, sizeof (buf)) < 0) { 1834 if (scf_error() != SCF_ERROR_TYPE_MISMATCH) 1835 bad_error("scf_value_get_astring", scf_error()); 1836 1837 return (EINVAL); 1838 } 1839 1840 if (buf[0] == '\0' || buf[1] != '\0') 1841 return (EINVAL); 1842 1843 *rlp = buf[0]; 1844 1845 return (0); 1846 } 1847 1848 /* 1849 * Delete the "runlevel" property from the given property group. Also set the 1850 * "milestone" property to the given string. Fails with ECONNABORTED, 1851 * ECANCELED, EPERM, EACCES, or EROFS. 1852 */ 1853 int 1854 libscf_clear_runlevel(scf_propertygroup_t *pg, const char *milestone) 1855 { 1856 scf_handle_t *h; 1857 scf_transaction_t *tx; 1858 scf_transaction_entry_t *e_rl, *e_ms; 1859 scf_value_t *val; 1860 scf_error_t serr; 1861 boolean_t isempty = B_TRUE; 1862 int ret = 0, r; 1863 1864 h = scf_pg_handle(pg); 1865 tx = safe_scf_transaction_create(h); 1866 e_rl = safe_scf_entry_create(h); 1867 e_ms = safe_scf_entry_create(h); 1868 val = safe_scf_value_create(h); 1869 1870 if (milestone) { 1871 r = scf_value_set_astring(val, milestone); 1872 assert(r == 0); 1873 } 1874 1875 for (;;) { 1876 if (scf_transaction_start(tx, pg) != 0) { 1877 switch (scf_error()) { 1878 case SCF_ERROR_CONNECTION_BROKEN: 1879 default: 1880 ret = ECONNABORTED; 1881 goto out; 1882 1883 case SCF_ERROR_DELETED: 1884 ret = ECANCELED; 1885 goto out; 1886 1887 case SCF_ERROR_PERMISSION_DENIED: 1888 ret = EPERM; 1889 goto out; 1890 1891 case SCF_ERROR_BACKEND_ACCESS: 1892 ret = EACCES; 1893 goto out; 1894 1895 case SCF_ERROR_BACKEND_READONLY: 1896 ret = EROFS; 1897 goto out; 1898 1899 case SCF_ERROR_NOT_SET: 1900 bad_error("scf_transaction_start", scf_error()); 1901 } 1902 } 1903 1904 if (scf_transaction_property_delete(tx, e_rl, 1905 "runlevel") == 0) { 1906 isempty = B_FALSE; 1907 } else { 1908 switch (scf_error()) { 1909 case SCF_ERROR_CONNECTION_BROKEN: 1910 default: 1911 ret = ECONNABORTED; 1912 goto out; 1913 1914 case SCF_ERROR_DELETED: 1915 ret = ECANCELED; 1916 goto out; 1917 1918 case SCF_ERROR_NOT_FOUND: 1919 break; 1920 1921 case SCF_ERROR_HANDLE_MISMATCH: 1922 case SCF_ERROR_NOT_BOUND: 1923 case SCF_ERROR_INVALID_ARGUMENT: 1924 bad_error("scf_transaction_property_delete", 1925 scf_error()); 1926 } 1927 } 1928 1929 if (milestone) { 1930 ret = transaction_add_set(tx, e_ms, 1931 SCF_PROPERTY_MILESTONE, SCF_TYPE_ASTRING); 1932 switch (ret) { 1933 case 0: 1934 break; 1935 1936 case ECONNABORTED: 1937 case ECANCELED: 1938 goto out; 1939 1940 default: 1941 bad_error("transaction_add_set", ret); 1942 } 1943 1944 isempty = B_FALSE; 1945 1946 r = scf_entry_add_value(e_ms, val); 1947 assert(r == 0); 1948 } 1949 1950 if (isempty) 1951 goto out; 1952 1953 r = scf_transaction_commit(tx); 1954 if (r == 1) 1955 break; 1956 if (r != 0) { 1957 serr = scf_error(); 1958 scf_transaction_reset(tx); 1959 switch (serr) { 1960 case SCF_ERROR_CONNECTION_BROKEN: 1961 ret = ECONNABORTED; 1962 goto out; 1963 1964 case SCF_ERROR_PERMISSION_DENIED: 1965 ret = EPERM; 1966 goto out; 1967 1968 case SCF_ERROR_BACKEND_ACCESS: 1969 ret = EACCES; 1970 goto out; 1971 1972 case SCF_ERROR_BACKEND_READONLY: 1973 ret = EROFS; 1974 goto out; 1975 1976 default: 1977 bad_error("scf_transaction_commit", serr); 1978 } 1979 } 1980 1981 scf_transaction_reset(tx); 1982 1983 if (scf_pg_update(pg) == -1) { 1984 switch (scf_error()) { 1985 case SCF_ERROR_CONNECTION_BROKEN: 1986 ret = ECONNABORTED; 1987 goto out; 1988 1989 case SCF_ERROR_NOT_SET: 1990 ret = ECANCELED; 1991 goto out; 1992 1993 default: 1994 assert(0); 1995 abort(); 1996 } 1997 } 1998 } 1999 2000 out: 2001 scf_transaction_destroy(tx); 2002 scf_entry_destroy(e_rl); 2003 scf_entry_destroy(e_ms); 2004 scf_value_destroy(val); 2005 return (ret); 2006 } 2007 2008 /* 2009 * int libscf_get_template_values(scf_instance_t *, scf_snapshot_t *, 2010 * char **) 2011 * 2012 * Return template values for inst in *common_name suitable for use in 2013 * restarter_inst_t->ri_common_name. Called by restarter_insert_inst(). 2014 * 2015 * Returns 0 on success, ECANCELED if the instance is deleted, ECHILD if 2016 * a value fetch failed for a property, ENOENT if the instance has no 2017 * tm_common_name property group or the property group is deleted, and 2018 * ECONNABORTED if the repository connection is broken. 2019 */ 2020 int 2021 libscf_get_template_values(scf_instance_t *inst, scf_snapshot_t *snap, 2022 char **common_name, char **c_common_name) 2023 { 2024 scf_handle_t *h; 2025 scf_propertygroup_t *pg = NULL; 2026 scf_property_t *prop = NULL; 2027 int ret = 0, r; 2028 char *cname = startd_alloc(max_scf_value_size); 2029 char *c_cname = startd_alloc(max_scf_value_size); 2030 2031 h = scf_instance_handle(inst); 2032 pg = safe_scf_pg_create(h); 2033 prop = safe_scf_property_create(h); 2034 2035 /* 2036 * The tm_common_name property group, as with all template property 2037 * groups, is optional. 2038 */ 2039 if (scf_instance_get_pg_composed(inst, snap, SCF_PG_TM_COMMON_NAME, pg) 2040 == -1) { 2041 switch (scf_error()) { 2042 case SCF_ERROR_DELETED: 2043 ret = ECANCELED; 2044 goto template_values_out; 2045 2046 case SCF_ERROR_NOT_FOUND: 2047 goto template_values_out; 2048 2049 case SCF_ERROR_CONNECTION_BROKEN: 2050 default: 2051 ret = ECONNABORTED; 2052 goto template_values_out; 2053 2054 case SCF_ERROR_INVALID_ARGUMENT: 2055 case SCF_ERROR_HANDLE_MISMATCH: 2056 case SCF_ERROR_NOT_SET: 2057 bad_error("scf_instance_get_pg_composed", scf_error()); 2058 } 2059 } 2060 2061 /* 2062 * The name we wish uses the current locale name as the property name. 2063 */ 2064 if (st->st_locale != NULL) { 2065 if (scf_pg_get_property(pg, st->st_locale, prop) == -1) { 2066 startd_free(cname, max_scf_value_size); 2067 2068 switch (scf_error()) { 2069 case SCF_ERROR_DELETED: 2070 case SCF_ERROR_NOT_FOUND: 2071 break; 2072 2073 case SCF_ERROR_CONNECTION_BROKEN: 2074 default: 2075 ret = ECONNABORTED; 2076 goto template_values_out; 2077 2078 case SCF_ERROR_INVALID_ARGUMENT: 2079 case SCF_ERROR_HANDLE_MISMATCH: 2080 case SCF_ERROR_NOT_SET: 2081 bad_error("scf_pg_get_property", scf_error()); 2082 } 2083 } else { 2084 if ((r = libscf_read_single_astring(h, prop, &cname)) != 2085 0) { 2086 if (r != LIBSCF_PROPERTY_ABSENT) 2087 ret = ECHILD; 2088 startd_free(cname, max_scf_value_size); 2089 goto template_values_out; 2090 } 2091 2092 *common_name = cname; 2093 } 2094 } 2095 2096 /* 2097 * Also pull out the C locale name, as a fallback for the case where 2098 * service offers no localized name. 2099 */ 2100 if (scf_pg_get_property(pg, "C", prop) == -1) { 2101 startd_free(c_cname, max_scf_value_size); 2102 2103 switch (scf_error()) { 2104 case SCF_ERROR_DELETED: 2105 ret = ENOENT; 2106 goto template_values_out; 2107 2108 case SCF_ERROR_NOT_FOUND: 2109 break; 2110 2111 case SCF_ERROR_CONNECTION_BROKEN: 2112 default: 2113 ret = ECONNABORTED; 2114 goto template_values_out; 2115 2116 case SCF_ERROR_INVALID_ARGUMENT: 2117 case SCF_ERROR_HANDLE_MISMATCH: 2118 case SCF_ERROR_NOT_SET: 2119 bad_error("scf_pg_get_property", scf_error()); 2120 } 2121 } else { 2122 if ((r = libscf_read_single_astring(h, prop, &c_cname)) != 0) { 2123 if (r != LIBSCF_PROPERTY_ABSENT) 2124 ret = ECHILD; 2125 goto template_values_out; 2126 } 2127 2128 *c_common_name = c_cname; 2129 } 2130 2131 2132 template_values_out: 2133 scf_property_destroy(prop); 2134 scf_pg_destroy(pg); 2135 2136 return (ret); 2137 } 2138 2139 /* 2140 * int libscf_get_startd_properties(scf_handle_t *, scf_instance_t *, 2141 * scf_snapshot_t *, uint_t *, char **) 2142 * 2143 * Return startd settings for inst in *flags suitable for use in 2144 * restarter_inst_t->ri_flags. Called by restarter_insert_inst(). 2145 * 2146 * Returns 0 on success, ECANCELED if the instance is deleted, ECHILD if 2147 * a value fetch failed for a property, ENOENT if the instance has no 2148 * general property group or the property group is deleted, and 2149 * ECONNABORTED if the repository connection is broken. 2150 */ 2151 int 2152 libscf_get_startd_properties(scf_instance_t *inst, 2153 scf_snapshot_t *snap, uint_t *flags, char **prefixp) 2154 { 2155 scf_handle_t *h; 2156 scf_propertygroup_t *pg = NULL; 2157 scf_property_t *prop = NULL; 2158 int style = RINST_CONTRACT; 2159 char *style_str = startd_alloc(max_scf_value_size); 2160 int ret = 0, r; 2161 2162 h = scf_instance_handle(inst); 2163 pg = safe_scf_pg_create(h); 2164 prop = safe_scf_property_create(h); 2165 2166 /* 2167 * The startd property group is optional. 2168 */ 2169 if (scf_instance_get_pg_composed(inst, snap, SCF_PG_STARTD, pg) == -1) { 2170 switch (scf_error()) { 2171 case SCF_ERROR_DELETED: 2172 ret = ECANCELED; 2173 goto instance_flags_out; 2174 2175 case SCF_ERROR_NOT_FOUND: 2176 ret = ENOENT; 2177 goto instance_flags_out; 2178 2179 case SCF_ERROR_CONNECTION_BROKEN: 2180 default: 2181 ret = ECONNABORTED; 2182 goto instance_flags_out; 2183 2184 case SCF_ERROR_INVALID_ARGUMENT: 2185 case SCF_ERROR_HANDLE_MISMATCH: 2186 case SCF_ERROR_NOT_SET: 2187 bad_error("scf_instance_get_pg_composed", scf_error()); 2188 } 2189 } 2190 2191 /* 2192 * 1. Duration property. 2193 */ 2194 if (scf_pg_get_property(pg, SCF_PROPERTY_DURATION, prop) == -1) { 2195 switch (scf_error()) { 2196 case SCF_ERROR_DELETED: 2197 ret = ENOENT; 2198 goto instance_flags_out; 2199 2200 case SCF_ERROR_NOT_FOUND: 2201 break; 2202 2203 case SCF_ERROR_CONNECTION_BROKEN: 2204 default: 2205 ret = ECONNABORTED; 2206 goto instance_flags_out; 2207 2208 case SCF_ERROR_INVALID_ARGUMENT: 2209 case SCF_ERROR_HANDLE_MISMATCH: 2210 case SCF_ERROR_NOT_SET: 2211 bad_error("scf_pg_get_property", scf_error()); 2212 } 2213 } else { 2214 errno = 0; 2215 if ((r = libscf_read_single_astring(h, prop, &style_str)) 2216 != 0) { 2217 if (r != LIBSCF_PROPERTY_ABSENT) 2218 ret = ECHILD; 2219 goto instance_flags_out; 2220 } 2221 2222 if (strcmp(style_str, "child") == 0) 2223 style = RINST_WAIT; 2224 else if (strcmp(style_str, "transient") == 0) 2225 style = RINST_TRANSIENT; 2226 } 2227 2228 /* 2229 * 2. utmpx prefix property. 2230 */ 2231 if (scf_pg_get_property(pg, SCF_PROPERTY_UTMPX_PREFIX, prop) == 0) { 2232 errno = 0; 2233 if ((r = libscf_read_single_astring(h, prop, prefixp)) != 0) { 2234 if (r != LIBSCF_PROPERTY_ABSENT) 2235 ret = ECHILD; 2236 goto instance_flags_out; 2237 } 2238 } else { 2239 switch (scf_error()) { 2240 case SCF_ERROR_DELETED: 2241 ret = ENOENT; 2242 goto instance_flags_out; 2243 2244 case SCF_ERROR_NOT_FOUND: 2245 goto instance_flags_out; 2246 2247 case SCF_ERROR_CONNECTION_BROKEN: 2248 default: 2249 ret = ECONNABORTED; 2250 goto instance_flags_out; 2251 2252 case SCF_ERROR_INVALID_ARGUMENT: 2253 case SCF_ERROR_HANDLE_MISMATCH: 2254 case SCF_ERROR_NOT_SET: 2255 bad_error("scf_pg_get_property", scf_error()); 2256 } 2257 } 2258 2259 instance_flags_out: 2260 startd_free(style_str, max_scf_value_size); 2261 *flags = (*flags & ~RINST_STYLE_MASK) | style; 2262 2263 scf_property_destroy(prop); 2264 scf_pg_destroy(pg); 2265 2266 return (ret); 2267 } 2268 2269 /* 2270 * int libscf_read_method_ids(scf_handle_t *, scf_instance_t *, ctid_t *, 2271 * ctid_t *, pid_t *) 2272 * 2273 * Sets given id_t variables to primary and transient contract IDs and start 2274 * PID. Returns 0, ECONNABORTED, and ECANCELED. 2275 */ 2276 int 2277 libscf_read_method_ids(scf_handle_t *h, scf_instance_t *inst, const char *fmri, 2278 ctid_t *primary, ctid_t *transient, pid_t *start_pid) 2279 { 2280 scf_propertygroup_t *pg = NULL; 2281 scf_property_t *prop = NULL; 2282 scf_value_t *val = NULL; 2283 uint64_t p, t; 2284 int ret = 0; 2285 2286 *primary = 0; 2287 *transient = 0; 2288 *start_pid = -1; 2289 2290 pg = safe_scf_pg_create(h); 2291 prop = safe_scf_property_create(h); 2292 val = safe_scf_value_create(h); 2293 2294 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) == -1) { 2295 switch (scf_error()) { 2296 case SCF_ERROR_CONNECTION_BROKEN: 2297 default: 2298 ret = ECONNABORTED; 2299 goto read_id_err; 2300 2301 case SCF_ERROR_DELETED: 2302 ret = ECANCELED; 2303 goto read_id_err; 2304 2305 case SCF_ERROR_NOT_FOUND: 2306 goto read_id_err; 2307 2308 case SCF_ERROR_NOT_SET: 2309 bad_error("scf_instance_get_pg", scf_error()); 2310 } 2311 } 2312 2313 ret = get_count(pg, SCF_PROPERTY_CONTRACT, &p); 2314 switch (ret) { 2315 case 0: 2316 break; 2317 2318 case EINVAL: 2319 log_error(LOG_NOTICE, 2320 "%s: Ignoring %s/%s: multivalued or not of type count\n", 2321 fmri, SCF_PG_RESTARTER, SCF_PROPERTY_CONTRACT); 2322 /* FALLTHROUGH */ 2323 case ENOENT: 2324 ret = 0; 2325 goto read_trans; 2326 2327 case ECONNABORTED: 2328 case ECANCELED: 2329 goto read_id_err; 2330 2331 default: 2332 bad_error("get_count", ret); 2333 } 2334 2335 *primary = p; 2336 2337 read_trans: 2338 ret = get_count(pg, SCF_PROPERTY_TRANSIENT_CONTRACT, &t); 2339 switch (ret) { 2340 case 0: 2341 break; 2342 2343 case EINVAL: 2344 log_error(LOG_NOTICE, 2345 "%s: Ignoring %s/%s: multivalued or not of type count\n", 2346 fmri, SCF_PG_RESTARTER, SCF_PROPERTY_TRANSIENT_CONTRACT); 2347 /* FALLTHROUGH */ 2348 2349 case ENOENT: 2350 ret = 0; 2351 goto read_pid_only; 2352 2353 case ECONNABORTED: 2354 case ECANCELED: 2355 goto read_id_err; 2356 2357 default: 2358 bad_error("get_count", ret); 2359 } 2360 2361 *transient = t; 2362 2363 read_pid_only: 2364 ret = get_count(pg, SCF_PROPERTY_START_PID, &p); 2365 switch (ret) { 2366 case 0: 2367 break; 2368 2369 case EINVAL: 2370 log_error(LOG_NOTICE, 2371 "%s: Ignoring %s/%s: multivalued or not of type count\n", 2372 fmri, SCF_PG_RESTARTER, SCF_PROPERTY_START_PID); 2373 /* FALLTHROUGH */ 2374 case ENOENT: 2375 ret = 0; 2376 goto read_id_err; 2377 2378 case ECONNABORTED: 2379 case ECANCELED: 2380 goto read_id_err; 2381 2382 default: 2383 bad_error("get_count", ret); 2384 } 2385 2386 *start_pid = p; 2387 2388 read_id_err: 2389 scf_value_destroy(val); 2390 scf_property_destroy(prop); 2391 scf_pg_destroy(pg); 2392 return (ret); 2393 } 2394 2395 /* 2396 * Returns with 2397 * 0 - success 2398 * ECONNABORTED - repository connection broken 2399 * - unknown libscf error 2400 * ECANCELED - s_inst was deleted 2401 * EPERM 2402 * EACCES 2403 * EROFS 2404 */ 2405 int 2406 libscf_write_start_pid(scf_instance_t *s_inst, pid_t pid) 2407 { 2408 scf_handle_t *h; 2409 scf_transaction_entry_t *t_pid; 2410 scf_value_t *v_pid; 2411 scf_propertygroup_t *pg; 2412 int ret = 0; 2413 2414 h = scf_instance_handle(s_inst); 2415 2416 pg = safe_scf_pg_create(h); 2417 t_pid = safe_scf_entry_create(h); 2418 v_pid = safe_scf_value_create(h); 2419 2420 get_pg: 2421 ret = libscf_inst_get_or_add_pg(s_inst, SCF_PG_RESTARTER, 2422 SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg); 2423 switch (ret) { 2424 case 0: 2425 break; 2426 2427 case ECONNABORTED: 2428 case ECANCELED: 2429 case EPERM: 2430 case EACCES: 2431 case EROFS: 2432 goto write_start_err; 2433 2434 default: 2435 bad_error("libscf_inst_get_or_add_pg", ret); 2436 } 2437 2438 scf_value_set_count(v_pid, pid); 2439 2440 ret = pg_set_prop_value(pg, SCF_PROPERTY_START_PID, v_pid); 2441 switch (ret) { 2442 case 0: 2443 case ECONNABORTED: 2444 case EPERM: 2445 case EACCES: 2446 case EROFS: 2447 break; 2448 2449 case ECANCELED: 2450 goto get_pg; 2451 2452 default: 2453 bad_error("pg_set_prop_value", ret); 2454 } 2455 2456 write_start_err: 2457 scf_entry_destroy(t_pid); 2458 scf_value_destroy(v_pid); 2459 scf_pg_destroy(pg); 2460 2461 return (ret); 2462 } 2463 2464 /* 2465 * Add a property indicating the instance log file. If the dir is 2466 * equal to LOG_PREFIX_EARLY, then the property restarter/alt_logfile 2467 * of the instance is used; otherwise, restarter/logfile is used. 2468 * 2469 * Returns 2470 * 0 - success 2471 * ECONNABORTED 2472 * ECANCELED 2473 * EPERM 2474 * EACCES 2475 * EROFS 2476 * EAGAIN 2477 */ 2478 int 2479 libscf_note_method_log(scf_instance_t *inst, const char *dir, const char *file) 2480 { 2481 scf_handle_t *h; 2482 scf_value_t *v; 2483 scf_propertygroup_t *pg; 2484 int ret = 0; 2485 char *logname; 2486 const char *propname; 2487 2488 h = scf_instance_handle(inst); 2489 pg = safe_scf_pg_create(h); 2490 v = safe_scf_value_create(h); 2491 2492 logname = uu_msprintf("%s%s", dir, file); 2493 2494 if (logname == NULL) { 2495 ret = errno; 2496 goto out; 2497 } 2498 2499 ret = libscf_inst_get_or_add_pg(inst, SCF_PG_RESTARTER, 2500 SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg); 2501 switch (ret) { 2502 case 0: 2503 break; 2504 2505 case ECONNABORTED: 2506 case ECANCELED: 2507 case EPERM: 2508 case EACCES: 2509 case EROFS: 2510 goto out; 2511 2512 default: 2513 bad_error("libscf_inst_get_or_add_pg", ret); 2514 } 2515 2516 (void) scf_value_set_astring(v, logname); 2517 2518 if (strcmp(LOG_PREFIX_EARLY, dir) == 0) 2519 propname = SCF_PROPERTY_ALT_LOGFILE; 2520 else 2521 propname = SCF_PROPERTY_LOGFILE; 2522 2523 ret = pg_set_prop_value(pg, propname, v); 2524 switch (ret) { 2525 case 0: 2526 case ECONNABORTED: 2527 case ECANCELED: 2528 case EPERM: 2529 case EACCES: 2530 case EROFS: 2531 break; 2532 2533 default: 2534 bad_error("pg_set_prop_value", ret); 2535 } 2536 2537 out: 2538 scf_pg_destroy(pg); 2539 scf_value_destroy(v); 2540 uu_free(logname); 2541 return (ret); 2542 } 2543 2544 /* 2545 * Returns 2546 * 0 - success 2547 * ENAMETOOLONG - name is too long 2548 * ECONNABORTED 2549 * ECANCELED 2550 * EPERM 2551 * EACCES 2552 * EROFS 2553 */ 2554 int 2555 libscf_write_method_status(scf_instance_t *s_inst, const char *name, 2556 int status) 2557 { 2558 scf_handle_t *h; 2559 scf_transaction_t *tx; 2560 scf_transaction_entry_t *e_time, *e_stat; 2561 scf_value_t *v_time, *v_stat; 2562 scf_propertygroup_t *pg; 2563 int ret = 0, r; 2564 char pname[30]; 2565 struct timeval tv; 2566 scf_error_t scfe; 2567 2568 if (strlen(name) + sizeof ("_method_waitstatus") > sizeof (pname)) 2569 return (ENAMETOOLONG); 2570 2571 h = scf_instance_handle(s_inst); 2572 2573 pg = safe_scf_pg_create(h); 2574 tx = safe_scf_transaction_create(h); 2575 e_time = safe_scf_entry_create(h); 2576 v_time = safe_scf_value_create(h); 2577 e_stat = safe_scf_entry_create(h); 2578 v_stat = safe_scf_value_create(h); 2579 2580 get_pg: 2581 ret = libscf_inst_get_or_add_pg(s_inst, SCF_PG_RESTARTER, 2582 SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg); 2583 switch (ret) { 2584 case 0: 2585 break; 2586 2587 case ECONNABORTED: 2588 case ECANCELED: 2589 case EPERM: 2590 case EACCES: 2591 case EROFS: 2592 goto out; 2593 2594 default: 2595 bad_error("libscf_inst_get_or_add_pg", ret); 2596 } 2597 2598 (void) gettimeofday(&tv, NULL); 2599 2600 r = scf_value_set_time(v_time, tv.tv_sec, tv.tv_usec * 1000); 2601 assert(r == 0); 2602 2603 scf_value_set_integer(v_stat, status); 2604 2605 for (;;) { 2606 if (scf_transaction_start(tx, pg) != 0) { 2607 switch (scf_error()) { 2608 case SCF_ERROR_CONNECTION_BROKEN: 2609 default: 2610 ret = ECONNABORTED; 2611 goto out; 2612 2613 case SCF_ERROR_DELETED: 2614 ret = ECANCELED; 2615 goto out; 2616 2617 case SCF_ERROR_PERMISSION_DENIED: 2618 ret = EPERM; 2619 goto out; 2620 2621 case SCF_ERROR_BACKEND_ACCESS: 2622 ret = EACCES; 2623 goto out; 2624 2625 case SCF_ERROR_BACKEND_READONLY: 2626 ret = EROFS; 2627 goto out; 2628 2629 case SCF_ERROR_NOT_SET: 2630 bad_error("scf_transaction_start", ret); 2631 } 2632 } 2633 2634 (void) snprintf(pname, sizeof (pname), "%s_method_timestamp", 2635 name); 2636 ret = transaction_add_set(tx, e_time, pname, SCF_TYPE_TIME); 2637 switch (ret) { 2638 case 0: 2639 break; 2640 2641 case ECONNABORTED: 2642 case ECANCELED: 2643 goto out; 2644 2645 default: 2646 bad_error("transaction_add_set", ret); 2647 } 2648 2649 r = scf_entry_add_value(e_time, v_time); 2650 assert(r == 0); 2651 2652 (void) snprintf(pname, sizeof (pname), "%s_method_waitstatus", 2653 name); 2654 ret = transaction_add_set(tx, e_stat, pname, SCF_TYPE_INTEGER); 2655 switch (ret) { 2656 case 0: 2657 break; 2658 2659 case ECONNABORTED: 2660 case ECANCELED: 2661 goto out; 2662 2663 default: 2664 bad_error("transaction_add_set", ret); 2665 } 2666 2667 r = scf_entry_add_value(e_stat, v_stat); 2668 if (r != 0) 2669 bad_error("scf_entry_add_value", scf_error()); 2670 2671 r = scf_transaction_commit(tx); 2672 if (r == 1) 2673 break; 2674 if (r != 0) { 2675 scfe = scf_error(); 2676 scf_transaction_reset_all(tx); 2677 switch (scfe) { 2678 case SCF_ERROR_CONNECTION_BROKEN: 2679 default: 2680 ret = ECONNABORTED; 2681 goto out; 2682 2683 case SCF_ERROR_DELETED: 2684 ret = ECANCELED; 2685 goto out; 2686 2687 case SCF_ERROR_PERMISSION_DENIED: 2688 ret = EPERM; 2689 goto out; 2690 2691 case SCF_ERROR_BACKEND_ACCESS: 2692 ret = EACCES; 2693 goto out; 2694 2695 case SCF_ERROR_BACKEND_READONLY: 2696 ret = EROFS; 2697 goto out; 2698 2699 case SCF_ERROR_NOT_SET: 2700 bad_error("scf_transaction_commit", scfe); 2701 } 2702 } 2703 2704 scf_transaction_reset_all(tx); 2705 2706 if (scf_pg_update(pg) == -1) { 2707 switch (scf_error()) { 2708 case SCF_ERROR_CONNECTION_BROKEN: 2709 default: 2710 ret = ECONNABORTED; 2711 goto out; 2712 2713 case SCF_ERROR_DELETED: 2714 ret = ECANCELED; 2715 goto out; 2716 2717 case SCF_ERROR_NOT_SET: 2718 bad_error("scf_pg_update", scf_error()); 2719 } 2720 } 2721 } 2722 2723 out: 2724 scf_transaction_destroy(tx); 2725 scf_entry_destroy(e_time); 2726 scf_value_destroy(v_time); 2727 scf_entry_destroy(e_stat); 2728 scf_value_destroy(v_stat); 2729 scf_pg_destroy(pg); 2730 2731 return (ret); 2732 } 2733 2734 /* 2735 * Call dgraph_add_instance() for each instance in the repository. 2736 */ 2737 void 2738 libscf_populate_graph(scf_handle_t *h) 2739 { 2740 scf_scope_t *scope; 2741 scf_service_t *svc; 2742 scf_instance_t *inst; 2743 scf_iter_t *svc_iter; 2744 scf_iter_t *inst_iter; 2745 int ret; 2746 2747 scope = safe_scf_scope_create(h); 2748 svc = safe_scf_service_create(h); 2749 inst = safe_scf_instance_create(h); 2750 svc_iter = safe_scf_iter_create(h); 2751 inst_iter = safe_scf_iter_create(h); 2752 2753 if ((ret = scf_handle_get_local_scope(h, scope)) != 2754 SCF_SUCCESS) 2755 uu_die("retrieving local scope failed: %d\n", ret); 2756 2757 if (scf_iter_scope_services(svc_iter, scope) == -1) 2758 uu_die("walking local scope's services failed\n"); 2759 2760 while (scf_iter_next_service(svc_iter, svc) > 0) { 2761 if (scf_iter_service_instances(inst_iter, svc) == -1) 2762 uu_die("unable to walk service's instances"); 2763 2764 while (scf_iter_next_instance(inst_iter, inst) > 0) { 2765 char *fmri; 2766 2767 if (libscf_instance_get_fmri(inst, &fmri) == 0) { 2768 int err; 2769 2770 err = dgraph_add_instance(fmri, inst, B_TRUE); 2771 if (err != 0 && err != EEXIST) 2772 log_error(LOG_WARNING, 2773 "Failed to add %s (%s).\n", fmri, 2774 strerror(err)); 2775 startd_free(fmri, max_scf_fmri_size); 2776 } 2777 } 2778 } 2779 2780 scf_iter_destroy(inst_iter); 2781 scf_iter_destroy(svc_iter); 2782 scf_instance_destroy(inst); 2783 scf_service_destroy(svc); 2784 scf_scope_destroy(scope); 2785 } 2786 2787 /* 2788 * Monitors get handled differently since there can be multiple of them. 2789 * 2790 * Returns exec string on success. If method not defined, returns 2791 * LIBSCF_PGROUP_ABSENT; if exec property missing, returns 2792 * LIBSCF_PROPERTY_ABSENT. Returns LIBSCF_PROPERTY_ERROR on other failures. 2793 */ 2794 char * 2795 libscf_get_method(scf_handle_t *h, int type, restarter_inst_t *inst, 2796 scf_snapshot_t *snap, method_restart_t *restart_on, uint_t *cte_mask, 2797 uint8_t *need_sessionp, uint64_t *timeout, uint8_t *timeout_retry) 2798 { 2799 scf_instance_t *scf_inst = NULL; 2800 scf_propertygroup_t *pg = NULL, *pg_startd = NULL; 2801 scf_property_t *prop = NULL; 2802 const char *name; 2803 char *method = startd_alloc(max_scf_value_size); 2804 char *ig = startd_alloc(max_scf_value_size); 2805 char *restart = startd_alloc(max_scf_value_size); 2806 char *ret; 2807 int error = 0, r; 2808 2809 scf_inst = safe_scf_instance_create(h); 2810 pg = safe_scf_pg_create(h); 2811 pg_startd = safe_scf_pg_create(h); 2812 prop = safe_scf_property_create(h); 2813 2814 ret = NULL; 2815 2816 *restart_on = METHOD_RESTART_UNKNOWN; 2817 2818 switch (type) { 2819 case METHOD_START: 2820 name = "start"; 2821 break; 2822 case METHOD_STOP: 2823 name = "stop"; 2824 break; 2825 case METHOD_REFRESH: 2826 name = "refresh"; 2827 break; 2828 default: 2829 error = LIBSCF_PROPERTY_ERROR; 2830 goto get_method_cleanup; 2831 } 2832 2833 if (scf_handle_decode_fmri(h, inst->ri_i.i_fmri, NULL, NULL, scf_inst, 2834 NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) { 2835 log_error(LOG_WARNING, 2836 "%s: get_method decode instance FMRI failed: %s\n", 2837 inst->ri_i.i_fmri, scf_strerror(scf_error())); 2838 error = LIBSCF_PROPERTY_ERROR; 2839 goto get_method_cleanup; 2840 } 2841 2842 if (scf_instance_get_pg_composed(scf_inst, snap, name, pg) == -1) { 2843 if (scf_error() == SCF_ERROR_NOT_FOUND) 2844 error = LIBSCF_PGROUP_ABSENT; 2845 else 2846 error = LIBSCF_PROPERTY_ERROR; 2847 goto get_method_cleanup; 2848 } 2849 2850 if (scf_pg_get_property(pg, SCF_PROPERTY_EXEC, prop) == -1) { 2851 if (scf_error() == SCF_ERROR_NOT_FOUND) 2852 error = LIBSCF_PROPERTY_ABSENT; 2853 else 2854 error = LIBSCF_PROPERTY_ERROR; 2855 goto get_method_cleanup; 2856 } 2857 2858 error = libscf_read_single_astring(h, prop, &method); 2859 if (error != 0) { 2860 log_error(LOG_WARNING, 2861 "%s: get_method failed: can't get a single astring " 2862 "from %s/%s\n", inst->ri_i.i_fmri, name, SCF_PROPERTY_EXEC); 2863 goto get_method_cleanup; 2864 } 2865 2866 error = expand_method_tokens(method, scf_inst, snap, type, &ret); 2867 if (error != 0) { 2868 log_instance(inst, B_TRUE, "Could not expand method tokens " 2869 "in \"%s\": %s", method, ret); 2870 error = LIBSCF_PROPERTY_ERROR; 2871 goto get_method_cleanup; 2872 } 2873 2874 r = get_count(pg, SCF_PROPERTY_TIMEOUT, timeout); 2875 switch (r) { 2876 case 0: 2877 break; 2878 2879 case ECONNABORTED: 2880 error = LIBSCF_PROPERTY_ERROR; 2881 goto get_method_cleanup; 2882 2883 case EINVAL: 2884 log_instance(inst, B_TRUE, "%s/%s is multi-valued or not of " 2885 "type count. Using infinite timeout.", name, 2886 SCF_PROPERTY_TIMEOUT); 2887 /* FALLTHROUGH */ 2888 case ECANCELED: 2889 case ENOENT: 2890 *timeout = METHOD_TIMEOUT_INFINITE; 2891 break; 2892 2893 default: 2894 bad_error("get_count", r); 2895 } 2896 2897 /* Both 0 and -1 (ugh) are considered infinite timeouts. */ 2898 if (*timeout == -1 || *timeout == 0) 2899 *timeout = METHOD_TIMEOUT_INFINITE; 2900 2901 if (scf_instance_get_pg_composed(scf_inst, snap, SCF_PG_STARTD, 2902 pg_startd) == -1) { 2903 switch (scf_error()) { 2904 case SCF_ERROR_CONNECTION_BROKEN: 2905 case SCF_ERROR_DELETED: 2906 error = LIBSCF_PROPERTY_ERROR; 2907 goto get_method_cleanup; 2908 2909 case SCF_ERROR_NOT_FOUND: 2910 *cte_mask = 0; 2911 break; 2912 2913 case SCF_ERROR_INVALID_ARGUMENT: 2914 case SCF_ERROR_HANDLE_MISMATCH: 2915 case SCF_ERROR_NOT_BOUND: 2916 case SCF_ERROR_NOT_SET: 2917 bad_error("scf_instance_get_pg_composed", scf_error()); 2918 } 2919 } else { 2920 if (scf_pg_get_property(pg_startd, SCF_PROPERTY_IGNORE, 2921 prop) == -1) { 2922 if (scf_error() == SCF_ERROR_NOT_FOUND) 2923 *cte_mask = 0; 2924 else { 2925 error = LIBSCF_PROPERTY_ERROR; 2926 goto get_method_cleanup; 2927 } 2928 } else { 2929 error = libscf_read_single_astring(h, prop, &ig); 2930 if (error != 0) { 2931 log_error(LOG_WARNING, 2932 "%s: get_method failed: can't get a single " 2933 "astring from %s/%s\n", inst->ri_i.i_fmri, 2934 name, SCF_PROPERTY_IGNORE); 2935 goto get_method_cleanup; 2936 } 2937 2938 if (strcmp(ig, "core") == 0) 2939 *cte_mask = CT_PR_EV_CORE; 2940 else if (strcmp(ig, "signal") == 0) 2941 *cte_mask = CT_PR_EV_SIGNAL; 2942 else if (strcmp(ig, "core,signal") == 0 || 2943 strcmp(ig, "signal,core") == 0) 2944 *cte_mask = CT_PR_EV_CORE | CT_PR_EV_SIGNAL; 2945 else 2946 *cte_mask = 0; 2947 } 2948 2949 r = get_boolean(pg_startd, SCF_PROPERTY_NEED_SESSION, 2950 need_sessionp); 2951 switch (r) { 2952 case 0: 2953 break; 2954 2955 case ECONNABORTED: 2956 error = LIBSCF_PROPERTY_ERROR; 2957 goto get_method_cleanup; 2958 2959 case ECANCELED: 2960 case ENOENT: 2961 case EINVAL: 2962 *need_sessionp = 0; 2963 break; 2964 2965 default: 2966 bad_error("get_boolean", r); 2967 } 2968 2969 /* 2970 * Determine whether service has overriden retry after 2971 * method timeout. Default to retry if no value is 2972 * specified. 2973 */ 2974 r = get_boolean(pg_startd, SCF_PROPERTY_TIMEOUT_RETRY, 2975 timeout_retry); 2976 switch (r) { 2977 case 0: 2978 break; 2979 2980 case ECONNABORTED: 2981 error = LIBSCF_PROPERTY_ERROR; 2982 goto get_method_cleanup; 2983 2984 case ECANCELED: 2985 case ENOENT: 2986 case EINVAL: 2987 *timeout_retry = 1; 2988 break; 2989 2990 default: 2991 bad_error("get_boolean", r); 2992 } 2993 } 2994 2995 if (type != METHOD_START) 2996 goto get_method_cleanup; 2997 2998 /* Only start methods need to honor the restart_on property. */ 2999 3000 if (scf_pg_get_property(pg, SCF_PROPERTY_RESTART_ON, prop) == -1) { 3001 if (scf_error() == SCF_ERROR_NOT_FOUND) 3002 *restart_on = METHOD_RESTART_ALL; 3003 else 3004 error = LIBSCF_PROPERTY_ERROR; 3005 goto get_method_cleanup; 3006 } 3007 3008 error = libscf_read_single_astring(h, prop, &restart); 3009 if (error != 0) { 3010 log_error(LOG_WARNING, 3011 "%s: get_method failed: can't get a single astring " 3012 "from %s/%s\n", inst->ri_i.i_fmri, name, 3013 SCF_PROPERTY_RESTART_ON); 3014 goto get_method_cleanup; 3015 } 3016 3017 if (strcmp(restart, "all") == 0) 3018 *restart_on = METHOD_RESTART_ALL; 3019 else if (strcmp(restart, "external_fault") == 0) 3020 *restart_on = METHOD_RESTART_EXTERNAL_FAULT; 3021 else if (strcmp(restart, "any_fault") == 0) 3022 *restart_on = METHOD_RESTART_ANY_FAULT; 3023 3024 get_method_cleanup: 3025 startd_free(ig, max_scf_value_size); 3026 startd_free(method, max_scf_value_size); 3027 startd_free(restart, max_scf_value_size); 3028 3029 scf_instance_destroy(scf_inst); 3030 scf_pg_destroy(pg); 3031 scf_pg_destroy(pg_startd); 3032 scf_property_destroy(prop); 3033 3034 if (error != 0 && ret != NULL) { 3035 free(ret); 3036 ret = NULL; 3037 } 3038 3039 errno = error; 3040 return (ret); 3041 } 3042 3043 /* 3044 * Returns 1 if we've reached the fault threshold 3045 */ 3046 int 3047 update_fault_count(restarter_inst_t *inst, int type) 3048 { 3049 assert(type == FAULT_COUNT_INCR || type == FAULT_COUNT_RESET); 3050 3051 if (type == FAULT_COUNT_INCR) { 3052 inst->ri_i.i_fault_count++; 3053 log_framework(LOG_INFO, "%s: Increasing fault count to %d\n", 3054 inst->ri_i.i_fmri, inst->ri_i.i_fault_count); 3055 } 3056 if (type == FAULT_COUNT_RESET) 3057 inst->ri_i.i_fault_count = 0; 3058 3059 if (inst->ri_i.i_fault_count >= FAULT_THRESHOLD) 3060 return (1); 3061 3062 return (0); 3063 } 3064 3065 /* 3066 * int libscf_unset_action() 3067 * Delete any pending timestamps for the specified action which is 3068 * older than the supplied ts. 3069 * 3070 * Returns 0 on success, ECONNABORTED, EACCES, or EPERM on failure. 3071 */ 3072 int 3073 libscf_unset_action(scf_handle_t *h, scf_propertygroup_t *pg, 3074 admin_action_t a, hrtime_t ts) 3075 { 3076 scf_transaction_t *t; 3077 scf_transaction_entry_t *e; 3078 scf_property_t *prop; 3079 scf_value_t *val; 3080 hrtime_t rep_ts; 3081 int ret = 0, r; 3082 3083 t = safe_scf_transaction_create(h); 3084 e = safe_scf_entry_create(h); 3085 prop = safe_scf_property_create(h); 3086 val = safe_scf_value_create(h); 3087 3088 for (;;) { 3089 if (scf_pg_update(pg) == -1) { 3090 switch (scf_error()) { 3091 case SCF_ERROR_CONNECTION_BROKEN: 3092 default: 3093 ret = ECONNABORTED; 3094 goto unset_action_cleanup; 3095 3096 case SCF_ERROR_DELETED: 3097 goto unset_action_cleanup; 3098 3099 case SCF_ERROR_NOT_SET: 3100 assert(0); 3101 abort(); 3102 } 3103 } 3104 3105 if (scf_transaction_start(t, pg) == -1) { 3106 switch (scf_error()) { 3107 case SCF_ERROR_CONNECTION_BROKEN: 3108 default: 3109 ret = ECONNABORTED; 3110 goto unset_action_cleanup; 3111 3112 case SCF_ERROR_DELETED: 3113 goto unset_action_cleanup; 3114 3115 case SCF_ERROR_PERMISSION_DENIED: 3116 ret = EPERM; 3117 goto unset_action_cleanup; 3118 3119 case SCF_ERROR_BACKEND_ACCESS: 3120 case SCF_ERROR_BACKEND_READONLY: 3121 ret = EACCES; 3122 goto unset_action_cleanup; 3123 3124 case SCF_ERROR_IN_USE: 3125 case SCF_ERROR_HANDLE_MISMATCH: 3126 case SCF_ERROR_NOT_SET: 3127 assert(0); 3128 abort(); 3129 } 3130 } 3131 3132 /* Return failure only if the property hasn't been deleted. */ 3133 if (scf_pg_get_property(pg, admin_actions[a], prop) == -1) { 3134 switch (scf_error()) { 3135 case SCF_ERROR_CONNECTION_BROKEN: 3136 default: 3137 ret = ECONNABORTED; 3138 goto unset_action_cleanup; 3139 3140 case SCF_ERROR_DELETED: 3141 case SCF_ERROR_NOT_FOUND: 3142 goto unset_action_cleanup; 3143 3144 case SCF_ERROR_HANDLE_MISMATCH: 3145 case SCF_ERROR_INVALID_ARGUMENT: 3146 case SCF_ERROR_NOT_SET: 3147 assert(0); 3148 abort(); 3149 } 3150 } 3151 3152 if (scf_property_get_value(prop, val) == -1) { 3153 switch (scf_error()) { 3154 case SCF_ERROR_CONNECTION_BROKEN: 3155 default: 3156 ret = ECONNABORTED; 3157 goto unset_action_cleanup; 3158 3159 case SCF_ERROR_DELETED: 3160 case SCF_ERROR_NOT_FOUND: 3161 goto unset_action_cleanup; 3162 3163 case SCF_ERROR_CONSTRAINT_VIOLATED: 3164 /* 3165 * More than one value was associated with 3166 * this property -- this is incorrect. Take 3167 * the opportunity to clean up and clear the 3168 * entire property. 3169 */ 3170 rep_ts = ts; 3171 break; 3172 3173 case SCF_ERROR_NOT_SET: 3174 assert(0); 3175 abort(); 3176 } 3177 } else if (scf_value_get_integer(val, &rep_ts) == -1) { 3178 assert(scf_error() == SCF_ERROR_TYPE_MISMATCH); 3179 rep_ts = 0; 3180 } 3181 3182 /* Repository ts is more current. Don't clear the action. */ 3183 if (rep_ts > ts) 3184 goto unset_action_cleanup; 3185 3186 r = scf_transaction_property_change_type(t, e, 3187 admin_actions[a], SCF_TYPE_INTEGER); 3188 assert(r == 0); 3189 3190 r = scf_transaction_commit(t); 3191 if (r == 1) 3192 break; 3193 3194 if (r != 0) { 3195 switch (scf_error()) { 3196 case SCF_ERROR_CONNECTION_BROKEN: 3197 default: 3198 ret = ECONNABORTED; 3199 goto unset_action_cleanup; 3200 3201 case SCF_ERROR_DELETED: 3202 break; 3203 3204 case SCF_ERROR_PERMISSION_DENIED: 3205 ret = EPERM; 3206 goto unset_action_cleanup; 3207 3208 case SCF_ERROR_BACKEND_ACCESS: 3209 case SCF_ERROR_BACKEND_READONLY: 3210 ret = EACCES; 3211 goto unset_action_cleanup; 3212 3213 case SCF_ERROR_INVALID_ARGUMENT: 3214 case SCF_ERROR_NOT_SET: 3215 assert(0); 3216 abort(); 3217 } 3218 } 3219 3220 scf_transaction_reset(t); 3221 } 3222 3223 unset_action_cleanup: 3224 scf_transaction_destroy(t); 3225 scf_entry_destroy(e); 3226 scf_property_destroy(prop); 3227 scf_value_destroy(val); 3228 3229 return (ret); 3230 } 3231 3232 /* 3233 * Decorates & binds hndl. hndl must be unbound. Returns 3234 * 0 - success 3235 * -1 - repository server is not running 3236 * -1 - repository server is out of resources 3237 */ 3238 static int 3239 handle_decorate_and_bind(scf_handle_t *hndl) 3240 { 3241 scf_value_t *door_dec_value; 3242 3243 door_dec_value = safe_scf_value_create(hndl); 3244 3245 /* 3246 * Decorate if alternate door path set. 3247 */ 3248 if (st->st_door_path) { 3249 if (scf_value_set_astring(door_dec_value, st->st_door_path) != 3250 0) 3251 uu_die("$STARTD_ALT_DOOR is too long.\n"); 3252 3253 if (scf_handle_decorate(hndl, "door_path", door_dec_value) != 0) 3254 bad_error("scf_handle_decorate", scf_error()); 3255 } 3256 3257 scf_value_destroy(door_dec_value); 3258 3259 if (scf_handle_bind(hndl) == 0) 3260 return (0); 3261 3262 switch (scf_error()) { 3263 case SCF_ERROR_NO_SERVER: 3264 case SCF_ERROR_NO_RESOURCES: 3265 return (-1); 3266 3267 case SCF_ERROR_INVALID_ARGUMENT: 3268 case SCF_ERROR_IN_USE: 3269 default: 3270 bad_error("scf_handle_bind", scf_error()); 3271 /* NOTREACHED */ 3272 } 3273 } 3274 3275 scf_handle_t * 3276 libscf_handle_create_bound(scf_version_t v) 3277 { 3278 scf_handle_t *hndl = scf_handle_create(v); 3279 3280 if (hndl == NULL) 3281 return (hndl); 3282 3283 if (handle_decorate_and_bind(hndl) == 0) 3284 return (hndl); 3285 3286 scf_handle_destroy(hndl); 3287 return (NULL); 3288 } 3289 3290 void 3291 libscf_handle_rebind(scf_handle_t *h) 3292 { 3293 (void) scf_handle_unbind(h); 3294 3295 MUTEX_LOCK(&st->st_configd_live_lock); 3296 3297 /* 3298 * Try to rebind the handle before sleeping in case the server isn't 3299 * really dead. 3300 */ 3301 while (handle_decorate_and_bind(h) != 0) 3302 (void) pthread_cond_wait(&st->st_configd_live_cv, 3303 &st->st_configd_live_lock); 3304 3305 MUTEX_UNLOCK(&st->st_configd_live_lock); 3306 } 3307 3308 /* 3309 * Create a handle and try to bind it until it succeeds. Always returns 3310 * a bound handle. 3311 */ 3312 scf_handle_t * 3313 libscf_handle_create_bound_loop() 3314 { 3315 scf_handle_t *h; 3316 3317 while ((h = scf_handle_create(SCF_VERSION)) == NULL) { 3318 /* This should have been caught earlier. */ 3319 assert(scf_error() != SCF_ERROR_VERSION_MISMATCH); 3320 (void) sleep(2); 3321 } 3322 3323 if (handle_decorate_and_bind(h) != 0) 3324 libscf_handle_rebind(h); 3325 3326 return (h); 3327 } 3328 3329 /* 3330 * Call cb for each dependency property group of inst. cb is invoked with 3331 * a pointer to the scf_propertygroup_t and arg. If the repository connection 3332 * is broken, returns ECONNABORTED. If inst is deleted, returns ECANCELED. 3333 * If cb returns non-zero, the walk is stopped and EINTR is returned. 3334 * Otherwise returns 0. 3335 */ 3336 int 3337 walk_dependency_pgs(scf_instance_t *inst, callback_t cb, void *arg) 3338 { 3339 scf_handle_t *h; 3340 scf_snapshot_t *snap; 3341 scf_iter_t *iter; 3342 scf_propertygroup_t *pg; 3343 int r; 3344 3345 h = scf_instance_handle(inst); 3346 3347 iter = safe_scf_iter_create(h); 3348 pg = safe_scf_pg_create(h); 3349 3350 snap = libscf_get_running_snapshot(inst); 3351 3352 if (scf_iter_instance_pgs_typed_composed(iter, inst, snap, 3353 SCF_GROUP_DEPENDENCY) != 0) { 3354 scf_snapshot_destroy(snap); 3355 scf_pg_destroy(pg); 3356 scf_iter_destroy(iter); 3357 switch (scf_error()) { 3358 case SCF_ERROR_CONNECTION_BROKEN: 3359 default: 3360 return (ECONNABORTED); 3361 3362 case SCF_ERROR_DELETED: 3363 return (ECANCELED); 3364 3365 case SCF_ERROR_HANDLE_MISMATCH: 3366 case SCF_ERROR_INVALID_ARGUMENT: 3367 case SCF_ERROR_NOT_SET: 3368 assert(0); 3369 abort(); 3370 } 3371 } 3372 3373 for (;;) { 3374 r = scf_iter_next_pg(iter, pg); 3375 if (r == 0) 3376 break; 3377 if (r == -1) { 3378 assert(scf_error() == SCF_ERROR_CONNECTION_BROKEN); 3379 scf_snapshot_destroy(snap); 3380 scf_pg_destroy(pg); 3381 scf_iter_destroy(iter); 3382 return (ECONNABORTED); 3383 } 3384 3385 r = cb(pg, arg); 3386 3387 if (r != 0) 3388 break; 3389 } 3390 3391 scf_snapshot_destroy(snap); 3392 scf_pg_destroy(pg); 3393 scf_iter_destroy(iter); 3394 3395 return (r == 0 ? 0 : EINTR); 3396 } 3397 3398 /* 3399 * Call cb for each of the string values of prop. cb is invoked with 3400 * a pointer to the string and arg. If the connection to the repository is 3401 * broken, ECONNABORTED is returned. If the property is deleted, ECANCELED is 3402 * returned. If the property does not have astring type, EINVAL is returned. 3403 * If cb returns non-zero, the walk is stopped and EINTR is returned. 3404 * Otherwise 0 is returned. 3405 */ 3406 int 3407 walk_property_astrings(scf_property_t *prop, callback_t cb, void *arg) 3408 { 3409 scf_handle_t *h; 3410 scf_value_t *val; 3411 scf_iter_t *iter; 3412 char *buf; 3413 int r; 3414 ssize_t sz; 3415 3416 if (scf_property_is_type(prop, SCF_TYPE_ASTRING) != 0) { 3417 switch (scf_error()) { 3418 case SCF_ERROR_CONNECTION_BROKEN: 3419 default: 3420 return (ECONNABORTED); 3421 3422 case SCF_ERROR_DELETED: 3423 return (ECANCELED); 3424 3425 case SCF_ERROR_TYPE_MISMATCH: 3426 return (EINVAL); 3427 3428 case SCF_ERROR_NOT_SET: 3429 assert(0); 3430 abort(); 3431 } 3432 } 3433 3434 h = scf_property_handle(prop); 3435 3436 val = safe_scf_value_create(h); 3437 iter = safe_scf_iter_create(h); 3438 3439 if (scf_iter_property_values(iter, prop) != 0) { 3440 scf_iter_destroy(iter); 3441 scf_value_destroy(val); 3442 switch (scf_error()) { 3443 case SCF_ERROR_CONNECTION_BROKEN: 3444 default: 3445 return (ECONNABORTED); 3446 3447 case SCF_ERROR_DELETED: 3448 return (ECANCELED); 3449 3450 case SCF_ERROR_HANDLE_MISMATCH: 3451 case SCF_ERROR_NOT_SET: 3452 assert(0); 3453 abort(); 3454 } 3455 } 3456 3457 buf = startd_alloc(max_scf_value_size); 3458 3459 for (;;) { 3460 r = scf_iter_next_value(iter, val); 3461 if (r < 0) { 3462 assert(scf_error() == SCF_ERROR_CONNECTION_BROKEN); 3463 startd_free(buf, max_scf_value_size); 3464 scf_iter_destroy(iter); 3465 scf_value_destroy(val); 3466 return (ECONNABORTED); 3467 } 3468 if (r == 0) 3469 break; 3470 3471 sz = scf_value_get_astring(val, buf, max_scf_value_size); 3472 assert(sz >= 0); 3473 3474 r = cb(buf, arg); 3475 3476 if (r != 0) 3477 break; 3478 } 3479 3480 startd_free(buf, max_scf_value_size); 3481 scf_value_destroy(val); 3482 scf_iter_destroy(iter); 3483 3484 return (r == 0 ? 0 : EINTR); 3485 } 3486 3487 /* 3488 * Returns 0 or ECONNABORTED. 3489 */ 3490 int 3491 libscf_create_self(scf_handle_t *h) 3492 { 3493 scf_scope_t *scope; 3494 scf_service_t *svc; 3495 scf_instance_t *inst; 3496 instance_data_t idata; 3497 int ret = 0, r; 3498 ctid_t ctid; 3499 uint64_t uint64; 3500 uint_t count = 0, msecs = ALLOC_DELAY; 3501 3502 const char * const startd_svc = "system/svc/restarter"; 3503 const char * const startd_inst = "default"; 3504 3505 /* If SCF_SERVICE_STARTD changes, our strings must change, too. */ 3506 assert(strcmp(SCF_SERVICE_STARTD, 3507 "svc:/system/svc/restarter:default") == 0); 3508 3509 scope = safe_scf_scope_create(h); 3510 svc = safe_scf_service_create(h); 3511 inst = safe_scf_instance_create(h); 3512 3513 if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, scope) != 0) { 3514 assert(scf_error() == SCF_ERROR_CONNECTION_BROKEN); 3515 ret = ECONNABORTED; 3516 goto out; 3517 } 3518 3519 get_svc: 3520 if (scf_scope_get_service(scope, startd_svc, svc) != 0) { 3521 switch (scf_error()) { 3522 case SCF_ERROR_CONNECTION_BROKEN: 3523 case SCF_ERROR_DELETED: 3524 default: 3525 ret = ECONNABORTED; 3526 goto out; 3527 3528 case SCF_ERROR_NOT_FOUND: 3529 break; 3530 3531 case SCF_ERROR_HANDLE_MISMATCH: 3532 case SCF_ERROR_INVALID_ARGUMENT: 3533 case SCF_ERROR_NOT_SET: 3534 bad_error("scf_scope_get_service", scf_error()); 3535 } 3536 3537 add_svc: 3538 if (scf_scope_add_service(scope, startd_svc, svc) != 0) { 3539 switch (scf_error()) { 3540 case SCF_ERROR_CONNECTION_BROKEN: 3541 case SCF_ERROR_DELETED: 3542 default: 3543 ret = ECONNABORTED; 3544 goto out; 3545 3546 case SCF_ERROR_EXISTS: 3547 goto get_svc; 3548 3549 case SCF_ERROR_PERMISSION_DENIED: 3550 case SCF_ERROR_BACKEND_ACCESS: 3551 case SCF_ERROR_BACKEND_READONLY: 3552 uu_warn("Could not create %s: %s\n", 3553 SCF_SERVICE_STARTD, 3554 scf_strerror(scf_error())); 3555 goto out; 3556 3557 case SCF_ERROR_HANDLE_MISMATCH: 3558 case SCF_ERROR_INVALID_ARGUMENT: 3559 case SCF_ERROR_NOT_SET: 3560 bad_error("scf_scope_add_service", scf_error()); 3561 } 3562 } 3563 } 3564 3565 if (scf_service_get_instance(svc, startd_inst, NULL) == 0) 3566 goto out; 3567 3568 switch (scf_error()) { 3569 case SCF_ERROR_CONNECTION_BROKEN: 3570 default: 3571 ret = ECONNABORTED; 3572 goto out; 3573 3574 case SCF_ERROR_NOT_FOUND: 3575 break; 3576 3577 case SCF_ERROR_DELETED: 3578 goto add_svc; 3579 3580 case SCF_ERROR_HANDLE_MISMATCH: 3581 case SCF_ERROR_INVALID_ARGUMENT: 3582 case SCF_ERROR_NOT_SET: 3583 bad_error("scf_service_get_instance", scf_error()); 3584 } 3585 3586 add_inst: 3587 if (scf_service_add_instance(svc, startd_inst, inst) != 0) { 3588 switch (scf_error()) { 3589 case SCF_ERROR_CONNECTION_BROKEN: 3590 default: 3591 ret = ECONNABORTED; 3592 goto out; 3593 3594 case SCF_ERROR_EXISTS: 3595 break; 3596 3597 case SCF_ERROR_PERMISSION_DENIED: 3598 case SCF_ERROR_BACKEND_ACCESS: 3599 uu_die("Could not create %s: %s\n", SCF_SERVICE_STARTD, 3600 scf_strerror(scf_error())); 3601 /* NOTREACHED */ 3602 3603 case SCF_ERROR_BACKEND_READONLY: 3604 log_error(LOG_NOTICE, 3605 "Could not create %s: backend readonly.\n", 3606 SCF_SERVICE_STARTD); 3607 goto out; 3608 3609 case SCF_ERROR_DELETED: 3610 goto add_svc; 3611 3612 case SCF_ERROR_HANDLE_MISMATCH: 3613 case SCF_ERROR_INVALID_ARGUMENT: 3614 case SCF_ERROR_NOT_SET: 3615 bad_error("scf_service_add_instance", scf_error()); 3616 } 3617 } 3618 3619 /* Set start time. */ 3620 idata.i_fmri = SCF_SERVICE_STARTD; 3621 idata.i_state = RESTARTER_STATE_NONE; 3622 idata.i_next_state = RESTARTER_STATE_NONE; 3623 set_state: 3624 switch (r = _restarter_commit_states(h, &idata, RESTARTER_STATE_ONLINE, 3625 RESTARTER_STATE_NONE, NULL)) { 3626 case 0: 3627 break; 3628 3629 case ENOMEM: 3630 ++count; 3631 if (count < ALLOC_RETRY) { 3632 (void) poll(NULL, 0, msecs); 3633 msecs *= ALLOC_DELAY_MULT; 3634 goto set_state; 3635 } 3636 3637 uu_die("Insufficient memory.\n"); 3638 /* NOTREACHED */ 3639 3640 case ECONNABORTED: 3641 ret = ECONNABORTED; 3642 goto out; 3643 3644 case ENOENT: 3645 goto add_inst; 3646 3647 case EPERM: 3648 case EACCES: 3649 case EROFS: 3650 uu_warn("Could not timestamp %s: %s\n", idata.i_fmri, 3651 strerror(r)); 3652 break; 3653 3654 case EINVAL: 3655 default: 3656 bad_error("_restarter_commit_states", r); 3657 } 3658 3659 /* Set general/enabled. */ 3660 ret = libscf_inst_set_boolean_prop(inst, SCF_PG_GENERAL, 3661 SCF_PG_GENERAL_TYPE, SCF_PG_GENERAL_FLAGS, SCF_PROPERTY_ENABLED, 1); 3662 switch (ret) { 3663 case 0: 3664 case ECONNABORTED: 3665 case EPERM: 3666 case EACCES: 3667 case EROFS: 3668 break; 3669 3670 case ECANCELED: 3671 goto add_inst; 3672 3673 default: 3674 bad_error("libscf_inst_set_boolean_prop", ret); 3675 } 3676 3677 ret = libscf_write_start_pid(inst, getpid()); 3678 switch (ret) { 3679 case 0: 3680 case ECONNABORTED: 3681 case EPERM: 3682 case EACCES: 3683 case EROFS: 3684 break; 3685 3686 case ECANCELED: 3687 goto add_inst; 3688 3689 default: 3690 bad_error("libscf_write_start_pid", ret); 3691 } 3692 3693 ctid = proc_get_ctid(); 3694 if (ctid > 0) { 3695 3696 uint64 = (uint64_t)ctid; 3697 ret = libscf_inst_set_count_prop(inst, 3698 SCF_PG_RESTARTER, SCF_PG_RESTARTER_TYPE, 3699 SCF_PG_RESTARTER_FLAGS, SCF_PROPERTY_CONTRACT, uint64); 3700 3701 switch (ret) { 3702 case 0: 3703 case ECONNABORTED: 3704 case EPERM: 3705 case EACCES: 3706 case EROFS: 3707 break; 3708 3709 case ECANCELED: 3710 goto add_inst; 3711 3712 default: 3713 bad_error("libscf_inst_set_count_prop", ret); 3714 } 3715 } 3716 3717 ret = libscf_note_method_log(inst, LOG_PREFIX_EARLY, 3718 STARTD_DEFAULT_LOG); 3719 if (ret == 0) { 3720 ret = libscf_note_method_log(inst, LOG_PREFIX_NORMAL, 3721 STARTD_DEFAULT_LOG); 3722 } 3723 3724 switch (ret) { 3725 case ECONNABORTED: 3726 case EPERM: 3727 case EACCES: 3728 case EROFS: 3729 case EAGAIN: 3730 break; 3731 3732 case ECANCELED: 3733 goto add_inst; 3734 3735 default: 3736 bad_error("libscf_note_method_log", ret); 3737 } 3738 3739 out: 3740 scf_instance_destroy(inst); 3741 scf_service_destroy(svc); 3742 scf_scope_destroy(scope); 3743 return (ret); 3744 } 3745 3746 /* 3747 * Returns 3748 * 0 - success 3749 * ENOENT - SCF_SERVICE_STARTD does not exist in repository 3750 * EPERM 3751 * EACCES 3752 * EROFS 3753 */ 3754 int 3755 libscf_set_reconfig(int set) 3756 { 3757 scf_handle_t *h; 3758 scf_instance_t *inst; 3759 scf_propertygroup_t *pg; 3760 int ret = 0; 3761 3762 h = libscf_handle_create_bound_loop(); 3763 inst = safe_scf_instance_create(h); 3764 pg = safe_scf_pg_create(h); 3765 3766 again: 3767 if (scf_handle_decode_fmri(h, SCF_SERVICE_STARTD, NULL, NULL, 3768 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) { 3769 switch (scf_error()) { 3770 case SCF_ERROR_CONNECTION_BROKEN: 3771 default: 3772 libscf_handle_rebind(h); 3773 goto again; 3774 3775 case SCF_ERROR_NOT_FOUND: 3776 ret = ENOENT; 3777 goto reconfig_out; 3778 3779 case SCF_ERROR_HANDLE_MISMATCH: 3780 case SCF_ERROR_INVALID_ARGUMENT: 3781 case SCF_ERROR_CONSTRAINT_VIOLATED: 3782 bad_error("scf_handle_decode_fmri", scf_error()); 3783 } 3784 } 3785 3786 ret = libscf_inst_set_boolean_prop(inst, "system", SCF_GROUP_FRAMEWORK, 3787 SCF_PG_FLAG_NONPERSISTENT, "reconfigure", set); 3788 switch (ret) { 3789 case 0: 3790 case EPERM: 3791 case EACCES: 3792 case EROFS: 3793 break; 3794 3795 case ECONNABORTED: 3796 libscf_handle_rebind(h); 3797 goto again; 3798 3799 case ECANCELED: 3800 ret = ENOENT; 3801 break; 3802 3803 default: 3804 bad_error("libscf_inst_set_boolean_prop", ret); 3805 } 3806 3807 reconfig_out: 3808 scf_pg_destroy(pg); 3809 scf_instance_destroy(inst); 3810 scf_handle_destroy(h); 3811 return (ret); 3812 } 3813 3814 /* 3815 * Set inst->ri_m_inst to the scf instance for inst. If it has been deleted, 3816 * set inst->ri_mi_deleted to true. If the repository connection is broken, it 3817 * is rebound with libscf_handle_rebound(). 3818 */ 3819 void 3820 libscf_reget_instance(restarter_inst_t *inst) 3821 { 3822 scf_handle_t *h; 3823 int r; 3824 3825 h = scf_instance_handle(inst->ri_m_inst); 3826 3827 again: 3828 r = libscf_lookup_instance(inst->ri_i.i_fmri, inst->ri_m_inst); 3829 switch (r) { 3830 case 0: 3831 case ENOENT: 3832 inst->ri_mi_deleted = (r == ENOENT); 3833 return; 3834 3835 case ECONNABORTED: 3836 libscf_handle_rebind(h); 3837 goto again; 3838 3839 case EINVAL: 3840 case ENOTSUP: 3841 default: 3842 bad_error("libscf_lookup_instance", r); 3843 } 3844 } 3845