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