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