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