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 */ 26 27 28 #include <sys/contract/process.h> 29 #include <assert.h> 30 #include <errno.h> 31 #include <libscf.h> 32 #include <libscf_priv.h> 33 #include <poll.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <unistd.h> 37 38 #include "startd.h" 39 40 #define SMF_SNAPSHOT_RUNNING "running" 41 42 #define INFO_EVENTS_ALL "info_events_all" 43 44 char * 45 inst_fmri_to_svc_fmri(const char *fmri) 46 { 47 char *buf, *sfmri; 48 const char *scope, *svc; 49 int r; 50 boolean_t local; 51 52 buf = startd_alloc(max_scf_fmri_size); 53 sfmri = startd_alloc(max_scf_fmri_size); 54 55 (void) strcpy(buf, fmri); 56 57 r = scf_parse_svc_fmri(buf, &scope, &svc, NULL, NULL, NULL); 58 assert(r == 0); 59 60 local = strcmp(scope, SCF_SCOPE_LOCAL) == 0; 61 62 (void) snprintf(sfmri, max_scf_fmri_size, "svc:%s%s/%s", 63 local ? "" : "//", local ? "" : scope, svc); 64 65 startd_free(buf, max_scf_fmri_size); 66 67 return (sfmri); 68 } 69 70 /* 71 * Wrapper for the scf_*_create() functions. On SCF_ERROR_NO_MEMORY and 72 * SCF_ERROR_NO_RESOURCES, retries or dies. So this can only fail with 73 * SCF_ERROR_INVALID_ARGUMENT, if h is NULL. 74 */ 75 void * 76 libscf_object_create(void *f(scf_handle_t *), scf_handle_t *h) 77 { 78 void *o; 79 uint_t try, msecs; 80 scf_error_t err; 81 82 o = f(h); 83 if (o != NULL) 84 return (o); 85 err = scf_error(); 86 if (err != SCF_ERROR_NO_MEMORY && err != SCF_ERROR_NO_RESOURCES) 87 return (NULL); 88 89 msecs = ALLOC_DELAY; 90 91 for (try = 0; try < ALLOC_RETRY; ++try) { 92 (void) poll(NULL, 0, msecs); 93 msecs *= ALLOC_DELAY_MULT; 94 o = f(h); 95 if (o != NULL) 96 return (o); 97 err = scf_error(); 98 if (err != SCF_ERROR_NO_MEMORY && err != SCF_ERROR_NO_RESOURCES) 99 return (NULL); 100 } 101 102 uu_die("Insufficient memory.\n"); 103 /* NOTREACHED */ 104 } 105 106 scf_snapshot_t * 107 libscf_get_running_snapshot(scf_instance_t *inst) 108 { 109 scf_handle_t *h; 110 scf_snapshot_t *snap; 111 112 h = scf_instance_handle(inst); 113 if (h == NULL) 114 return (NULL); 115 116 snap = scf_snapshot_create(h); 117 if (snap == NULL) 118 return (NULL); 119 120 if (scf_instance_get_snapshot(inst, SMF_SNAPSHOT_RUNNING, snap) == 0) 121 return (snap); 122 123 scf_snapshot_destroy(snap); 124 return (NULL); 125 } 126 127 /* 128 * Make sure a service has a "running" snapshot. If it doesn't, make one from 129 * the editing configuration. 130 */ 131 scf_snapshot_t * 132 libscf_get_or_make_running_snapshot(scf_instance_t *inst, const char *fmri, 133 boolean_t retake) 134 { 135 scf_handle_t *h; 136 scf_snapshot_t *snap; 137 138 h = scf_instance_handle(inst); 139 140 snap = scf_snapshot_create(h); 141 if (snap == NULL) 142 goto err; 143 144 if (scf_instance_get_snapshot(inst, SMF_SNAPSHOT_RUNNING, snap) == 0) 145 return (snap); 146 147 switch (scf_error()) { 148 case SCF_ERROR_NOT_FOUND: 149 break; 150 151 case SCF_ERROR_DELETED: 152 scf_snapshot_destroy(snap); 153 return (NULL); 154 155 default: 156 err: 157 log_error(LOG_NOTICE, 158 "Could not check for running snapshot of %s (%s).\n", fmri, 159 scf_strerror(scf_error())); 160 scf_snapshot_destroy(snap); 161 return (NULL); 162 } 163 164 if (_scf_snapshot_take_new(inst, SMF_SNAPSHOT_RUNNING, snap) == 0) { 165 log_framework(LOG_DEBUG, "Took running snapshot for %s.\n", 166 fmri); 167 } else { 168 if (retake && scf_error() == SCF_ERROR_BACKEND_READONLY) 169 restarter_mark_pending_snapshot(fmri, 170 RINST_RETAKE_RUNNING); 171 else 172 log_error(LOG_DEBUG, 173 "Could not create running snapshot for %s " 174 "(%s).\n", fmri, scf_strerror(scf_error())); 175 176 scf_snapshot_destroy(snap); 177 snap = NULL; 178 } 179 180 return (snap); 181 } 182 183 /* 184 * When a service comes up, point the "start" snapshot at the "running" 185 * snapshot. Returns 0 on success, ENOTSUP if fmri designates something other 186 * than an instance, ECONNABORTED, ENOENT if the instance does not exist, or 187 * EACCES. 188 */ 189 int 190 libscf_snapshots_poststart(scf_handle_t *h, const char *fmri, boolean_t retake) 191 { 192 scf_instance_t *inst = NULL; 193 scf_snapshot_t *running, *start = NULL; 194 int ret = 0, r; 195 196 r = libscf_fmri_get_instance(h, fmri, &inst); 197 switch (r) { 198 case 0: 199 break; 200 201 case ENOTSUP: 202 case ECONNABORTED: 203 case ENOENT: 204 return (r); 205 206 case EINVAL: 207 default: 208 assert(0); 209 abort(); 210 } 211 212 start = safe_scf_snapshot_create(h); 213 214 again: 215 running = libscf_get_or_make_running_snapshot(inst, fmri, retake); 216 if (running == NULL) { 217 ret = 0; 218 goto out; 219 } 220 221 lookup: 222 if (scf_instance_get_snapshot(inst, "start", start) != 0) { 223 switch (scf_error()) { 224 case SCF_ERROR_CONNECTION_BROKEN: 225 default: 226 ret = ECONNABORTED; 227 goto out; 228 229 case SCF_ERROR_NOT_FOUND: 230 if (_scf_snapshot_take_new(inst, "start", start) != 0) { 231 switch (scf_error()) { 232 case SCF_ERROR_CONNECTION_BROKEN: 233 default: 234 ret = ECONNABORTED; 235 goto out; 236 237 case SCF_ERROR_DELETED: 238 ret = ENOENT; 239 goto out; 240 241 case SCF_ERROR_EXISTS: 242 goto lookup; 243 244 case SCF_ERROR_NO_RESOURCES: 245 uu_die("Repository server out of " 246 "resources.\n"); 247 /* NOTREACHED */ 248 249 case SCF_ERROR_BACKEND_READONLY: 250 goto readonly; 251 252 case SCF_ERROR_PERMISSION_DENIED: 253 uu_die("Insufficient privileges.\n"); 254 /* NOTREACHED */ 255 256 case SCF_ERROR_BACKEND_ACCESS: 257 ret = EACCES; 258 goto out; 259 260 case SCF_ERROR_HANDLE_MISMATCH: 261 case SCF_ERROR_INTERNAL: 262 case SCF_ERROR_INVALID_ARGUMENT: 263 case SCF_ERROR_NOT_SET: 264 bad_error("_scf_snapshot_take_new", 265 scf_error()); 266 } 267 } 268 break; 269 270 case SCF_ERROR_DELETED: 271 ret = ENOENT; 272 goto out; 273 274 case SCF_ERROR_HANDLE_MISMATCH: 275 case SCF_ERROR_NOT_SET: 276 case SCF_ERROR_INVALID_ARGUMENT: 277 bad_error("scf_instance_get_snapshot", scf_error()); 278 } 279 } 280 281 if (_scf_snapshot_attach(running, start) == 0) { 282 log_framework(LOG_DEBUG, "Updated \"start\" snapshot for %s.\n", 283 fmri); 284 } else { 285 switch (scf_error()) { 286 case SCF_ERROR_CONNECTION_BROKEN: 287 default: 288 ret = ECONNABORTED; 289 goto out; 290 291 case SCF_ERROR_DELETED: 292 scf_snapshot_destroy(running); 293 goto again; 294 295 case SCF_ERROR_NO_RESOURCES: 296 uu_die("Repository server out of resources.\n"); 297 /* NOTREACHED */ 298 299 case SCF_ERROR_PERMISSION_DENIED: 300 uu_die("Insufficient privileges.\n"); 301 /* NOTREACHED */ 302 303 case SCF_ERROR_BACKEND_ACCESS: 304 ret = EACCES; 305 goto out; 306 307 case SCF_ERROR_BACKEND_READONLY: 308 readonly: 309 if (retake) 310 restarter_mark_pending_snapshot(fmri, 311 RINST_RETAKE_START); 312 break; 313 314 case SCF_ERROR_HANDLE_MISMATCH: 315 case SCF_ERROR_NOT_SET: 316 bad_error("_scf_snapshot_attach", scf_error()); 317 } 318 } 319 320 out: 321 scf_snapshot_destroy(start); 322 scf_snapshot_destroy(running); 323 scf_instance_destroy(inst); 324 325 return (ret); 326 } 327 328 /* 329 * Before a refresh, update the "running" snapshot from the editing 330 * configuration. 331 * 332 * Returns 0 on success and -1 on failure. 333 */ 334 int 335 libscf_snapshots_refresh(scf_instance_t *inst, const char *fmri) 336 { 337 scf_handle_t *h; 338 scf_snapshot_t *snap; 339 boolean_t err = 1; 340 341 h = scf_instance_handle(inst); 342 if (h == NULL) 343 goto out; 344 345 snap = scf_snapshot_create(h); 346 if (snap == NULL) 347 goto out; 348 349 if (scf_instance_get_snapshot(inst, SMF_SNAPSHOT_RUNNING, snap) == 0) { 350 if (_scf_snapshot_take_attach(inst, snap) == 0) 351 err = 0; 352 } else { 353 switch (scf_error()) { 354 case SCF_ERROR_DELETED: 355 err = 0; 356 goto out; 357 358 case SCF_ERROR_NOT_FOUND: 359 break; 360 361 case SCF_ERROR_NOT_SET: 362 assert(0); 363 abort(); 364 /* NOTREACHED */ 365 366 default: 367 goto out; 368 } 369 370 log_error(LOG_DEBUG, 371 "Service %s has no %s snapshot; creating one.\n", fmri, 372 SMF_SNAPSHOT_RUNNING); 373 374 if (_scf_snapshot_take_new(inst, SMF_SNAPSHOT_RUNNING, 375 snap) == 0) 376 err = 0; 377 } 378 379 out: 380 scf_snapshot_destroy(snap); 381 382 if (!err) 383 return (0); 384 385 log_error(LOG_WARNING, 386 "Could not update \"running\" snapshot for refresh of %s.\n", fmri); 387 return (-1); 388 } 389 390 /* 391 * int libscf_read_single_astring() 392 * Reads a single astring value of the requested property into the 393 * pre-allocated buffer (conventionally of size max_scf_value_size). 394 * Multiple values constitute an error. 395 * 396 * Returns 0 on success or LIBSCF_PROPERTY_ABSENT or LIBSCF_PROPERTY_ERROR. 397 */ 398 static int 399 libscf_read_single_astring(scf_handle_t *h, scf_property_t *prop, char **ret) 400 { 401 scf_value_t *val = safe_scf_value_create(h); 402 int r = 0; 403 404 if (scf_property_get_value(prop, val) == -1) { 405 if (scf_error() == SCF_ERROR_NOT_FOUND) 406 r = LIBSCF_PROPERTY_ABSENT; 407 else 408 r = LIBSCF_PROPERTY_ERROR; 409 goto read_single_astring_fail; 410 } 411 412 if (scf_value_get_astring(val, *ret, max_scf_value_size) <= 0) { 413 r = LIBSCF_PROPERTY_ERROR; 414 goto read_single_astring_fail; 415 } 416 417 read_single_astring_fail: 418 scf_value_destroy(val); 419 return (r); 420 } 421 422 /* 423 * libscf_get_stn_tset 424 */ 425 int32_t 426 libscf_get_stn_tset(scf_instance_t *inst) 427 { 428 scf_handle_t *h = scf_instance_handle(inst); 429 scf_propertygroup_t *pg = scf_pg_create(h); 430 char *pgname = NULL; 431 int32_t t, f, tset; 432 433 assert(inst != NULL); 434 435 pgname = startd_alloc(max_scf_fmri_size); 436 if (h == NULL || pg == NULL) { 437 tset = -1; 438 goto cleanup; 439 } 440 441 for (tset = 0, t = 1; t < SCF_STATE_ALL; t <<= 1) { 442 f = t << 16; 443 444 (void) strcpy(pgname, SCF_STN_PREFIX_TO); 445 (void) strlcat(pgname, smf_state_to_string(t), 446 max_scf_fmri_size); 447 448 if (scf_instance_get_pg_composed(inst, NULL, pgname, pg) == 449 SCF_SUCCESS) { 450 tset |= t; 451 } else if (scf_error() != SCF_ERROR_NOT_FOUND && scf_error() != 452 SCF_ERROR_DELETED) { 453 tset = -1; 454 goto cleanup; 455 } 456 457 (void) strcpy(pgname, SCF_STN_PREFIX_FROM); 458 (void) strlcat(pgname, smf_state_to_string(t), 459 max_scf_fmri_size); 460 461 if (scf_instance_get_pg_composed(inst, NULL, pgname, pg) == 462 SCF_SUCCESS) { 463 tset |= f; 464 } else if (scf_error() != SCF_ERROR_NOT_FOUND && scf_error() != 465 SCF_ERROR_DELETED) { 466 tset = -1; 467 goto cleanup; 468 } 469 } 470 471 cleanup: 472 scf_pg_destroy(pg); 473 startd_free(pgname, max_scf_fmri_size); 474 475 return (tset); 476 } 477 478 static int32_t 479 libscf_get_global_stn_tset(scf_handle_t *h) 480 { 481 scf_instance_t *inst = scf_instance_create(h); 482 int32_t tset = -1; 483 484 if (inst == NULL) { 485 goto cleanup; 486 } 487 488 if (scf_handle_decode_fmri(h, SCF_INSTANCE_GLOBAL, NULL, NULL, inst, 489 NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) { 490 goto cleanup; 491 } 492 493 tset = libscf_get_stn_tset(inst); 494 495 cleanup: 496 scf_instance_destroy(inst); 497 498 if (tset == -1) 499 log_framework(LOG_WARNING, 500 "Failed to get system wide notification parameters: %s\n", 501 scf_strerror(scf_error())); 502 503 return (tset); 504 } 505 506 static int 507 libscf_read_state(const scf_propertygroup_t *pg, const char *prop_name, 508 restarter_instance_state_t *state) 509 { 510 scf_handle_t *h; 511 scf_property_t *prop; 512 char *char_state = startd_alloc(max_scf_value_size); 513 int ret = 0; 514 515 h = scf_pg_handle(pg); 516 prop = safe_scf_property_create(h); 517 518 if (scf_pg_get_property(pg, prop_name, prop) == -1) { 519 if (scf_error() == SCF_ERROR_NOT_FOUND) 520 ret = LIBSCF_PROPERTY_ABSENT; 521 else 522 ret = LIBSCF_PROPERTY_ERROR; 523 } else { 524 ret = libscf_read_single_astring(h, prop, &char_state); 525 if (ret != 0) { 526 if (ret != LIBSCF_PROPERTY_ABSENT) 527 ret = LIBSCF_PROPERTY_ERROR; 528 } else { 529 *state = restarter_string_to_state(char_state); 530 ret = 0; 531 } 532 } 533 534 startd_free(char_state, max_scf_value_size); 535 scf_property_destroy(prop); 536 return (ret); 537 } 538 539 /* 540 * int libscf_read_states(const scf_propertygroup_t *, 541 * restarter_instance_state_t *, restarter_instance_state_t *) 542 * 543 * Set the current state and next_state values for the given service instance. 544 * Returns 0 on success, or a libscf error code on failure. 545 */ 546 int 547 libscf_read_states(const scf_propertygroup_t *pg, 548 restarter_instance_state_t *state, restarter_instance_state_t *next_state) 549 { 550 int state_ret, next_state_ret, ret; 551 552 state_ret = libscf_read_state(pg, SCF_PROPERTY_STATE, state); 553 next_state_ret = libscf_read_state(pg, SCF_PROPERTY_NEXT_STATE, 554 next_state); 555 556 if (state_ret == LIBSCF_PROPERTY_ERROR || 557 next_state_ret == LIBSCF_PROPERTY_ERROR) { 558 ret = LIBSCF_PROPERTY_ERROR; 559 } else if (state_ret == 0 && next_state_ret == 0) { 560 ret = 0; 561 } else if (state_ret == LIBSCF_PROPERTY_ABSENT && 562 next_state_ret == LIBSCF_PROPERTY_ABSENT) { 563 *state = RESTARTER_STATE_UNINIT; 564 *next_state = RESTARTER_STATE_NONE; 565 ret = 0; 566 } else if (state_ret == LIBSCF_PROPERTY_ABSENT || 567 next_state_ret == LIBSCF_PROPERTY_ABSENT) { 568 log_framework(LOG_DEBUG, 569 "Only one repository state exists, setting " 570 "restarter states to MAINTENANCE and NONE\n"); 571 *state = RESTARTER_STATE_MAINT; 572 *next_state = RESTARTER_STATE_NONE; 573 ret = 0; 574 } else { 575 ret = LIBSCF_PROPERTY_ERROR; 576 } 577 578 read_states_out: 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 * Returns 0, ECONNABORTED, ECANCELED, or EPERM. 1685 */ 1686 int 1687 libscf_delete_enable_ovr(scf_instance_t *inst) 1688 { 1689 return (scf_instance_delete_prop(inst, SCF_PG_GENERAL_OVR, 1690 SCF_PROPERTY_ENABLED)); 1691 } 1692 1693 /* 1694 * Fails with 1695 * ECONNABORTED - repository connection was broken 1696 * ECANCELED - pg was deleted 1697 * ENOENT - pg has no milestone property 1698 * EINVAL - the milestone property is misconfigured 1699 */ 1700 static int 1701 pg_get_milestone(scf_propertygroup_t *pg, scf_property_t *prop, 1702 scf_value_t *val, char *buf, size_t buf_sz) 1703 { 1704 if (scf_pg_get_property(pg, SCF_PROPERTY_MILESTONE, prop) != 0) { 1705 switch (scf_error()) { 1706 case SCF_ERROR_CONNECTION_BROKEN: 1707 default: 1708 return (ECONNABORTED); 1709 1710 case SCF_ERROR_DELETED: 1711 return (ECANCELED); 1712 1713 case SCF_ERROR_NOT_FOUND: 1714 return (ENOENT); 1715 1716 case SCF_ERROR_HANDLE_MISMATCH: 1717 case SCF_ERROR_INVALID_ARGUMENT: 1718 case SCF_ERROR_NOT_SET: 1719 bad_error("scf_pg_get_property", scf_error()); 1720 } 1721 } 1722 1723 if (scf_property_get_value(prop, val) != 0) { 1724 switch (scf_error()) { 1725 case SCF_ERROR_CONNECTION_BROKEN: 1726 default: 1727 return (ECONNABORTED); 1728 1729 case SCF_ERROR_DELETED: 1730 case SCF_ERROR_CONSTRAINT_VIOLATED: 1731 case SCF_ERROR_NOT_FOUND: 1732 return (EINVAL); 1733 1734 case SCF_ERROR_NOT_SET: 1735 case SCF_ERROR_PERMISSION_DENIED: 1736 bad_error("scf_property_get_value", scf_error()); 1737 } 1738 } 1739 1740 if (scf_value_get_astring(val, buf, buf_sz) < 0) { 1741 switch (scf_error()) { 1742 case SCF_ERROR_TYPE_MISMATCH: 1743 return (EINVAL); 1744 1745 case SCF_ERROR_NOT_SET: 1746 default: 1747 bad_error("scf_value_get_astring", scf_error()); 1748 } 1749 } 1750 1751 return (0); 1752 } 1753 1754 /* 1755 * Fails with 1756 * ECONNABORTED - repository connection was broken 1757 * ECANCELED - inst was deleted 1758 * ENOENT - inst has no milestone property 1759 * EINVAL - the milestone property is misconfigured 1760 */ 1761 int 1762 libscf_get_milestone(scf_instance_t *inst, scf_property_t *prop, 1763 scf_value_t *val, char *buf, size_t buf_sz) 1764 { 1765 scf_propertygroup_t *pg; 1766 int r; 1767 1768 pg = safe_scf_pg_create(scf_instance_handle(inst)); 1769 1770 if (scf_instance_get_pg(inst, SCF_PG_OPTIONS_OVR, pg) == 0) { 1771 switch (r = pg_get_milestone(pg, prop, val, buf, buf_sz)) { 1772 case 0: 1773 case ECONNABORTED: 1774 case EINVAL: 1775 goto out; 1776 1777 case ECANCELED: 1778 case ENOENT: 1779 break; 1780 1781 default: 1782 bad_error("pg_get_milestone", r); 1783 } 1784 } else { 1785 switch (scf_error()) { 1786 case SCF_ERROR_CONNECTION_BROKEN: 1787 default: 1788 r = ECONNABORTED; 1789 goto out; 1790 1791 case SCF_ERROR_DELETED: 1792 r = ECANCELED; 1793 goto out; 1794 1795 case SCF_ERROR_NOT_FOUND: 1796 break; 1797 1798 case SCF_ERROR_HANDLE_MISMATCH: 1799 case SCF_ERROR_INVALID_ARGUMENT: 1800 case SCF_ERROR_NOT_SET: 1801 bad_error("scf_instance_get_pg", scf_error()); 1802 } 1803 } 1804 1805 if (scf_instance_get_pg(inst, SCF_PG_OPTIONS, pg) == 0) { 1806 r = pg_get_milestone(pg, prop, val, buf, buf_sz); 1807 } else { 1808 switch (scf_error()) { 1809 case SCF_ERROR_CONNECTION_BROKEN: 1810 default: 1811 r = ECONNABORTED; 1812 goto out; 1813 1814 case SCF_ERROR_DELETED: 1815 r = ECANCELED; 1816 goto out; 1817 1818 case SCF_ERROR_NOT_FOUND: 1819 r = ENOENT; 1820 break; 1821 1822 case SCF_ERROR_HANDLE_MISMATCH: 1823 case SCF_ERROR_INVALID_ARGUMENT: 1824 case SCF_ERROR_NOT_SET: 1825 bad_error("scf_instance_get_pg", scf_error()); 1826 } 1827 } 1828 1829 out: 1830 scf_pg_destroy(pg); 1831 1832 return (r); 1833 } 1834 1835 /* 1836 * Get the runlevel character from the runlevel property of the given property 1837 * group. Fails with 1838 * ECONNABORTED - repository connection was broken 1839 * ECANCELED - prop's property group was deleted 1840 * ENOENT - the property has no values 1841 * EINVAL - the property has more than one value 1842 * the property is of the wrong type 1843 * the property value is malformed 1844 */ 1845 int 1846 libscf_extract_runlevel(scf_property_t *prop, char *rlp) 1847 { 1848 scf_value_t *val; 1849 char buf[2]; 1850 1851 val = safe_scf_value_create(scf_property_handle(prop)); 1852 1853 if (scf_property_get_value(prop, val) != 0) { 1854 scf_value_destroy(val); 1855 switch (scf_error()) { 1856 case SCF_ERROR_CONNECTION_BROKEN: 1857 return (ECONNABORTED); 1858 1859 case SCF_ERROR_NOT_SET: 1860 return (ENOENT); 1861 1862 case SCF_ERROR_DELETED: 1863 return (ECANCELED); 1864 1865 case SCF_ERROR_CONSTRAINT_VIOLATED: 1866 return (EINVAL); 1867 1868 case SCF_ERROR_NOT_FOUND: 1869 return (ENOENT); 1870 1871 case SCF_ERROR_HANDLE_MISMATCH: 1872 case SCF_ERROR_NOT_BOUND: 1873 case SCF_ERROR_PERMISSION_DENIED: 1874 default: 1875 bad_error("scf_property_get_value", scf_error()); 1876 } 1877 } 1878 1879 if (scf_value_get_astring(val, buf, sizeof (buf)) < 0) { 1880 scf_value_destroy(val); 1881 if (scf_error() != SCF_ERROR_TYPE_MISMATCH) 1882 bad_error("scf_value_get_astring", scf_error()); 1883 1884 return (EINVAL); 1885 } 1886 1887 scf_value_destroy(val); 1888 1889 if (buf[0] == '\0' || buf[1] != '\0') 1890 return (EINVAL); 1891 1892 *rlp = buf[0]; 1893 1894 return (0); 1895 } 1896 1897 /* 1898 * Delete the "runlevel" property from the given property group. Also set the 1899 * "milestone" property to the given string. Fails with ECONNABORTED, 1900 * ECANCELED, EPERM, EACCES, or EROFS. 1901 */ 1902 int 1903 libscf_clear_runlevel(scf_propertygroup_t *pg, const char *milestone) 1904 { 1905 scf_handle_t *h; 1906 scf_transaction_t *tx; 1907 scf_transaction_entry_t *e_rl, *e_ms; 1908 scf_value_t *val; 1909 scf_error_t serr; 1910 boolean_t isempty = B_TRUE; 1911 int ret = 0, r; 1912 1913 h = scf_pg_handle(pg); 1914 tx = safe_scf_transaction_create(h); 1915 e_rl = safe_scf_entry_create(h); 1916 e_ms = safe_scf_entry_create(h); 1917 val = safe_scf_value_create(h); 1918 1919 if (milestone) { 1920 r = scf_value_set_astring(val, milestone); 1921 assert(r == 0); 1922 } 1923 1924 for (;;) { 1925 if (scf_transaction_start(tx, pg) != 0) { 1926 switch (scf_error()) { 1927 case SCF_ERROR_CONNECTION_BROKEN: 1928 default: 1929 ret = ECONNABORTED; 1930 goto out; 1931 1932 case SCF_ERROR_DELETED: 1933 ret = ECANCELED; 1934 goto out; 1935 1936 case SCF_ERROR_PERMISSION_DENIED: 1937 ret = EPERM; 1938 goto out; 1939 1940 case SCF_ERROR_BACKEND_ACCESS: 1941 ret = EACCES; 1942 goto out; 1943 1944 case SCF_ERROR_BACKEND_READONLY: 1945 ret = EROFS; 1946 goto out; 1947 1948 case SCF_ERROR_NOT_SET: 1949 bad_error("scf_transaction_start", scf_error()); 1950 } 1951 } 1952 1953 if (scf_transaction_property_delete(tx, e_rl, 1954 "runlevel") == 0) { 1955 isempty = B_FALSE; 1956 } else { 1957 switch (scf_error()) { 1958 case SCF_ERROR_CONNECTION_BROKEN: 1959 default: 1960 ret = ECONNABORTED; 1961 goto out; 1962 1963 case SCF_ERROR_DELETED: 1964 ret = ECANCELED; 1965 goto out; 1966 1967 case SCF_ERROR_NOT_FOUND: 1968 break; 1969 1970 case SCF_ERROR_HANDLE_MISMATCH: 1971 case SCF_ERROR_NOT_BOUND: 1972 case SCF_ERROR_INVALID_ARGUMENT: 1973 bad_error("scf_transaction_property_delete", 1974 scf_error()); 1975 } 1976 } 1977 1978 if (milestone) { 1979 ret = transaction_add_set(tx, e_ms, 1980 SCF_PROPERTY_MILESTONE, SCF_TYPE_ASTRING); 1981 switch (ret) { 1982 case 0: 1983 break; 1984 1985 case ECONNABORTED: 1986 case ECANCELED: 1987 goto out; 1988 1989 default: 1990 bad_error("transaction_add_set", ret); 1991 } 1992 1993 isempty = B_FALSE; 1994 1995 r = scf_entry_add_value(e_ms, val); 1996 assert(r == 0); 1997 } 1998 1999 if (isempty) 2000 goto out; 2001 2002 r = scf_transaction_commit(tx); 2003 if (r == 1) 2004 break; 2005 if (r != 0) { 2006 serr = scf_error(); 2007 scf_transaction_reset(tx); 2008 switch (serr) { 2009 case SCF_ERROR_CONNECTION_BROKEN: 2010 ret = ECONNABORTED; 2011 goto out; 2012 2013 case SCF_ERROR_PERMISSION_DENIED: 2014 ret = EPERM; 2015 goto out; 2016 2017 case SCF_ERROR_BACKEND_ACCESS: 2018 ret = EACCES; 2019 goto out; 2020 2021 case SCF_ERROR_BACKEND_READONLY: 2022 ret = EROFS; 2023 goto out; 2024 2025 default: 2026 bad_error("scf_transaction_commit", serr); 2027 } 2028 } 2029 2030 scf_transaction_reset(tx); 2031 2032 if (scf_pg_update(pg) == -1) { 2033 switch (scf_error()) { 2034 case SCF_ERROR_CONNECTION_BROKEN: 2035 ret = ECONNABORTED; 2036 goto out; 2037 2038 case SCF_ERROR_NOT_SET: 2039 ret = ECANCELED; 2040 goto out; 2041 2042 default: 2043 assert(0); 2044 abort(); 2045 } 2046 } 2047 } 2048 2049 out: 2050 scf_transaction_destroy(tx); 2051 scf_entry_destroy(e_rl); 2052 scf_entry_destroy(e_ms); 2053 scf_value_destroy(val); 2054 return (ret); 2055 } 2056 2057 /* 2058 * int libscf_get_template_values(scf_instance_t *, scf_snapshot_t *, 2059 * char **) 2060 * 2061 * Return template values for inst in *common_name suitable for use in 2062 * restarter_inst_t->ri_common_name. Called by restarter_insert_inst(). 2063 * 2064 * Returns 0 on success, ECANCELED if the instance is deleted, ECHILD if 2065 * a value fetch failed for a property, ENOENT if the instance has no 2066 * tm_common_name property group or the property group is deleted, and 2067 * ECONNABORTED if the repository connection is broken. 2068 */ 2069 int 2070 libscf_get_template_values(scf_instance_t *inst, scf_snapshot_t *snap, 2071 char **common_name, char **c_common_name) 2072 { 2073 scf_handle_t *h; 2074 scf_propertygroup_t *pg = NULL; 2075 scf_property_t *prop = NULL; 2076 int ret = 0, r; 2077 char *cname = startd_alloc(max_scf_value_size); 2078 char *c_cname = startd_alloc(max_scf_value_size); 2079 int common_name_initialized = B_FALSE; 2080 int c_common_name_initialized = B_FALSE; 2081 2082 h = scf_instance_handle(inst); 2083 pg = safe_scf_pg_create(h); 2084 prop = safe_scf_property_create(h); 2085 2086 /* 2087 * The tm_common_name property group, as with all template property 2088 * groups, is optional. 2089 */ 2090 if (scf_instance_get_pg_composed(inst, snap, SCF_PG_TM_COMMON_NAME, pg) 2091 == -1) { 2092 switch (scf_error()) { 2093 case SCF_ERROR_DELETED: 2094 ret = ECANCELED; 2095 goto template_values_out; 2096 2097 case SCF_ERROR_NOT_FOUND: 2098 goto template_values_out; 2099 2100 case SCF_ERROR_CONNECTION_BROKEN: 2101 default: 2102 ret = ECONNABORTED; 2103 goto template_values_out; 2104 2105 case SCF_ERROR_INVALID_ARGUMENT: 2106 case SCF_ERROR_HANDLE_MISMATCH: 2107 case SCF_ERROR_NOT_SET: 2108 bad_error("scf_instance_get_pg_composed", scf_error()); 2109 } 2110 } 2111 2112 /* 2113 * The name we wish uses the current locale name as the property name. 2114 */ 2115 if (st->st_locale != NULL) { 2116 if (scf_pg_get_property(pg, st->st_locale, prop) == -1) { 2117 switch (scf_error()) { 2118 case SCF_ERROR_DELETED: 2119 case SCF_ERROR_NOT_FOUND: 2120 break; 2121 2122 case SCF_ERROR_CONNECTION_BROKEN: 2123 default: 2124 ret = ECONNABORTED; 2125 goto template_values_out; 2126 2127 case SCF_ERROR_INVALID_ARGUMENT: 2128 case SCF_ERROR_HANDLE_MISMATCH: 2129 case SCF_ERROR_NOT_SET: 2130 bad_error("scf_pg_get_property", scf_error()); 2131 } 2132 } else { 2133 if ((r = libscf_read_single_astring(h, prop, &cname)) != 2134 0) { 2135 if (r != LIBSCF_PROPERTY_ABSENT) 2136 ret = ECHILD; 2137 goto template_values_out; 2138 } 2139 2140 *common_name = cname; 2141 common_name_initialized = B_TRUE; 2142 } 2143 } 2144 2145 /* 2146 * Also pull out the C locale name, as a fallback for the case where 2147 * service offers no localized name. 2148 */ 2149 if (scf_pg_get_property(pg, "C", prop) == -1) { 2150 switch (scf_error()) { 2151 case SCF_ERROR_DELETED: 2152 ret = ENOENT; 2153 goto template_values_out; 2154 2155 case SCF_ERROR_NOT_FOUND: 2156 break; 2157 2158 case SCF_ERROR_CONNECTION_BROKEN: 2159 default: 2160 ret = ECONNABORTED; 2161 goto template_values_out; 2162 2163 case SCF_ERROR_INVALID_ARGUMENT: 2164 case SCF_ERROR_HANDLE_MISMATCH: 2165 case SCF_ERROR_NOT_SET: 2166 bad_error("scf_pg_get_property", scf_error()); 2167 } 2168 } else { 2169 if ((r = libscf_read_single_astring(h, prop, &c_cname)) != 0) { 2170 if (r != LIBSCF_PROPERTY_ABSENT) 2171 ret = ECHILD; 2172 goto template_values_out; 2173 } 2174 2175 *c_common_name = c_cname; 2176 c_common_name_initialized = B_TRUE; 2177 } 2178 2179 2180 template_values_out: 2181 if (common_name_initialized == B_FALSE) 2182 startd_free(cname, max_scf_value_size); 2183 if (c_common_name_initialized == B_FALSE) 2184 startd_free(c_cname, max_scf_value_size); 2185 scf_property_destroy(prop); 2186 scf_pg_destroy(pg); 2187 2188 return (ret); 2189 } 2190 2191 /* 2192 * int libscf_get_startd_properties(scf_handle_t *, scf_instance_t *, 2193 * scf_snapshot_t *, uint_t *, char **) 2194 * 2195 * Return startd settings for inst in *flags suitable for use in 2196 * restarter_inst_t->ri_flags. Called by restarter_insert_inst(). 2197 * 2198 * Returns 0 on success, ECANCELED if the instance is deleted, ECHILD if 2199 * a value fetch failed for a property, ENOENT if the instance has no 2200 * general property group or the property group is deleted, and 2201 * ECONNABORTED if the repository connection is broken. 2202 */ 2203 int 2204 libscf_get_startd_properties(scf_instance_t *inst, 2205 scf_snapshot_t *snap, uint_t *flags, char **prefixp) 2206 { 2207 scf_handle_t *h; 2208 scf_propertygroup_t *pg = NULL; 2209 scf_property_t *prop = NULL; 2210 int style = RINST_CONTRACT; 2211 char *style_str = startd_alloc(max_scf_value_size); 2212 int ret = 0, r; 2213 2214 h = scf_instance_handle(inst); 2215 pg = safe_scf_pg_create(h); 2216 prop = safe_scf_property_create(h); 2217 2218 /* 2219 * The startd property group is optional. 2220 */ 2221 if (scf_instance_get_pg_composed(inst, snap, SCF_PG_STARTD, pg) == -1) { 2222 switch (scf_error()) { 2223 case SCF_ERROR_DELETED: 2224 ret = ECANCELED; 2225 goto instance_flags_out; 2226 2227 case SCF_ERROR_NOT_FOUND: 2228 ret = ENOENT; 2229 goto instance_flags_out; 2230 2231 case SCF_ERROR_CONNECTION_BROKEN: 2232 default: 2233 ret = ECONNABORTED; 2234 goto instance_flags_out; 2235 2236 case SCF_ERROR_INVALID_ARGUMENT: 2237 case SCF_ERROR_HANDLE_MISMATCH: 2238 case SCF_ERROR_NOT_SET: 2239 bad_error("scf_instance_get_pg_composed", scf_error()); 2240 } 2241 } 2242 2243 /* 2244 * 1. Duration property. 2245 */ 2246 if (scf_pg_get_property(pg, SCF_PROPERTY_DURATION, prop) == -1) { 2247 switch (scf_error()) { 2248 case SCF_ERROR_DELETED: 2249 ret = ENOENT; 2250 goto instance_flags_out; 2251 2252 case SCF_ERROR_NOT_FOUND: 2253 break; 2254 2255 case SCF_ERROR_CONNECTION_BROKEN: 2256 default: 2257 ret = ECONNABORTED; 2258 goto instance_flags_out; 2259 2260 case SCF_ERROR_INVALID_ARGUMENT: 2261 case SCF_ERROR_HANDLE_MISMATCH: 2262 case SCF_ERROR_NOT_SET: 2263 bad_error("scf_pg_get_property", scf_error()); 2264 } 2265 } else { 2266 errno = 0; 2267 if ((r = libscf_read_single_astring(h, prop, &style_str)) 2268 != 0) { 2269 if (r != LIBSCF_PROPERTY_ABSENT) 2270 ret = ECHILD; 2271 goto instance_flags_out; 2272 } 2273 2274 if (strcmp(style_str, "child") == 0) 2275 style = RINST_WAIT; 2276 else if (strcmp(style_str, "transient") == 0) 2277 style = RINST_TRANSIENT; 2278 } 2279 2280 /* 2281 * 2. utmpx prefix property. 2282 */ 2283 if (scf_pg_get_property(pg, SCF_PROPERTY_UTMPX_PREFIX, prop) == 0) { 2284 errno = 0; 2285 if ((r = libscf_read_single_astring(h, prop, prefixp)) != 0) { 2286 if (r != LIBSCF_PROPERTY_ABSENT) 2287 ret = ECHILD; 2288 goto instance_flags_out; 2289 } 2290 } else { 2291 switch (scf_error()) { 2292 case SCF_ERROR_DELETED: 2293 ret = ENOENT; 2294 goto instance_flags_out; 2295 2296 case SCF_ERROR_NOT_FOUND: 2297 goto instance_flags_out; 2298 2299 case SCF_ERROR_CONNECTION_BROKEN: 2300 default: 2301 ret = ECONNABORTED; 2302 goto instance_flags_out; 2303 2304 case SCF_ERROR_INVALID_ARGUMENT: 2305 case SCF_ERROR_HANDLE_MISMATCH: 2306 case SCF_ERROR_NOT_SET: 2307 bad_error("scf_pg_get_property", scf_error()); 2308 } 2309 } 2310 2311 instance_flags_out: 2312 startd_free(style_str, max_scf_value_size); 2313 *flags = (*flags & ~RINST_STYLE_MASK) | style; 2314 2315 scf_property_destroy(prop); 2316 scf_pg_destroy(pg); 2317 2318 return (ret); 2319 } 2320 2321 /* 2322 * int libscf_read_method_ids(scf_handle_t *, scf_instance_t *, ctid_t *, 2323 * ctid_t *, pid_t *) 2324 * 2325 * Sets given id_t variables to primary and transient contract IDs and start 2326 * PID. Returns 0, ECONNABORTED, and ECANCELED. 2327 */ 2328 int 2329 libscf_read_method_ids(scf_handle_t *h, scf_instance_t *inst, const char *fmri, 2330 ctid_t *primary, ctid_t *transient, pid_t *start_pid) 2331 { 2332 scf_propertygroup_t *pg = NULL; 2333 scf_property_t *prop = NULL; 2334 scf_value_t *val = NULL; 2335 uint64_t p, t; 2336 int ret = 0; 2337 2338 *primary = 0; 2339 *transient = 0; 2340 *start_pid = -1; 2341 2342 pg = safe_scf_pg_create(h); 2343 prop = safe_scf_property_create(h); 2344 val = safe_scf_value_create(h); 2345 2346 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) == -1) { 2347 switch (scf_error()) { 2348 case SCF_ERROR_CONNECTION_BROKEN: 2349 default: 2350 ret = ECONNABORTED; 2351 goto read_id_err; 2352 2353 case SCF_ERROR_DELETED: 2354 ret = ECANCELED; 2355 goto read_id_err; 2356 2357 case SCF_ERROR_NOT_FOUND: 2358 goto read_id_err; 2359 2360 case SCF_ERROR_NOT_SET: 2361 bad_error("scf_instance_get_pg", scf_error()); 2362 } 2363 } 2364 2365 ret = get_count(pg, SCF_PROPERTY_CONTRACT, &p); 2366 switch (ret) { 2367 case 0: 2368 break; 2369 2370 case EINVAL: 2371 log_error(LOG_NOTICE, 2372 "%s: Ignoring %s/%s: multivalued or not of type count\n", 2373 fmri, SCF_PG_RESTARTER, SCF_PROPERTY_CONTRACT); 2374 /* FALLTHROUGH */ 2375 case ENOENT: 2376 ret = 0; 2377 goto read_trans; 2378 2379 case ECONNABORTED: 2380 case ECANCELED: 2381 goto read_id_err; 2382 2383 case EACCES: 2384 default: 2385 bad_error("get_count", ret); 2386 } 2387 2388 *primary = p; 2389 2390 read_trans: 2391 ret = get_count(pg, SCF_PROPERTY_TRANSIENT_CONTRACT, &t); 2392 switch (ret) { 2393 case 0: 2394 break; 2395 2396 case EINVAL: 2397 log_error(LOG_NOTICE, 2398 "%s: Ignoring %s/%s: multivalued or not of type count\n", 2399 fmri, SCF_PG_RESTARTER, SCF_PROPERTY_TRANSIENT_CONTRACT); 2400 /* FALLTHROUGH */ 2401 2402 case ENOENT: 2403 ret = 0; 2404 goto read_pid_only; 2405 2406 case ECONNABORTED: 2407 case ECANCELED: 2408 goto read_id_err; 2409 2410 case EACCES: 2411 default: 2412 bad_error("get_count", ret); 2413 } 2414 2415 *transient = t; 2416 2417 read_pid_only: 2418 ret = get_count(pg, SCF_PROPERTY_START_PID, &p); 2419 switch (ret) { 2420 case 0: 2421 break; 2422 2423 case EINVAL: 2424 log_error(LOG_NOTICE, 2425 "%s: Ignoring %s/%s: multivalued or not of type count\n", 2426 fmri, SCF_PG_RESTARTER, SCF_PROPERTY_START_PID); 2427 /* FALLTHROUGH */ 2428 case ENOENT: 2429 ret = 0; 2430 goto read_id_err; 2431 2432 case ECONNABORTED: 2433 case ECANCELED: 2434 goto read_id_err; 2435 2436 case EACCES: 2437 default: 2438 bad_error("get_count", ret); 2439 } 2440 2441 *start_pid = p; 2442 2443 read_id_err: 2444 scf_value_destroy(val); 2445 scf_property_destroy(prop); 2446 scf_pg_destroy(pg); 2447 return (ret); 2448 } 2449 2450 /* 2451 * Returns with 2452 * 0 - success 2453 * ECONNABORTED - repository connection broken 2454 * - unknown libscf error 2455 * ECANCELED - s_inst was deleted 2456 * EPERM 2457 * EACCES 2458 * EROFS 2459 */ 2460 int 2461 libscf_write_start_pid(scf_instance_t *s_inst, pid_t pid) 2462 { 2463 scf_handle_t *h; 2464 scf_transaction_entry_t *t_pid; 2465 scf_value_t *v_pid; 2466 scf_propertygroup_t *pg; 2467 int ret = 0; 2468 2469 h = scf_instance_handle(s_inst); 2470 2471 pg = safe_scf_pg_create(h); 2472 t_pid = safe_scf_entry_create(h); 2473 v_pid = safe_scf_value_create(h); 2474 2475 get_pg: 2476 ret = libscf_inst_get_or_add_pg(s_inst, SCF_PG_RESTARTER, 2477 SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg); 2478 switch (ret) { 2479 case 0: 2480 break; 2481 2482 case ECONNABORTED: 2483 case ECANCELED: 2484 case EPERM: 2485 case EACCES: 2486 case EROFS: 2487 goto write_start_err; 2488 2489 default: 2490 bad_error("libscf_inst_get_or_add_pg", ret); 2491 } 2492 2493 scf_value_set_count(v_pid, pid); 2494 2495 ret = pg_set_prop_value(pg, SCF_PROPERTY_START_PID, v_pid); 2496 switch (ret) { 2497 case 0: 2498 case ECONNABORTED: 2499 case EPERM: 2500 case EACCES: 2501 case EROFS: 2502 break; 2503 2504 case ECANCELED: 2505 goto get_pg; 2506 2507 default: 2508 bad_error("pg_set_prop_value", ret); 2509 } 2510 2511 write_start_err: 2512 scf_entry_destroy(t_pid); 2513 scf_value_destroy(v_pid); 2514 scf_pg_destroy(pg); 2515 2516 return (ret); 2517 } 2518 2519 /* 2520 * Add a property indicating the instance log file. If the dir is 2521 * equal to LOG_PREFIX_EARLY, then the property restarter/alt_logfile 2522 * of the instance is used; otherwise, restarter/logfile is used. 2523 * 2524 * Returns 2525 * 0 - success 2526 * ECONNABORTED 2527 * ECANCELED 2528 * EPERM 2529 * EACCES 2530 * EROFS 2531 * EAGAIN 2532 */ 2533 int 2534 libscf_note_method_log(scf_instance_t *inst, const char *dir, const char *file) 2535 { 2536 scf_handle_t *h; 2537 scf_value_t *v; 2538 scf_propertygroup_t *pg; 2539 int ret = 0; 2540 char *logname; 2541 const char *propname; 2542 2543 h = scf_instance_handle(inst); 2544 pg = safe_scf_pg_create(h); 2545 v = safe_scf_value_create(h); 2546 2547 logname = uu_msprintf("%s%s", dir, file); 2548 2549 if (logname == NULL) { 2550 ret = errno; 2551 goto out; 2552 } 2553 2554 ret = libscf_inst_get_or_add_pg(inst, SCF_PG_RESTARTER, 2555 SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg); 2556 switch (ret) { 2557 case 0: 2558 break; 2559 2560 case ECONNABORTED: 2561 case ECANCELED: 2562 case EPERM: 2563 case EACCES: 2564 case EROFS: 2565 goto out; 2566 2567 default: 2568 bad_error("libscf_inst_get_or_add_pg", ret); 2569 } 2570 2571 (void) scf_value_set_astring(v, logname); 2572 2573 if (strcmp(LOG_PREFIX_EARLY, dir) == 0) 2574 propname = SCF_PROPERTY_ALT_LOGFILE; 2575 else 2576 propname = SCF_PROPERTY_LOGFILE; 2577 2578 ret = pg_set_prop_value(pg, propname, v); 2579 switch (ret) { 2580 case 0: 2581 case ECONNABORTED: 2582 case ECANCELED: 2583 case EPERM: 2584 case EACCES: 2585 case EROFS: 2586 break; 2587 2588 default: 2589 bad_error("pg_set_prop_value", ret); 2590 } 2591 2592 out: 2593 scf_pg_destroy(pg); 2594 scf_value_destroy(v); 2595 uu_free(logname); 2596 return (ret); 2597 } 2598 2599 /* 2600 * Returns 2601 * 0 - success 2602 * ENAMETOOLONG - name is too long 2603 * ECONNABORTED 2604 * ECANCELED 2605 * EPERM 2606 * EACCES 2607 * EROFS 2608 */ 2609 int 2610 libscf_write_method_status(scf_instance_t *s_inst, const char *name, 2611 int status) 2612 { 2613 scf_handle_t *h; 2614 scf_transaction_t *tx; 2615 scf_transaction_entry_t *e_time, *e_stat; 2616 scf_value_t *v_time, *v_stat; 2617 scf_propertygroup_t *pg; 2618 int ret = 0, r; 2619 char pname[30]; 2620 struct timeval tv; 2621 scf_error_t scfe; 2622 2623 if (strlen(name) + sizeof ("_method_waitstatus") > sizeof (pname)) 2624 return (ENAMETOOLONG); 2625 2626 h = scf_instance_handle(s_inst); 2627 2628 pg = safe_scf_pg_create(h); 2629 tx = safe_scf_transaction_create(h); 2630 e_time = safe_scf_entry_create(h); 2631 v_time = safe_scf_value_create(h); 2632 e_stat = safe_scf_entry_create(h); 2633 v_stat = safe_scf_value_create(h); 2634 2635 get_pg: 2636 ret = libscf_inst_get_or_add_pg(s_inst, SCF_PG_RESTARTER, 2637 SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg); 2638 switch (ret) { 2639 case 0: 2640 break; 2641 2642 case ECONNABORTED: 2643 case ECANCELED: 2644 case EPERM: 2645 case EACCES: 2646 case EROFS: 2647 goto out; 2648 2649 default: 2650 bad_error("libscf_inst_get_or_add_pg", ret); 2651 } 2652 2653 (void) gettimeofday(&tv, NULL); 2654 2655 r = scf_value_set_time(v_time, tv.tv_sec, tv.tv_usec * 1000); 2656 assert(r == 0); 2657 2658 scf_value_set_integer(v_stat, status); 2659 2660 for (;;) { 2661 if (scf_transaction_start(tx, pg) != 0) { 2662 switch (scf_error()) { 2663 case SCF_ERROR_CONNECTION_BROKEN: 2664 default: 2665 ret = ECONNABORTED; 2666 goto out; 2667 2668 case SCF_ERROR_DELETED: 2669 ret = ECANCELED; 2670 goto out; 2671 2672 case SCF_ERROR_PERMISSION_DENIED: 2673 ret = EPERM; 2674 goto out; 2675 2676 case SCF_ERROR_BACKEND_ACCESS: 2677 ret = EACCES; 2678 goto out; 2679 2680 case SCF_ERROR_BACKEND_READONLY: 2681 ret = EROFS; 2682 goto out; 2683 2684 case SCF_ERROR_NOT_SET: 2685 bad_error("scf_transaction_start", ret); 2686 } 2687 } 2688 2689 (void) snprintf(pname, sizeof (pname), "%s_method_timestamp", 2690 name); 2691 ret = transaction_add_set(tx, e_time, pname, SCF_TYPE_TIME); 2692 switch (ret) { 2693 case 0: 2694 break; 2695 2696 case ECONNABORTED: 2697 case ECANCELED: 2698 goto out; 2699 2700 default: 2701 bad_error("transaction_add_set", ret); 2702 } 2703 2704 r = scf_entry_add_value(e_time, v_time); 2705 assert(r == 0); 2706 2707 (void) snprintf(pname, sizeof (pname), "%s_method_waitstatus", 2708 name); 2709 ret = transaction_add_set(tx, e_stat, pname, SCF_TYPE_INTEGER); 2710 switch (ret) { 2711 case 0: 2712 break; 2713 2714 case ECONNABORTED: 2715 case ECANCELED: 2716 goto out; 2717 2718 default: 2719 bad_error("transaction_add_set", ret); 2720 } 2721 2722 r = scf_entry_add_value(e_stat, v_stat); 2723 if (r != 0) 2724 bad_error("scf_entry_add_value", scf_error()); 2725 2726 r = scf_transaction_commit(tx); 2727 if (r == 1) 2728 break; 2729 if (r != 0) { 2730 scfe = scf_error(); 2731 scf_transaction_reset_all(tx); 2732 switch (scfe) { 2733 case SCF_ERROR_CONNECTION_BROKEN: 2734 default: 2735 ret = ECONNABORTED; 2736 goto out; 2737 2738 case SCF_ERROR_DELETED: 2739 ret = ECANCELED; 2740 goto out; 2741 2742 case SCF_ERROR_PERMISSION_DENIED: 2743 ret = EPERM; 2744 goto out; 2745 2746 case SCF_ERROR_BACKEND_ACCESS: 2747 ret = EACCES; 2748 goto out; 2749 2750 case SCF_ERROR_BACKEND_READONLY: 2751 ret = EROFS; 2752 goto out; 2753 2754 case SCF_ERROR_NOT_SET: 2755 bad_error("scf_transaction_commit", scfe); 2756 } 2757 } 2758 2759 scf_transaction_reset_all(tx); 2760 2761 if (scf_pg_update(pg) == -1) { 2762 switch (scf_error()) { 2763 case SCF_ERROR_CONNECTION_BROKEN: 2764 default: 2765 ret = ECONNABORTED; 2766 goto out; 2767 2768 case SCF_ERROR_DELETED: 2769 ret = ECANCELED; 2770 goto out; 2771 2772 case SCF_ERROR_NOT_SET: 2773 bad_error("scf_pg_update", scf_error()); 2774 } 2775 } 2776 } 2777 2778 out: 2779 scf_transaction_destroy(tx); 2780 scf_entry_destroy(e_time); 2781 scf_value_destroy(v_time); 2782 scf_entry_destroy(e_stat); 2783 scf_value_destroy(v_stat); 2784 scf_pg_destroy(pg); 2785 2786 return (ret); 2787 } 2788 2789 extern int32_t stn_global; 2790 /* 2791 * Call dgraph_add_instance() for each instance in the repository. 2792 */ 2793 void 2794 libscf_populate_graph(scf_handle_t *h) 2795 { 2796 scf_scope_t *scope; 2797 scf_service_t *svc; 2798 scf_instance_t *inst; 2799 scf_iter_t *svc_iter; 2800 scf_iter_t *inst_iter; 2801 2802 scope = safe_scf_scope_create(h); 2803 svc = safe_scf_service_create(h); 2804 inst = safe_scf_instance_create(h); 2805 svc_iter = safe_scf_iter_create(h); 2806 inst_iter = safe_scf_iter_create(h); 2807 2808 deathrow_init(); 2809 2810 stn_global = libscf_get_global_stn_tset(h); 2811 2812 if (scf_handle_get_local_scope(h, scope) != 2813 SCF_SUCCESS) 2814 uu_die("retrieving local scope failed: %s\n", 2815 scf_strerror(scf_error())); 2816 2817 if (scf_iter_scope_services(svc_iter, scope) == -1) 2818 uu_die("walking local scope's services failed\n"); 2819 2820 while (scf_iter_next_service(svc_iter, svc) > 0) { 2821 if (scf_iter_service_instances(inst_iter, svc) == -1) 2822 uu_die("unable to walk service's instances"); 2823 2824 while (scf_iter_next_instance(inst_iter, inst) > 0) { 2825 char *fmri; 2826 2827 if (libscf_instance_get_fmri(inst, &fmri) == 0) { 2828 int err; 2829 2830 err = dgraph_add_instance(fmri, inst, B_TRUE); 2831 if (err != 0 && err != EEXIST) 2832 log_error(LOG_WARNING, 2833 "Failed to add %s (%s).\n", fmri, 2834 strerror(err)); 2835 startd_free(fmri, max_scf_fmri_size); 2836 } 2837 } 2838 } 2839 2840 deathrow_fini(); 2841 2842 scf_iter_destroy(inst_iter); 2843 scf_iter_destroy(svc_iter); 2844 scf_instance_destroy(inst); 2845 scf_service_destroy(svc); 2846 scf_scope_destroy(scope); 2847 } 2848 2849 /* 2850 * Monitors get handled differently since there can be multiple of them. 2851 * 2852 * Returns exec string on success. If method not defined, returns 2853 * LIBSCF_PGROUP_ABSENT; if exec property missing, returns 2854 * LIBSCF_PROPERTY_ABSENT. Returns LIBSCF_PROPERTY_ERROR on other failures. 2855 */ 2856 char * 2857 libscf_get_method(scf_handle_t *h, int type, restarter_inst_t *inst, 2858 scf_snapshot_t *snap, method_restart_t *restart_on, uint_t *cte_mask, 2859 uint8_t *need_sessionp, uint64_t *timeout, uint8_t *timeout_retry) 2860 { 2861 scf_instance_t *scf_inst = NULL; 2862 scf_propertygroup_t *pg = NULL, *pg_startd = NULL; 2863 scf_property_t *prop = NULL; 2864 const char *name; 2865 char *method = startd_alloc(max_scf_value_size); 2866 char *ig = startd_alloc(max_scf_value_size); 2867 char *restart = startd_alloc(max_scf_value_size); 2868 char *ret; 2869 int error = 0, r; 2870 2871 scf_inst = safe_scf_instance_create(h); 2872 pg = safe_scf_pg_create(h); 2873 pg_startd = safe_scf_pg_create(h); 2874 prop = safe_scf_property_create(h); 2875 2876 ret = NULL; 2877 2878 *restart_on = METHOD_RESTART_UNKNOWN; 2879 2880 switch (type) { 2881 case METHOD_START: 2882 name = "start"; 2883 break; 2884 case METHOD_STOP: 2885 name = "stop"; 2886 break; 2887 case METHOD_REFRESH: 2888 name = "refresh"; 2889 break; 2890 default: 2891 error = LIBSCF_PROPERTY_ERROR; 2892 goto get_method_cleanup; 2893 } 2894 2895 if (scf_handle_decode_fmri(h, inst->ri_i.i_fmri, NULL, NULL, scf_inst, 2896 NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) { 2897 log_error(LOG_WARNING, 2898 "%s: get_method decode instance FMRI failed: %s\n", 2899 inst->ri_i.i_fmri, scf_strerror(scf_error())); 2900 error = LIBSCF_PROPERTY_ERROR; 2901 goto get_method_cleanup; 2902 } 2903 2904 if (scf_instance_get_pg_composed(scf_inst, snap, name, pg) == -1) { 2905 if (scf_error() == SCF_ERROR_NOT_FOUND) 2906 error = LIBSCF_PGROUP_ABSENT; 2907 else 2908 error = LIBSCF_PROPERTY_ERROR; 2909 goto get_method_cleanup; 2910 } 2911 2912 if (scf_pg_get_property(pg, SCF_PROPERTY_EXEC, prop) == -1) { 2913 if (scf_error() == SCF_ERROR_NOT_FOUND) 2914 error = LIBSCF_PROPERTY_ABSENT; 2915 else 2916 error = LIBSCF_PROPERTY_ERROR; 2917 goto get_method_cleanup; 2918 } 2919 2920 error = libscf_read_single_astring(h, prop, &method); 2921 if (error != 0) { 2922 log_error(LOG_WARNING, 2923 "%s: get_method failed: can't get a single astring " 2924 "from %s/%s\n", inst->ri_i.i_fmri, name, SCF_PROPERTY_EXEC); 2925 goto get_method_cleanup; 2926 } 2927 2928 error = expand_method_tokens(method, scf_inst, snap, type, &ret); 2929 if (error != 0) { 2930 log_instance(inst, B_TRUE, "Could not expand method tokens " 2931 "in \"%s\": %s.", method, ret); 2932 error = LIBSCF_PROPERTY_ERROR; 2933 goto get_method_cleanup; 2934 } 2935 2936 r = get_count(pg, SCF_PROPERTY_TIMEOUT, timeout); 2937 switch (r) { 2938 case 0: 2939 break; 2940 2941 case ECONNABORTED: 2942 error = LIBSCF_PROPERTY_ERROR; 2943 goto get_method_cleanup; 2944 2945 case EINVAL: 2946 log_instance(inst, B_TRUE, "%s/%s is multi-valued or not of " 2947 "type count. Using infinite timeout.", name, 2948 SCF_PROPERTY_TIMEOUT); 2949 /* FALLTHROUGH */ 2950 case ECANCELED: 2951 case ENOENT: 2952 *timeout = METHOD_TIMEOUT_INFINITE; 2953 break; 2954 2955 case EACCES: 2956 default: 2957 bad_error("get_count", r); 2958 } 2959 2960 /* Both 0 and -1 (ugh) are considered infinite timeouts. */ 2961 if (*timeout == -1 || *timeout == 0) 2962 *timeout = METHOD_TIMEOUT_INFINITE; 2963 2964 if (scf_instance_get_pg_composed(scf_inst, snap, SCF_PG_STARTD, 2965 pg_startd) == -1) { 2966 switch (scf_error()) { 2967 case SCF_ERROR_CONNECTION_BROKEN: 2968 case SCF_ERROR_DELETED: 2969 error = LIBSCF_PROPERTY_ERROR; 2970 goto get_method_cleanup; 2971 2972 case SCF_ERROR_NOT_FOUND: 2973 *cte_mask = 0; 2974 break; 2975 2976 case SCF_ERROR_INVALID_ARGUMENT: 2977 case SCF_ERROR_HANDLE_MISMATCH: 2978 case SCF_ERROR_NOT_BOUND: 2979 case SCF_ERROR_NOT_SET: 2980 bad_error("scf_instance_get_pg_composed", scf_error()); 2981 } 2982 } else { 2983 if (scf_pg_get_property(pg_startd, SCF_PROPERTY_IGNORE, 2984 prop) == -1) { 2985 if (scf_error() == SCF_ERROR_NOT_FOUND) 2986 *cte_mask = 0; 2987 else { 2988 error = LIBSCF_PROPERTY_ERROR; 2989 goto get_method_cleanup; 2990 } 2991 } else { 2992 error = libscf_read_single_astring(h, prop, &ig); 2993 if (error != 0) { 2994 log_error(LOG_WARNING, 2995 "%s: get_method failed: can't get a single " 2996 "astring from %s/%s\n", inst->ri_i.i_fmri, 2997 name, SCF_PROPERTY_IGNORE); 2998 goto get_method_cleanup; 2999 } 3000 3001 if (strcmp(ig, "core") == 0) 3002 *cte_mask = CT_PR_EV_CORE; 3003 else if (strcmp(ig, "signal") == 0) 3004 *cte_mask = CT_PR_EV_SIGNAL; 3005 else if (strcmp(ig, "core,signal") == 0 || 3006 strcmp(ig, "signal,core") == 0) 3007 *cte_mask = CT_PR_EV_CORE | CT_PR_EV_SIGNAL; 3008 else 3009 *cte_mask = 0; 3010 } 3011 3012 r = get_boolean(pg_startd, SCF_PROPERTY_NEED_SESSION, 3013 need_sessionp); 3014 switch (r) { 3015 case 0: 3016 break; 3017 3018 case ECONNABORTED: 3019 error = LIBSCF_PROPERTY_ERROR; 3020 goto get_method_cleanup; 3021 3022 case ECANCELED: 3023 case ENOENT: 3024 case EINVAL: 3025 *need_sessionp = 0; 3026 break; 3027 3028 case EACCES: 3029 default: 3030 bad_error("get_boolean", r); 3031 } 3032 3033 /* 3034 * Determine whether service has overriden retry after 3035 * method timeout. Default to retry if no value is 3036 * specified. 3037 */ 3038 r = get_boolean(pg_startd, SCF_PROPERTY_TIMEOUT_RETRY, 3039 timeout_retry); 3040 switch (r) { 3041 case 0: 3042 break; 3043 3044 case ECONNABORTED: 3045 error = LIBSCF_PROPERTY_ERROR; 3046 goto get_method_cleanup; 3047 3048 case ECANCELED: 3049 case ENOENT: 3050 case EINVAL: 3051 *timeout_retry = 1; 3052 break; 3053 3054 case EACCES: 3055 default: 3056 bad_error("get_boolean", r); 3057 } 3058 } 3059 3060 if (type != METHOD_START) 3061 goto get_method_cleanup; 3062 3063 /* Only start methods need to honor the restart_on property. */ 3064 3065 if (scf_pg_get_property(pg, SCF_PROPERTY_RESTART_ON, prop) == -1) { 3066 if (scf_error() == SCF_ERROR_NOT_FOUND) 3067 *restart_on = METHOD_RESTART_ALL; 3068 else 3069 error = LIBSCF_PROPERTY_ERROR; 3070 goto get_method_cleanup; 3071 } 3072 3073 error = libscf_read_single_astring(h, prop, &restart); 3074 if (error != 0) { 3075 log_error(LOG_WARNING, 3076 "%s: get_method failed: can't get a single astring " 3077 "from %s/%s\n", inst->ri_i.i_fmri, name, 3078 SCF_PROPERTY_RESTART_ON); 3079 goto get_method_cleanup; 3080 } 3081 3082 if (strcmp(restart, "all") == 0) 3083 *restart_on = METHOD_RESTART_ALL; 3084 else if (strcmp(restart, "external_fault") == 0) 3085 *restart_on = METHOD_RESTART_EXTERNAL_FAULT; 3086 else if (strcmp(restart, "any_fault") == 0) 3087 *restart_on = METHOD_RESTART_ANY_FAULT; 3088 3089 get_method_cleanup: 3090 startd_free(ig, max_scf_value_size); 3091 startd_free(method, max_scf_value_size); 3092 startd_free(restart, max_scf_value_size); 3093 3094 scf_instance_destroy(scf_inst); 3095 scf_pg_destroy(pg); 3096 scf_pg_destroy(pg_startd); 3097 scf_property_destroy(prop); 3098 3099 if (error != 0 && ret != NULL) { 3100 free(ret); 3101 ret = NULL; 3102 } 3103 3104 errno = error; 3105 return (ret); 3106 } 3107 3108 /* 3109 * Returns 1 if we've reached the fault threshold 3110 */ 3111 int 3112 update_fault_count(restarter_inst_t *inst, int type) 3113 { 3114 assert(type == FAULT_COUNT_INCR || type == FAULT_COUNT_RESET); 3115 3116 if (type == FAULT_COUNT_INCR) { 3117 inst->ri_i.i_fault_count++; 3118 log_framework(LOG_INFO, "%s: Increasing fault count to %d\n", 3119 inst->ri_i.i_fmri, inst->ri_i.i_fault_count); 3120 } 3121 if (type == FAULT_COUNT_RESET) 3122 inst->ri_i.i_fault_count = 0; 3123 3124 if (inst->ri_i.i_fault_count >= FAULT_THRESHOLD) 3125 return (1); 3126 3127 return (0); 3128 } 3129 3130 /* 3131 * int libscf_unset_action() 3132 * Delete any pending timestamps for the specified action which is 3133 * older than the supplied ts. 3134 * 3135 * Returns 0 on success, ECONNABORTED, EACCES, or EPERM on failure. 3136 */ 3137 int 3138 libscf_unset_action(scf_handle_t *h, scf_propertygroup_t *pg, 3139 admin_action_t a, hrtime_t ts) 3140 { 3141 scf_transaction_t *t; 3142 scf_transaction_entry_t *e; 3143 scf_property_t *prop; 3144 scf_value_t *val; 3145 hrtime_t rep_ts; 3146 int ret = 0, r; 3147 3148 t = safe_scf_transaction_create(h); 3149 e = safe_scf_entry_create(h); 3150 prop = safe_scf_property_create(h); 3151 val = safe_scf_value_create(h); 3152 3153 for (;;) { 3154 if (scf_pg_update(pg) == -1) { 3155 switch (scf_error()) { 3156 case SCF_ERROR_CONNECTION_BROKEN: 3157 default: 3158 ret = ECONNABORTED; 3159 goto unset_action_cleanup; 3160 3161 case SCF_ERROR_DELETED: 3162 goto unset_action_cleanup; 3163 3164 case SCF_ERROR_NOT_SET: 3165 assert(0); 3166 abort(); 3167 } 3168 } 3169 3170 if (scf_transaction_start(t, pg) == -1) { 3171 switch (scf_error()) { 3172 case SCF_ERROR_CONNECTION_BROKEN: 3173 default: 3174 ret = ECONNABORTED; 3175 goto unset_action_cleanup; 3176 3177 case SCF_ERROR_DELETED: 3178 goto unset_action_cleanup; 3179 3180 case SCF_ERROR_PERMISSION_DENIED: 3181 ret = EPERM; 3182 goto unset_action_cleanup; 3183 3184 case SCF_ERROR_BACKEND_ACCESS: 3185 case SCF_ERROR_BACKEND_READONLY: 3186 ret = EACCES; 3187 goto unset_action_cleanup; 3188 3189 case SCF_ERROR_IN_USE: 3190 case SCF_ERROR_HANDLE_MISMATCH: 3191 case SCF_ERROR_NOT_SET: 3192 assert(0); 3193 abort(); 3194 } 3195 } 3196 3197 /* Return failure only if the property hasn't been deleted. */ 3198 if (scf_pg_get_property(pg, admin_actions[a], prop) == -1) { 3199 switch (scf_error()) { 3200 case SCF_ERROR_CONNECTION_BROKEN: 3201 default: 3202 ret = ECONNABORTED; 3203 goto unset_action_cleanup; 3204 3205 case SCF_ERROR_DELETED: 3206 case SCF_ERROR_NOT_FOUND: 3207 goto unset_action_cleanup; 3208 3209 case SCF_ERROR_HANDLE_MISMATCH: 3210 case SCF_ERROR_INVALID_ARGUMENT: 3211 case SCF_ERROR_NOT_SET: 3212 assert(0); 3213 abort(); 3214 } 3215 } 3216 3217 if (scf_property_get_value(prop, val) == -1) { 3218 switch (scf_error()) { 3219 case SCF_ERROR_CONNECTION_BROKEN: 3220 default: 3221 ret = ECONNABORTED; 3222 goto unset_action_cleanup; 3223 3224 case SCF_ERROR_DELETED: 3225 case SCF_ERROR_NOT_FOUND: 3226 goto unset_action_cleanup; 3227 3228 case SCF_ERROR_CONSTRAINT_VIOLATED: 3229 /* 3230 * More than one value was associated with 3231 * this property -- this is incorrect. Take 3232 * the opportunity to clean up and clear the 3233 * entire property. 3234 */ 3235 rep_ts = ts; 3236 break; 3237 3238 case SCF_ERROR_PERMISSION_DENIED: 3239 case SCF_ERROR_NOT_SET: 3240 assert(0); 3241 abort(); 3242 } 3243 } else if (scf_value_get_integer(val, &rep_ts) == -1) { 3244 assert(scf_error() == SCF_ERROR_TYPE_MISMATCH); 3245 rep_ts = 0; 3246 } 3247 3248 /* Repository ts is more current. Don't clear the action. */ 3249 if (rep_ts > ts) 3250 goto unset_action_cleanup; 3251 3252 r = scf_transaction_property_change_type(t, e, 3253 admin_actions[a], SCF_TYPE_INTEGER); 3254 assert(r == 0); 3255 3256 r = scf_transaction_commit(t); 3257 if (r == 1) 3258 break; 3259 3260 if (r != 0) { 3261 switch (scf_error()) { 3262 case SCF_ERROR_CONNECTION_BROKEN: 3263 default: 3264 ret = ECONNABORTED; 3265 goto unset_action_cleanup; 3266 3267 case SCF_ERROR_DELETED: 3268 break; 3269 3270 case SCF_ERROR_PERMISSION_DENIED: 3271 ret = EPERM; 3272 goto unset_action_cleanup; 3273 3274 case SCF_ERROR_BACKEND_ACCESS: 3275 case SCF_ERROR_BACKEND_READONLY: 3276 ret = EACCES; 3277 goto unset_action_cleanup; 3278 3279 case SCF_ERROR_INVALID_ARGUMENT: 3280 case SCF_ERROR_NOT_SET: 3281 assert(0); 3282 abort(); 3283 } 3284 } 3285 3286 scf_transaction_reset(t); 3287 } 3288 3289 unset_action_cleanup: 3290 scf_transaction_destroy(t); 3291 scf_entry_destroy(e); 3292 scf_property_destroy(prop); 3293 scf_value_destroy(val); 3294 3295 return (ret); 3296 } 3297 3298 /* 3299 * Decorates & binds hndl. hndl must be unbound. Returns 3300 * 0 - success 3301 * -1 - repository server is not running 3302 * -1 - repository server is out of resources 3303 */ 3304 static int 3305 handle_decorate_and_bind(scf_handle_t *hndl) 3306 { 3307 scf_value_t *door_dec_value; 3308 3309 door_dec_value = safe_scf_value_create(hndl); 3310 3311 /* 3312 * Decorate if alternate door path set. 3313 */ 3314 if (st->st_door_path) { 3315 if (scf_value_set_astring(door_dec_value, st->st_door_path) != 3316 0) 3317 uu_die("$STARTD_ALT_DOOR is too long.\n"); 3318 3319 if (scf_handle_decorate(hndl, "door_path", door_dec_value) != 0) 3320 bad_error("scf_handle_decorate", scf_error()); 3321 } 3322 3323 scf_value_destroy(door_dec_value); 3324 3325 if (scf_handle_bind(hndl) == 0) 3326 return (0); 3327 3328 switch (scf_error()) { 3329 case SCF_ERROR_NO_SERVER: 3330 case SCF_ERROR_NO_RESOURCES: 3331 return (-1); 3332 3333 case SCF_ERROR_INVALID_ARGUMENT: 3334 case SCF_ERROR_IN_USE: 3335 default: 3336 bad_error("scf_handle_bind", scf_error()); 3337 /* NOTREACHED */ 3338 } 3339 } 3340 3341 scf_handle_t * 3342 libscf_handle_create_bound(scf_version_t v) 3343 { 3344 scf_handle_t *hndl = scf_handle_create(v); 3345 3346 if (hndl == NULL) 3347 return (hndl); 3348 3349 if (handle_decorate_and_bind(hndl) == 0) 3350 return (hndl); 3351 3352 scf_handle_destroy(hndl); 3353 return (NULL); 3354 } 3355 3356 void 3357 libscf_handle_rebind(scf_handle_t *h) 3358 { 3359 (void) scf_handle_unbind(h); 3360 3361 MUTEX_LOCK(&st->st_configd_live_lock); 3362 3363 /* 3364 * Try to rebind the handle before sleeping in case the server isn't 3365 * really dead. 3366 */ 3367 while (handle_decorate_and_bind(h) != 0) 3368 (void) pthread_cond_wait(&st->st_configd_live_cv, 3369 &st->st_configd_live_lock); 3370 3371 MUTEX_UNLOCK(&st->st_configd_live_lock); 3372 } 3373 3374 /* 3375 * Create a handle and try to bind it until it succeeds. Always returns 3376 * a bound handle. 3377 */ 3378 scf_handle_t * 3379 libscf_handle_create_bound_loop() 3380 { 3381 scf_handle_t *h; 3382 3383 while ((h = scf_handle_create(SCF_VERSION)) == NULL) { 3384 /* This should have been caught earlier. */ 3385 assert(scf_error() != SCF_ERROR_VERSION_MISMATCH); 3386 (void) sleep(2); 3387 } 3388 3389 if (handle_decorate_and_bind(h) != 0) 3390 libscf_handle_rebind(h); 3391 3392 return (h); 3393 } 3394 3395 /* 3396 * Call cb for each dependency property group of inst. cb is invoked with 3397 * a pointer to the scf_propertygroup_t and arg. If the repository connection 3398 * is broken, returns ECONNABORTED. If inst is deleted, returns ECANCELED. 3399 * If cb returns non-zero, the walk is stopped and EINTR is returned. 3400 * Otherwise returns 0. 3401 */ 3402 int 3403 walk_dependency_pgs(scf_instance_t *inst, callback_t cb, void *arg) 3404 { 3405 scf_handle_t *h; 3406 scf_snapshot_t *snap; 3407 scf_iter_t *iter; 3408 scf_propertygroup_t *pg; 3409 int r; 3410 3411 h = scf_instance_handle(inst); 3412 3413 iter = safe_scf_iter_create(h); 3414 pg = safe_scf_pg_create(h); 3415 3416 snap = libscf_get_running_snapshot(inst); 3417 3418 if (scf_iter_instance_pgs_typed_composed(iter, inst, snap, 3419 SCF_GROUP_DEPENDENCY) != 0) { 3420 scf_snapshot_destroy(snap); 3421 scf_pg_destroy(pg); 3422 scf_iter_destroy(iter); 3423 switch (scf_error()) { 3424 case SCF_ERROR_CONNECTION_BROKEN: 3425 default: 3426 return (ECONNABORTED); 3427 3428 case SCF_ERROR_DELETED: 3429 return (ECANCELED); 3430 3431 case SCF_ERROR_HANDLE_MISMATCH: 3432 case SCF_ERROR_INVALID_ARGUMENT: 3433 case SCF_ERROR_NOT_SET: 3434 assert(0); 3435 abort(); 3436 } 3437 } 3438 3439 for (;;) { 3440 r = scf_iter_next_pg(iter, pg); 3441 if (r == 0) 3442 break; 3443 if (r == -1) { 3444 scf_snapshot_destroy(snap); 3445 scf_pg_destroy(pg); 3446 scf_iter_destroy(iter); 3447 3448 switch (scf_error()) { 3449 case SCF_ERROR_CONNECTION_BROKEN: 3450 return (ECONNABORTED); 3451 3452 case SCF_ERROR_DELETED: 3453 return (ECANCELED); 3454 3455 case SCF_ERROR_NOT_SET: 3456 case SCF_ERROR_INVALID_ARGUMENT: 3457 case SCF_ERROR_NOT_BOUND: 3458 case SCF_ERROR_HANDLE_MISMATCH: 3459 default: 3460 bad_error("scf_iter_next_pg", scf_error()); 3461 } 3462 } 3463 3464 r = cb(pg, arg); 3465 3466 if (r != 0) 3467 break; 3468 } 3469 3470 scf_snapshot_destroy(snap); 3471 scf_pg_destroy(pg); 3472 scf_iter_destroy(iter); 3473 3474 return (r == 0 ? 0 : EINTR); 3475 } 3476 3477 /* 3478 * Call cb for each of the string values of prop. cb is invoked with 3479 * a pointer to the string and arg. If the connection to the repository is 3480 * broken, ECONNABORTED is returned. If the property is deleted, ECANCELED is 3481 * returned. If the property does not have astring type, EINVAL is returned. 3482 * If cb returns non-zero, the walk is stopped and EINTR is returned. 3483 * Otherwise 0 is returned. 3484 */ 3485 int 3486 walk_property_astrings(scf_property_t *prop, callback_t cb, void *arg) 3487 { 3488 scf_handle_t *h; 3489 scf_value_t *val; 3490 scf_iter_t *iter; 3491 char *buf; 3492 int r; 3493 ssize_t sz; 3494 3495 if (scf_property_is_type(prop, SCF_TYPE_ASTRING) != 0) { 3496 switch (scf_error()) { 3497 case SCF_ERROR_CONNECTION_BROKEN: 3498 default: 3499 return (ECONNABORTED); 3500 3501 case SCF_ERROR_DELETED: 3502 return (ECANCELED); 3503 3504 case SCF_ERROR_TYPE_MISMATCH: 3505 return (EINVAL); 3506 3507 case SCF_ERROR_NOT_SET: 3508 assert(0); 3509 abort(); 3510 } 3511 } 3512 3513 h = scf_property_handle(prop); 3514 3515 val = safe_scf_value_create(h); 3516 iter = safe_scf_iter_create(h); 3517 3518 if (scf_iter_property_values(iter, prop) != 0) { 3519 scf_iter_destroy(iter); 3520 scf_value_destroy(val); 3521 switch (scf_error()) { 3522 case SCF_ERROR_CONNECTION_BROKEN: 3523 default: 3524 return (ECONNABORTED); 3525 3526 case SCF_ERROR_DELETED: 3527 return (ECANCELED); 3528 3529 case SCF_ERROR_HANDLE_MISMATCH: 3530 case SCF_ERROR_NOT_SET: 3531 assert(0); 3532 abort(); 3533 } 3534 } 3535 3536 buf = startd_alloc(max_scf_value_size); 3537 3538 for (;;) { 3539 r = scf_iter_next_value(iter, val); 3540 if (r < 0) { 3541 startd_free(buf, max_scf_value_size); 3542 scf_iter_destroy(iter); 3543 scf_value_destroy(val); 3544 3545 switch (scf_error()) { 3546 case SCF_ERROR_CONNECTION_BROKEN: 3547 return (ECONNABORTED); 3548 3549 case SCF_ERROR_DELETED: 3550 return (ECANCELED); 3551 3552 case SCF_ERROR_NOT_SET: 3553 case SCF_ERROR_INVALID_ARGUMENT: 3554 case SCF_ERROR_NOT_BOUND: 3555 case SCF_ERROR_HANDLE_MISMATCH: 3556 case SCF_ERROR_PERMISSION_DENIED: 3557 default: 3558 bad_error("scf_iter_next_value", scf_error()); 3559 } 3560 } 3561 if (r == 0) 3562 break; 3563 3564 sz = scf_value_get_astring(val, buf, max_scf_value_size); 3565 assert(sz >= 0); 3566 3567 r = cb(buf, arg); 3568 3569 if (r != 0) 3570 break; 3571 } 3572 3573 startd_free(buf, max_scf_value_size); 3574 scf_value_destroy(val); 3575 scf_iter_destroy(iter); 3576 3577 return (r == 0 ? 0 : EINTR); 3578 } 3579 3580 /* 3581 * Returns 0 or ECONNABORTED. 3582 */ 3583 int 3584 libscf_create_self(scf_handle_t *h) 3585 { 3586 scf_scope_t *scope; 3587 scf_service_t *svc; 3588 scf_instance_t *inst; 3589 instance_data_t idata; 3590 int ret = 0, r; 3591 ctid_t ctid; 3592 uint64_t uint64; 3593 uint_t count = 0, msecs = ALLOC_DELAY; 3594 3595 const char * const startd_svc = "system/svc/restarter"; 3596 const char * const startd_inst = "default"; 3597 3598 /* If SCF_SERVICE_STARTD changes, our strings must change, too. */ 3599 assert(strcmp(SCF_SERVICE_STARTD, 3600 "svc:/system/svc/restarter:default") == 0); 3601 3602 scope = safe_scf_scope_create(h); 3603 svc = safe_scf_service_create(h); 3604 inst = safe_scf_instance_create(h); 3605 3606 if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, scope) != 0) { 3607 assert(scf_error() == SCF_ERROR_CONNECTION_BROKEN); 3608 ret = ECONNABORTED; 3609 goto out; 3610 } 3611 3612 get_svc: 3613 if (scf_scope_get_service(scope, startd_svc, svc) != 0) { 3614 switch (scf_error()) { 3615 case SCF_ERROR_CONNECTION_BROKEN: 3616 case SCF_ERROR_DELETED: 3617 default: 3618 ret = ECONNABORTED; 3619 goto out; 3620 3621 case SCF_ERROR_NOT_FOUND: 3622 break; 3623 3624 case SCF_ERROR_HANDLE_MISMATCH: 3625 case SCF_ERROR_INVALID_ARGUMENT: 3626 case SCF_ERROR_NOT_SET: 3627 bad_error("scf_scope_get_service", scf_error()); 3628 } 3629 3630 add_svc: 3631 if (scf_scope_add_service(scope, startd_svc, svc) != 0) { 3632 switch (scf_error()) { 3633 case SCF_ERROR_CONNECTION_BROKEN: 3634 case SCF_ERROR_DELETED: 3635 default: 3636 ret = ECONNABORTED; 3637 goto out; 3638 3639 case SCF_ERROR_EXISTS: 3640 goto get_svc; 3641 3642 case SCF_ERROR_PERMISSION_DENIED: 3643 case SCF_ERROR_BACKEND_ACCESS: 3644 case SCF_ERROR_BACKEND_READONLY: 3645 uu_warn("Could not create %s: %s\n", 3646 SCF_SERVICE_STARTD, 3647 scf_strerror(scf_error())); 3648 goto out; 3649 3650 case SCF_ERROR_HANDLE_MISMATCH: 3651 case SCF_ERROR_INVALID_ARGUMENT: 3652 case SCF_ERROR_NOT_SET: 3653 bad_error("scf_scope_add_service", scf_error()); 3654 } 3655 } 3656 } 3657 3658 if (scf_service_get_instance(svc, startd_inst, NULL) == 0) 3659 goto out; 3660 3661 switch (scf_error()) { 3662 case SCF_ERROR_CONNECTION_BROKEN: 3663 default: 3664 ret = ECONNABORTED; 3665 goto out; 3666 3667 case SCF_ERROR_NOT_FOUND: 3668 break; 3669 3670 case SCF_ERROR_DELETED: 3671 goto add_svc; 3672 3673 case SCF_ERROR_HANDLE_MISMATCH: 3674 case SCF_ERROR_INVALID_ARGUMENT: 3675 case SCF_ERROR_NOT_SET: 3676 bad_error("scf_service_get_instance", scf_error()); 3677 } 3678 3679 add_inst: 3680 if (scf_service_add_instance(svc, startd_inst, inst) != 0) { 3681 switch (scf_error()) { 3682 case SCF_ERROR_CONNECTION_BROKEN: 3683 default: 3684 ret = ECONNABORTED; 3685 goto out; 3686 3687 case SCF_ERROR_EXISTS: 3688 break; 3689 3690 case SCF_ERROR_PERMISSION_DENIED: 3691 case SCF_ERROR_BACKEND_ACCESS: 3692 uu_die("Could not create %s: %s\n", SCF_SERVICE_STARTD, 3693 scf_strerror(scf_error())); 3694 /* NOTREACHED */ 3695 3696 case SCF_ERROR_BACKEND_READONLY: 3697 log_error(LOG_NOTICE, 3698 "Could not create %s: backend readonly.\n", 3699 SCF_SERVICE_STARTD); 3700 goto out; 3701 3702 case SCF_ERROR_DELETED: 3703 goto add_svc; 3704 3705 case SCF_ERROR_HANDLE_MISMATCH: 3706 case SCF_ERROR_INVALID_ARGUMENT: 3707 case SCF_ERROR_NOT_SET: 3708 bad_error("scf_service_add_instance", scf_error()); 3709 } 3710 } 3711 3712 /* Set start time. */ 3713 idata.i_fmri = SCF_SERVICE_STARTD; 3714 idata.i_state = RESTARTER_STATE_NONE; 3715 idata.i_next_state = RESTARTER_STATE_NONE; 3716 set_state: 3717 switch (r = _restarter_commit_states(h, &idata, 3718 RESTARTER_STATE_ONLINE, RESTARTER_STATE_NONE, 3719 restarter_get_str_short(restarter_str_insert_in_graph))) { 3720 case 0: 3721 break; 3722 3723 case ENOMEM: 3724 ++count; 3725 if (count < ALLOC_RETRY) { 3726 (void) poll(NULL, 0, msecs); 3727 msecs *= ALLOC_DELAY_MULT; 3728 goto set_state; 3729 } 3730 3731 uu_die("Insufficient memory.\n"); 3732 /* NOTREACHED */ 3733 3734 case ECONNABORTED: 3735 ret = ECONNABORTED; 3736 goto out; 3737 3738 case ENOENT: 3739 goto add_inst; 3740 3741 case EPERM: 3742 case EACCES: 3743 case EROFS: 3744 uu_warn("Could not timestamp %s: %s\n", idata.i_fmri, 3745 strerror(r)); 3746 break; 3747 3748 case EINVAL: 3749 default: 3750 bad_error("_restarter_commit_states", r); 3751 } 3752 3753 /* Set general/enabled. */ 3754 ret = libscf_inst_set_boolean_prop(inst, SCF_PG_GENERAL, 3755 SCF_PG_GENERAL_TYPE, SCF_PG_GENERAL_FLAGS, SCF_PROPERTY_ENABLED, 1); 3756 switch (ret) { 3757 case 0: 3758 case ECONNABORTED: 3759 case EPERM: 3760 case EACCES: 3761 case EROFS: 3762 break; 3763 3764 case ECANCELED: 3765 goto add_inst; 3766 3767 default: 3768 bad_error("libscf_inst_set_boolean_prop", ret); 3769 } 3770 3771 ret = libscf_write_start_pid(inst, getpid()); 3772 switch (ret) { 3773 case 0: 3774 case ECONNABORTED: 3775 case EPERM: 3776 case EACCES: 3777 case EROFS: 3778 break; 3779 3780 case ECANCELED: 3781 goto add_inst; 3782 3783 default: 3784 bad_error("libscf_write_start_pid", ret); 3785 } 3786 3787 ctid = proc_get_ctid(); 3788 if (ctid > 0) { 3789 3790 uint64 = (uint64_t)ctid; 3791 ret = libscf_inst_set_count_prop(inst, 3792 SCF_PG_RESTARTER, SCF_PG_RESTARTER_TYPE, 3793 SCF_PG_RESTARTER_FLAGS, SCF_PROPERTY_CONTRACT, uint64); 3794 3795 switch (ret) { 3796 case 0: 3797 case ECONNABORTED: 3798 case EPERM: 3799 case EACCES: 3800 case EROFS: 3801 break; 3802 3803 case ECANCELED: 3804 goto add_inst; 3805 3806 default: 3807 bad_error("libscf_inst_set_count_prop", ret); 3808 } 3809 } 3810 3811 ret = libscf_note_method_log(inst, LOG_PREFIX_EARLY, 3812 STARTD_DEFAULT_LOG); 3813 if (ret == 0) { 3814 ret = libscf_note_method_log(inst, LOG_PREFIX_NORMAL, 3815 STARTD_DEFAULT_LOG); 3816 } 3817 3818 switch (ret) { 3819 case 0: 3820 case ECONNABORTED: 3821 case EPERM: 3822 case EACCES: 3823 case EROFS: 3824 case EAGAIN: 3825 break; 3826 3827 case ECANCELED: 3828 goto add_inst; 3829 3830 default: 3831 bad_error("libscf_note_method_log", ret); 3832 } 3833 3834 out: 3835 scf_instance_destroy(inst); 3836 scf_service_destroy(svc); 3837 scf_scope_destroy(scope); 3838 return (ret); 3839 } 3840 3841 /* 3842 * Returns 3843 * 0 - success 3844 * ENOENT - SCF_SERVICE_STARTD does not exist in repository 3845 * EPERM 3846 * EACCES 3847 * EROFS 3848 */ 3849 int 3850 libscf_set_reconfig(int set) 3851 { 3852 scf_handle_t *h; 3853 scf_instance_t *inst; 3854 scf_propertygroup_t *pg; 3855 int ret = 0; 3856 3857 h = libscf_handle_create_bound_loop(); 3858 inst = safe_scf_instance_create(h); 3859 pg = safe_scf_pg_create(h); 3860 3861 again: 3862 if (scf_handle_decode_fmri(h, SCF_SERVICE_STARTD, NULL, NULL, 3863 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) { 3864 switch (scf_error()) { 3865 case SCF_ERROR_CONNECTION_BROKEN: 3866 default: 3867 libscf_handle_rebind(h); 3868 goto again; 3869 3870 case SCF_ERROR_NOT_FOUND: 3871 ret = ENOENT; 3872 goto reconfig_out; 3873 3874 case SCF_ERROR_HANDLE_MISMATCH: 3875 case SCF_ERROR_INVALID_ARGUMENT: 3876 case SCF_ERROR_CONSTRAINT_VIOLATED: 3877 bad_error("scf_handle_decode_fmri", scf_error()); 3878 } 3879 } 3880 3881 ret = libscf_inst_set_boolean_prop(inst, "system", SCF_GROUP_FRAMEWORK, 3882 SCF_PG_FLAG_NONPERSISTENT, "reconfigure", set); 3883 switch (ret) { 3884 case 0: 3885 case EPERM: 3886 case EACCES: 3887 case EROFS: 3888 break; 3889 3890 case ECONNABORTED: 3891 libscf_handle_rebind(h); 3892 goto again; 3893 3894 case ECANCELED: 3895 ret = ENOENT; 3896 break; 3897 3898 default: 3899 bad_error("libscf_inst_set_boolean_prop", ret); 3900 } 3901 3902 reconfig_out: 3903 scf_pg_destroy(pg); 3904 scf_instance_destroy(inst); 3905 scf_handle_destroy(h); 3906 return (ret); 3907 } 3908 3909 /* 3910 * Set inst->ri_m_inst to the scf instance for inst. If it has been deleted, 3911 * set inst->ri_mi_deleted to true. If the repository connection is broken, it 3912 * is rebound with libscf_handle_rebound(). 3913 */ 3914 void 3915 libscf_reget_instance(restarter_inst_t *inst) 3916 { 3917 scf_handle_t *h; 3918 int r; 3919 3920 h = scf_instance_handle(inst->ri_m_inst); 3921 3922 again: 3923 r = libscf_lookup_instance(inst->ri_i.i_fmri, inst->ri_m_inst); 3924 switch (r) { 3925 case 0: 3926 case ENOENT: 3927 inst->ri_mi_deleted = (r == ENOENT); 3928 return; 3929 3930 case ECONNABORTED: 3931 libscf_handle_rebind(h); 3932 goto again; 3933 3934 case EINVAL: 3935 case ENOTSUP: 3936 default: 3937 bad_error("libscf_lookup_instance", r); 3938 } 3939 }