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