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