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