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