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