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