libscf.c revision 5777:e3276fcb93e7
1116742Ssam/* 2116904Ssam * CDDL HEADER START 3186904Ssam * 4116742Ssam * The contents of this file are subject to the terms of the 5116742Ssam * Common Development and Distribution License (the "License"). 6116742Ssam * You may not use this file except in compliance with the License. 7116742Ssam * 8116742Ssam * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9116742Ssam * or http://www.opensolaris.org/os/licensing. 10116904Ssam * See the License for the specific language governing permissions 11116904Ssam * and limitations under the License. 12116904Ssam * 13116904Ssam * When distributing Covered Code, include this CDDL HEADER in each 14116742Ssam * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15116904Ssam * If applicable, add the following below this CDDL HEADER, with the 16116904Ssam * fields enclosed by brackets "[]" replaced with your own identifying 17116904Ssam * information: Portions Copyright [yyyy] [name of copyright owner] 18116904Ssam * 19116904Ssam * CDDL HEADER END 20116904Ssam */ 21116904Ssam 22116904Ssam/* 23116904Ssam * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24116904Ssam * Use is subject to license terms. 25116742Ssam */ 26116742Ssam 27116742Ssam#pragma ident "%Z%%M% %I% %E% SMI" 28116742Ssam 29116742Ssam#include <sys/contract/process.h> 30116742Ssam#include <assert.h> 31116742Ssam#include <errno.h> 32116742Ssam#include <libscf.h> 33178354Ssam#include <libscf_priv.h> 34116742Ssam#include <poll.h> 35116742Ssam#include <stdlib.h> 36191746Sthompsa#include <string.h> 37116742Ssam#include <unistd.h> 38182742Sbrooks 39116742Ssam#include "startd.h" 40116742Ssam 41116742Ssam#define SMF_SNAPSHOT_RUNNING "running" 42178354Ssam 43116742Ssamchar * 44178354Ssaminst_fmri_to_svc_fmri(const char *fmri) 45116742Ssam{ 46116742Ssam char *buf, *sfmri; 47116742Ssam const char *scope, *svc; 48178354Ssam int r; 49190391Ssam boolean_t local; 50190391Ssam 51190391Ssam buf = startd_alloc(max_scf_fmri_size); 52116742Ssam sfmri = startd_alloc(max_scf_fmri_size); 53116742Ssam 54116742Ssam (void) strcpy(buf, fmri); 55178955Ssam 56178955Ssam r = scf_parse_svc_fmri(buf, &scope, &svc, NULL, NULL, NULL); 57178955Ssam assert(r == 0); 58178955Ssam 59178955Ssam local = strcmp(scope, SCF_SCOPE_LOCAL) == 0; 60178955Ssam 61178955Ssam (void) snprintf(sfmri, max_scf_fmri_size, "svc:%s%s/%s", 62178955Ssam local ? "" : "//", local ? "" : scope, svc); 63178955Ssam 64188782Ssam startd_free(buf, max_scf_fmri_size); 65188782Ssam 66178955Ssam return (sfmri); 67178955Ssam} 68116742Ssam 69178957Ssam/* 70178957Ssam * Wrapper for the scf_*_create() functions. On SCF_ERROR_NO_MEMORY and 71178957Ssam * SCF_ERROR_NO_RESOURCES, retries or dies. So this can only fail with 72178957Ssam * SCF_ERROR_INVALID_ARGUMENT, if h is NULL. 73178957Ssam */ 74178957Ssamvoid * 75178957Ssamlibscf_object_create(void *f(scf_handle_t *), scf_handle_t *h) 76178957Ssam{ 77195618Srpaulo void *o; 78195618Srpaulo uint_t try, msecs; 79195618Srpaulo scf_error_t err; 80178957Ssam 81178957Ssam o = f(h); 82178354Ssam if (o != NULL) 83178354Ssam return (o); 84116742Ssam err = scf_error(); 85178354Ssam if (err != SCF_ERROR_NO_MEMORY && err != SCF_ERROR_NO_RESOURCES) 86193655Ssam return (NULL); 87178354Ssam 88178354Ssam msecs = ALLOC_DELAY; 89178354Ssam 90178354Ssam for (try = 0; try < ALLOC_RETRY; ++try) { 91178354Ssam (void) poll(NULL, 0, msecs); 92178354Ssam msecs *= ALLOC_DELAY_MULT; 93178354Ssam o = f(h); 94178354Ssam if (o != NULL) 95178354Ssam return (o); 96178354Ssam err = scf_error(); 97178354Ssam if (err != SCF_ERROR_NO_MEMORY && err != SCF_ERROR_NO_RESOURCES) 98164645Ssam return (NULL); 99164645Ssam } 100164645Ssam 101164645Ssam uu_die("Insufficient memory.\n"); 102164645Ssam /* NOTREACHED */ 103164645Ssam} 104165569Ssam 105165569Ssamscf_snapshot_t * 106165569Ssamlibscf_get_running_snapshot(scf_instance_t *inst) 107165569Ssam{ 108164645Ssam scf_handle_t *h; 109164645Ssam scf_snapshot_t *snap; 110164645Ssam 111164645Ssam h = scf_instance_handle(inst); 112164645Ssam if (h == NULL) 113164645Ssam return (NULL); 114164645Ssam 115140915Ssam snap = scf_snapshot_create(h); 116165569Ssam if (snap == NULL) 117165569Ssam return (NULL); 118165569Ssam 119165569Ssam if (scf_instance_get_snapshot(inst, SMF_SNAPSHOT_RUNNING, snap) == 0) 120165569Ssam return (snap); 121165569Ssam 122116742Ssam scf_snapshot_destroy(snap); 123165569Ssam return (NULL); 124188782Ssam} 125165574Ssam 126165569Ssam/* 127116742Ssam * Make sure a service has a "running" snapshot. If it doesn't, make one from 128116742Ssam * the editing configuration. 129116742Ssam */ 130186107Ssamscf_snapshot_t * 131170530Ssamlibscf_get_or_make_running_snapshot(scf_instance_t *inst, const char *fmri, 132116742Ssam boolean_t retake) 133178354Ssam{ 134167468Ssam scf_handle_t *h; 135170530Ssam scf_snapshot_t *snap; 136116742Ssam 137170530Ssam h = scf_instance_handle(inst); 138187796Ssam 139187796Ssam snap = scf_snapshot_create(h); 140187796Ssam if (snap == NULL) 141187796Ssam goto err; 142187796Ssam 143187796Ssam if (scf_instance_get_snapshot(inst, SMF_SNAPSHOT_RUNNING, snap) == 0) 144187796Ssam return (snap); 145187796Ssam 146187796Ssam switch (scf_error()) { 147187796Ssam case SCF_ERROR_NOT_FOUND: 148187796Ssam break; 149187796Ssam 150187796Ssam case SCF_ERROR_DELETED: 151187796Ssam scf_snapshot_destroy(snap); 152187796Ssam return (NULL); 153170530Ssam 154170530Ssam default: 155170530Ssamerr: 156170530Ssam log_error(LOG_NOTICE, 157170530Ssam "Could not check for running snapshot of %s (%s).\n", fmri, 158170530Ssam scf_strerror(scf_error())); 159170530Ssam scf_snapshot_destroy(snap); 160170530Ssam return (NULL); 161170530Ssam } 162170530Ssam 163170530Ssam if (_scf_snapshot_take_new(inst, SMF_SNAPSHOT_RUNNING, snap) == 0) { 164170530Ssam log_framework(LOG_DEBUG, "Took running snapshot for %s.\n", 165170530Ssam fmri); 166170530Ssam } else { 167170530Ssam if (retake && scf_error() == SCF_ERROR_BACKEND_READONLY) 168170530Ssam restarter_mark_pending_snapshot(fmri, 169170530Ssam RINST_RETAKE_RUNNING); 170170530Ssam else 171188782Ssam log_error(LOG_DEBUG, 172188782Ssam "Could not create running snapshot for %s " 173188782Ssam "(%s).\n", fmri, scf_strerror(scf_error())); 174188782Ssam 175170530Ssam scf_snapshot_destroy(snap); 176170530Ssam snap = NULL; 177170530Ssam } 178170530Ssam 179116742Ssam return (snap); 180170530Ssam} 181170530Ssam 182170530Ssam/* 183164645Ssam * When a service comes up, point the "start" snapshot at the "running" 184178354Ssam * snapshot. Returns 0 on success, ENOTSUP if fmri designates something other 185178354Ssam * than an instance, ECONNABORTED, ENOENT if the instance does not exist, or 186178354Ssam * EACCES. 187178354Ssam */ 188170530Ssamint 189172233Ssamlibscf_snapshots_poststart(scf_handle_t *h, const char *fmri, boolean_t retake) 190178354Ssam{ 191170530Ssam scf_instance_t *inst = NULL; 192170530Ssam scf_snapshot_t *running, *start = NULL; 193190532Ssam int ret = 0, r; 194170530Ssam 195164645Ssam r = libscf_fmri_get_instance(h, fmri, &inst); 196165569Ssam switch (r) { 197165569Ssam case 0: 198165569Ssam break; 199165569Ssam 200165569Ssam case ENOTSUP: 201187897Ssam case ECONNABORTED: 202188782Ssam case ENOENT: 203188782Ssam return (r); 204188774Ssam 205188774Ssam case EINVAL: 206165569Ssam default: 207165569Ssam assert(0); 208165569Ssam abort(); 209165569Ssam } 210165569Ssam 211165569Ssam start = safe_scf_snapshot_create(h); 212165569Ssam 213165569Ssamagain: 214178354Ssam running = libscf_get_or_make_running_snapshot(inst, fmri, retake); 215178354Ssam if (running == NULL) { 216178354Ssam ret = 0; 217178354Ssam goto out; 218178354Ssam } 219178354Ssam 220178354Ssamlookup: 221178354Ssam if (scf_instance_get_snapshot(inst, "start", start) != 0) { 222178354Ssam switch (scf_error()) { 223178354Ssam case SCF_ERROR_CONNECTION_BROKEN: 224178354Ssam default: 225178354Ssam ret = ECONNABORTED; 226178521Ssam goto out; 227178521Ssam 228191148Skmacy case SCF_ERROR_NOT_FOUND: 229178521Ssam if (_scf_snapshot_take_new(inst, "start", start) != 0) { 230178521Ssam switch (scf_error()) { 231178521Ssam case SCF_ERROR_CONNECTION_BROKEN: 232178521Ssam default: 233178521Ssam ret = ECONNABORTED; 234178521Ssam goto out; 235178521Ssam 236178521Ssam case SCF_ERROR_DELETED: 237178521Ssam ret = ENOENT; 238178521Ssam goto out; 239178521Ssam 240178521Ssam case SCF_ERROR_EXISTS: 241178521Ssam goto lookup; 242178354Ssam 243178354Ssam case SCF_ERROR_NO_RESOURCES: 244178354Ssam uu_die("Repository server out of " 245178354Ssam "resources.\n"); 246165569Ssam /* NOTREACHED */ 247190526Ssam 248190526Ssam case SCF_ERROR_BACKEND_READONLY: 249165569Ssam goto readonly; 250165569Ssam 251178354Ssam case SCF_ERROR_PERMISSION_DENIED: 252178354Ssam uu_die("Insufficient privileges.\n"); 253165569Ssam /* NOTREACHED */ 254178354Ssam 255165569Ssam case SCF_ERROR_BACKEND_ACCESS: 256179388Ssam ret = EACCES; 257178354Ssam goto out; 258191746Sthompsa 259191746Sthompsa case SCF_ERROR_HANDLE_MISMATCH: 260191746Sthompsa case SCF_ERROR_INTERNAL: 261191746Sthompsa case SCF_ERROR_INVALID_ARGUMENT: 262191746Sthompsa case SCF_ERROR_NOT_SET: 263191746Sthompsa bad_error("_scf_snapshot_take_new", 264165569Ssam scf_error()); 265165569Ssam } 266165569Ssam } 267165569Ssam break; 268165569Ssam 269178354Ssam case SCF_ERROR_DELETED: 270170530Ssam ret = ENOENT; 271178354Ssam goto out; 272178354Ssam 273116742Ssam case SCF_ERROR_HANDLE_MISMATCH: 274195379Ssam case SCF_ERROR_NOT_SET: 275155688Ssam case SCF_ERROR_INVALID_ARGUMENT: 276155688Ssam bad_error("scf_instance_get_snapshot", scf_error()); 277138568Ssam } 278138568Ssam } 279170530Ssam 280138568Ssam if (_scf_snapshot_attach(running, start) == 0) { 281170530Ssam log_framework(LOG_DEBUG, "Updated \"start\" snapshot for %s.\n", 282138568Ssam fmri); 283190391Ssam } else { 284190391Ssam switch (scf_error()) { 285190391Ssam case SCF_ERROR_CONNECTION_BROKEN: 286170530Ssam default: 287170530Ssam ret = ECONNABORTED; 288178354Ssam goto out; 289193843Ssam 290138568Ssam case SCF_ERROR_DELETED: 291178354Ssam scf_snapshot_destroy(running); 292138568Ssam goto again; 293178354Ssam 294178354Ssam case SCF_ERROR_NO_RESOURCES: 295178354Ssam uu_die("Repository server out of resources.\n"); 296178354Ssam /* NOTREACHED */ 297178354Ssam 298178521Ssam case SCF_ERROR_PERMISSION_DENIED: 299178521Ssam uu_die("Insufficient privileges.\n"); 300178521Ssam /* NOTREACHED */ 301140915Ssam 302178354Ssam case SCF_ERROR_BACKEND_ACCESS: 303178354Ssam ret = EACCES; 304178354Ssam goto out; 305178354Ssam 306178354Ssam case SCF_ERROR_BACKEND_READONLY: 307190526Ssamreadonly: 308194760Srwatson if (retake) 309116742Ssam restarter_mark_pending_snapshot(fmri, 310116742Ssam RINST_RETAKE_START); 311178354Ssam break; 312178354Ssam 313178354Ssam case SCF_ERROR_HANDLE_MISMATCH: 314178354Ssam case SCF_ERROR_NOT_SET: 315178354Ssam bad_error("_scf_snapshot_attach", scf_error()); 316178354Ssam } 317116742Ssam } 318138568Ssam 319116742Ssamout: 320138568Ssam scf_snapshot_destroy(start); 321178354Ssam scf_snapshot_destroy(running); 322116742Ssam scf_instance_destroy(inst); 323193337Ssam 324193337Ssam return (ret); 325178354Ssam} 326178354Ssam 327188533Sthompsa/* 328138568Ssam * Before a refresh, update the "running" snapshot from the editing 329138568Ssam * configuration. 330193843Ssam * 331178354Ssam * Returns 0 on success and -1 on failure. 332170530Ssam */ 333190391Ssamint 334190391Ssamlibscf_snapshots_refresh(scf_instance_t *inst, const char *fmri) 335190391Ssam{ 336170530Ssam scf_handle_t *h; 337166012Ssam scf_snapshot_t *snap; 338138568Ssam boolean_t err = 1; 339138568Ssam 340170530Ssam h = scf_instance_handle(inst); 341138568Ssam if (h == NULL) 342193337Ssam goto out; 343116742Ssam 344191746Sthompsa snap = scf_snapshot_create(h); 345170530Ssam if (snap == NULL) 346178354Ssam goto out; 347138568Ssam 348178354Ssam if (scf_instance_get_snapshot(inst, SMF_SNAPSHOT_RUNNING, snap) == 0) { 349178354Ssam if (_scf_snapshot_take_attach(inst, snap) == 0) 350178354Ssam err = 0; 351178354Ssam } else { 352178354Ssam switch (scf_error()) { 353178354Ssam case SCF_ERROR_DELETED: 354178354Ssam err = 0; 355178354Ssam goto out; 356178354Ssam 357178354Ssam case SCF_ERROR_NOT_FOUND: 358178354Ssam break; 359178354Ssam 360178354Ssam case SCF_ERROR_NOT_SET: 361178354Ssam assert(0); 362178354Ssam abort(); 363178354Ssam /* NOTREACHED */ 364178354Ssam 365178354Ssam default: 366178354Ssam goto out; 367178354Ssam } 368178354Ssam 369178354Ssam log_error(LOG_DEBUG, 370178354Ssam "Service %s has no %s snapshot; creating one.\n", fmri, 371178354Ssam SMF_SNAPSHOT_RUNNING); 372178354Ssam 373178354Ssam if (_scf_snapshot_take_new(inst, SMF_SNAPSHOT_RUNNING, 374178354Ssam snap) == 0) 375178354Ssam err = 0; 376178354Ssam } 377178354Ssam 378178354Ssamout: 379178354Ssam scf_snapshot_destroy(snap); 380178354Ssam 381178354Ssam if (!err) 382178354Ssam return (0); 383178354Ssam 384178354Ssam log_error(LOG_WARNING, 385178354Ssam "Could not update \"running\" snapshot for refresh of %s.\n", fmri); 386178354Ssam return (-1); 387178354Ssam} 388178354Ssam 389178354Ssam/* 390178354Ssam * int libscf_read_single_astring() 391178354Ssam * Reads a single astring value of the requested property into the 392178354Ssam * pre-allocated buffer (conventionally of size max_scf_value_size). 393178354Ssam * Multiple values constitute an error. 394178354Ssam * 395178354Ssam * Returns 0 on success or LIBSCF_PROPERTY_ABSENT or LIBSCF_PROPERTY_ERROR. 396178354Ssam */ 397178354Ssamstatic int 398178354Ssamlibscf_read_single_astring(scf_handle_t *h, scf_property_t *prop, char **ret) 399178354Ssam{ 400178354Ssam scf_value_t *val = safe_scf_value_create(h); 401178354Ssam int r = 0; 402178957Ssam 403178354Ssam if (scf_property_get_value(prop, val) == -1) { 404178354Ssam if (scf_error() == SCF_ERROR_NOT_FOUND) 405178354Ssam r = LIBSCF_PROPERTY_ABSENT; 406178354Ssam else 407178354Ssam r = LIBSCF_PROPERTY_ERROR; 408178354Ssam goto read_single_astring_fail; 409178354Ssam } 410178354Ssam 411178354Ssam if (scf_value_get_astring(val, *ret, max_scf_value_size) <= 0) { 412178354Ssam r = LIBSCF_PROPERTY_ERROR; 413178354Ssam goto read_single_astring_fail; 414178354Ssam } 415178354Ssam 416178354Ssamread_single_astring_fail: 417178354Ssam scf_value_destroy(val); 418186904Ssam return (r); 419186904Ssam} 420186904Ssam 421186904Ssamstatic int 422186904Ssamlibscf_read_state(const scf_propertygroup_t *pg, const char *prop_name, 423186904Ssam restarter_instance_state_t *state) 424186904Ssam{ 425186904Ssam scf_handle_t *h; 426186904Ssam scf_property_t *prop; 427186904Ssam char *char_state = startd_alloc(max_scf_value_size); 428186904Ssam int ret = 0; 429186904Ssam 430186904Ssam h = scf_pg_handle(pg); 431186904Ssam prop = safe_scf_property_create(h); 432186904Ssam 433178354Ssam if (scf_pg_get_property(pg, prop_name, prop) == -1) { 434184278Ssam if (scf_error() == SCF_ERROR_NOT_FOUND) 435184278Ssam ret = LIBSCF_PROPERTY_ABSENT; 436184278Ssam else 437178354Ssam ret = LIBSCF_PROPERTY_ERROR; 438178354Ssam } else { 439178354Ssam ret = libscf_read_single_astring(h, prop, &char_state); 440178354Ssam if (ret != 0) { 441178354Ssam if (ret != LIBSCF_PROPERTY_ABSENT) 442178354Ssam ret = LIBSCF_PROPERTY_ERROR; 443178354Ssam } else { 444178354Ssam *state = restarter_string_to_state(char_state); 445178354Ssam ret = 0; 446178354Ssam } 447178354Ssam } 448178354Ssam 449178957Ssam startd_free(char_state, max_scf_value_size); 450178954Ssam scf_property_destroy(prop); 451178954Ssam return (ret); 452178954Ssam} 453178354Ssam 454178354Ssam/* 455178354Ssam * int libscf_read_states(const scf_propertygroup_t *, 456178354Ssam * restarter_instance_state_t *, restarter_instance_state_t *) 457178354Ssam * 458178354Ssam * Set the current state and next_state values for the given service instance. 459178354Ssam * Returns 0 on success, or a libscf error code on failure. 460178354Ssam */ 461178354Ssamint 462178354Ssamlibscf_read_states(const scf_propertygroup_t *pg, 463178354Ssam restarter_instance_state_t *state, restarter_instance_state_t *next_state) 464178354Ssam{ 465178354Ssam int state_ret, next_state_ret, ret; 466178354Ssam 467178354Ssam state_ret = libscf_read_state(pg, SCF_PROPERTY_STATE, state); 468178354Ssam next_state_ret = libscf_read_state(pg, SCF_PROPERTY_NEXT_STATE, 469178354Ssam next_state); 470178354Ssam 471190391Ssam if (state_ret == LIBSCF_PROPERTY_ERROR || 472190391Ssam next_state_ret == LIBSCF_PROPERTY_ERROR) { 473190391Ssam ret = LIBSCF_PROPERTY_ERROR; 474178354Ssam } else if (state_ret == 0 && next_state_ret == 0) { 475178354Ssam ret = 0; 476178354Ssam } else if (state_ret == LIBSCF_PROPERTY_ABSENT && 477192468Ssam next_state_ret == LIBSCF_PROPERTY_ABSENT) { 478178354Ssam *state = RESTARTER_STATE_UNINIT; 479178354Ssam *next_state = RESTARTER_STATE_NONE; 480178354Ssam ret = 0; 481178354Ssam } else if (state_ret == LIBSCF_PROPERTY_ABSENT || 482178354Ssam next_state_ret == LIBSCF_PROPERTY_ABSENT) { 483178354Ssam log_framework(LOG_DEBUG, 484178354Ssam "Only one repository state exists, setting " 485178354Ssam "restarter states to MAINTENANCE and NONE\n"); 486178354Ssam *state = RESTARTER_STATE_MAINT; 487178354Ssam *next_state = RESTARTER_STATE_NONE; 488178354Ssam ret = 0; 489178354Ssam } else { 490178354Ssam ret = LIBSCF_PROPERTY_ERROR; 491178354Ssam } 492178354Ssam 493178354Ssamread_states_out: 494178354Ssam return (ret); 495178354Ssam} 496178354Ssam 497178354Ssam/* 498178354Ssam * depgroup_empty() 499178354Ssam * 500178354Ssam * Returns 0 if not empty. 501178354Ssam * Returns 1 if empty. 502178354Ssam * Returns -1 on error (check scf_error()). 503178354Ssam */ 504178354Ssamint 505178354Ssamdepgroup_empty(scf_handle_t *h, scf_propertygroup_t *pg) 506178354Ssam{ 507178354Ssam int empty = 1; 508178354Ssam scf_iter_t *iter; 509178354Ssam scf_property_t *prop; 510178354Ssam int ret; 511178354Ssam 512188106Ssam iter = safe_scf_iter_create(h); 513188106Ssam prop = safe_scf_property_create(h); 514178354Ssam 515178354Ssam if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) { 516178354Ssam scf_property_destroy(prop); 517178354Ssam scf_iter_destroy(iter); 518178354Ssam return (-1); 519178354Ssam } 520178354Ssam 521178354Ssam ret = scf_iter_next_property(iter, prop); 522178354Ssam if (ret < 0) { 523178354Ssam scf_property_destroy(prop); 524178354Ssam scf_iter_destroy(iter); 525178354Ssam return (-1); 526190391Ssam } 527178354Ssam 528190391Ssam if (ret == 1) 529178354Ssam empty = 0; 530178354Ssam 531193655Ssam scf_property_destroy(prop); 532193655Ssam scf_iter_destroy(iter); 533178354Ssam 534178354Ssam return (empty); 535178354Ssam} 536178354Ssam 537178354Ssamgv_type_t 538178354Ssamdepgroup_read_scheme(scf_handle_t *h, scf_propertygroup_t *pg) 539178354Ssam{ 540178354Ssam scf_property_t *prop; 541178354Ssam char *scheme = startd_alloc(max_scf_value_size); 542178354Ssam gv_type_t ret; 543178354Ssam 544178354Ssam prop = safe_scf_property_create(h); 545178354Ssam 546178354Ssam if (scf_pg_get_property(pg, SCF_PROPERTY_TYPE, prop) == -1 || 547178354Ssam libscf_read_single_astring(h, prop, &scheme) != 0) { 548178354Ssam scf_property_destroy(prop); 549178354Ssam startd_free(scheme, max_scf_value_size); 550178354Ssam return (GVT_UNSUPPORTED); 551178354Ssam } 552178354Ssam 553178354Ssam if (strcmp(scheme, "service") == 0) 554178354Ssam ret = GVT_INST; 555178354Ssam else if (strcmp(scheme, "path") == 0) 556193312Ssam ret = GVT_FILE; 557193312Ssam else 558178354Ssam ret = GVT_UNSUPPORTED; 559193312Ssam 560193312Ssam startd_free(scheme, max_scf_value_size); 561191746Sthompsa scf_property_destroy(prop); 562191746Sthompsa return (ret); 563191746Sthompsa} 564191746Sthompsa 565191746Sthompsadepgroup_type_t 566191746Sthompsadepgroup_read_grouping(scf_handle_t *h, scf_propertygroup_t *pg) 567191746Sthompsa{ 568191746Sthompsa char *grouping = startd_alloc(max_scf_value_size); 569191746Sthompsa depgroup_type_t ret; 570178354Ssam scf_property_t *prop = safe_scf_property_create(h); 571178354Ssam 572190391Ssam if (scf_pg_get_property(pg, SCF_PROPERTY_GROUPING, prop) == -1 || 573178354Ssam libscf_read_single_astring(h, prop, &grouping) != 0) { 574190391Ssam scf_property_destroy(prop); 575178354Ssam startd_free(grouping, max_scf_value_size); 576178354Ssam return (DEPGRP_UNSUPPORTED); 577193655Ssam } 578193655Ssam 579192468Ssam if (strcmp(grouping, SCF_DEP_REQUIRE_ANY) == 0) 580192468Ssam ret = DEPGRP_REQUIRE_ANY; 581178354Ssam else if (strcmp(grouping, SCF_DEP_REQUIRE_ALL) == 0) 582178354Ssam ret = DEPGRP_REQUIRE_ALL; 583178354Ssam else if (strcmp(grouping, SCF_DEP_OPTIONAL_ALL) == 0) 584178354Ssam ret = DEPGRP_OPTIONAL_ALL; 585178354Ssam else if (strcmp(grouping, SCF_DEP_EXCLUDE_ALL) == 0) 586178354Ssam ret = DEPGRP_EXCLUDE_ALL; 587192468Ssam else { 588178354Ssam ret = DEPGRP_UNSUPPORTED; 589178354Ssam } 590190391Ssam startd_free(grouping, max_scf_value_size); 591190391Ssam scf_property_destroy(prop); 592190391Ssam return (ret); 593178354Ssam} 594178354Ssam 595178354Ssamrestarter_error_t 596178354Ssamdepgroup_read_restart(scf_handle_t *h, scf_propertygroup_t *pg) 597178354Ssam{ 598178354Ssam scf_property_t *prop = safe_scf_property_create(h); 599178354Ssam char *restart_on = startd_alloc(max_scf_value_size); 600182674Sweongyo restarter_error_t ret; 601182674Sweongyo 602116742Ssam if (scf_pg_get_property(pg, SCF_PROPERTY_RESTART_ON, prop) == -1 || 603116742Ssam libscf_read_single_astring(h, prop, &restart_on) != 0) { 604178354Ssam startd_free(restart_on, max_scf_value_size); 605178354Ssam scf_property_destroy(prop); 606178354Ssam return (RERR_UNSUPPORTED); 607178354Ssam } 608178354Ssam 609178354Ssam if (strcmp(restart_on, SCF_DEP_RESET_ON_ERROR) == 0) 610178354Ssam ret = RERR_FAULT; 611178354Ssam else if (strcmp(restart_on, SCF_DEP_RESET_ON_RESTART) == 0) 612178354Ssam ret = RERR_RESTART; 613178354Ssam else if (strcmp(restart_on, SCF_DEP_RESET_ON_REFRESH) == 0) 614178354Ssam ret = RERR_REFRESH; 615178354Ssam else if (strcmp(restart_on, SCF_DEP_RESET_ON_NONE) == 0) 616178354Ssam ret = RERR_NONE; 617178354Ssam else 618178354Ssam ret = RERR_UNSUPPORTED; 619178354Ssam 620178354Ssam startd_free(restart_on, max_scf_value_size); 621178354Ssam scf_property_destroy(prop); 622178354Ssam return (ret); 623178354Ssam} 624178354Ssam 625178354Ssam/* 626178354Ssam * int get_boolean() 627178354Ssam * Fetches the value of a boolean property of the given property group. 628178354Ssam * Returns 629178354Ssam * 0 - success 630178354Ssam * ECONNABORTED - repository connection broken 631178354Ssam * ECANCELED - pg was deleted 632178354Ssam * ENOENT - the property doesn't exist or has no values 633178354Ssam * EINVAL - the property has the wrong type 634178354Ssam * the property is not single-valued 635178354Ssam * EACCES - the current user does not have permission to read the value 636178354Ssam */ 637178354Ssamstatic int 638178354Ssamget_boolean(scf_propertygroup_t *pg, const char *propname, uint8_t *valuep) 639178354Ssam{ 640178354Ssam scf_handle_t *h; 641191746Sthompsa scf_property_t *prop; 642178354Ssam scf_value_t *val; 643191746Sthompsa int ret = 0, r; 644178354Ssam scf_type_t type; 645178354Ssam 646178354Ssam h = scf_pg_handle(pg); 647178354Ssam prop = safe_scf_property_create(h); 648178354Ssam val = safe_scf_value_create(h); 649178354Ssam 650178354Ssam if (scf_pg_get_property(pg, propname, prop) != 0) { 651178354Ssam switch (scf_error()) { 652178354Ssam case SCF_ERROR_CONNECTION_BROKEN: 653178354Ssam default: 654178354Ssam ret = ECONNABORTED; 655178354Ssam goto out; 656178354Ssam 657178354Ssam case SCF_ERROR_DELETED: 658178354Ssam ret = ECANCELED; 659178354Ssam goto out; 660178354Ssam 661178354Ssam case SCF_ERROR_NOT_FOUND: 662178354Ssam ret = ENOENT; 663178354Ssam goto out; 664178354Ssam 665178354Ssam case SCF_ERROR_HANDLE_MISMATCH: 666178354Ssam case SCF_ERROR_INVALID_ARGUMENT: 667178354Ssam case SCF_ERROR_NOT_SET: 668178354Ssam bad_error("scf_pg_get_property", scf_error()); 669178354Ssam } 670178354Ssam } 671178354Ssam 672178354Ssam if (scf_property_type(prop, &type) != 0) { 673178354Ssam switch (scf_error()) { 674178354Ssam case SCF_ERROR_CONNECTION_BROKEN: 675178354Ssam default: 676178354Ssam ret = ECONNABORTED; 677178354Ssam goto out; 678178354Ssam 679178354Ssam case SCF_ERROR_DELETED: 680178354Ssam ret = ENOENT; 681178354Ssam goto out; 682178354Ssam 683178354Ssam case SCF_ERROR_NOT_SET: 684178354Ssam bad_error("scf_property_type", scf_error()); 685178354Ssam } 686178354Ssam } 687178354Ssam 688178354Ssam if (type != SCF_TYPE_BOOLEAN) { 689193655Ssam ret = EINVAL; 690178354Ssam goto out; 691178354Ssam } 692178354Ssam 693178354Ssam if (scf_property_get_value(prop, val) != 0) { 694193655Ssam switch (scf_error()) { 695193655Ssam case SCF_ERROR_CONNECTION_BROKEN: 696193655Ssam default: 697193655Ssam ret = ECONNABORTED; 698193655Ssam goto out; 699193655Ssam 700193655Ssam case SCF_ERROR_DELETED: 701193655Ssam case SCF_ERROR_NOT_FOUND: 702193655Ssam ret = ENOENT; 703193655Ssam goto out; 704193655Ssam 705193655Ssam case SCF_ERROR_CONSTRAINT_VIOLATED: 706193655Ssam ret = EINVAL; 707193655Ssam goto out; 708193655Ssam 709193655Ssam case SCF_ERROR_PERMISSION_DENIED: 710193655Ssam ret = EACCES; 711193655Ssam goto out; 712193655Ssam 713193655Ssam case SCF_ERROR_NOT_SET: 714193655Ssam bad_error("scf_property_get_value", scf_error()); 715193655Ssam } 716193655Ssam } 717193655Ssam 718193655Ssam r = scf_value_get_boolean(val, valuep); 719193655Ssam assert(r == 0); 720193655Ssam 721193655Ssamout: 722193655Ssam scf_value_destroy(val); 723193655Ssam scf_property_destroy(prop); 724193655Ssam return (ret); 725193655Ssam} 726193655Ssam 727193655Ssam/* 728193655Ssam * int get_count() 729193655Ssam * Fetches the value of a count property of the given property group. 730193655Ssam * Returns 731193655Ssam * 0 - success 732193655Ssam * ECONNABORTED - repository connection broken 733193655Ssam * unknown libscf error 734178354Ssam * ECANCELED - pg was deleted 735178354Ssam * ENOENT - the property doesn't exist or has no values 736178354Ssam * EINVAL - the property has the wrong type 737178354Ssam * the property is not single-valued 738178354Ssam * EACCES - the current user does not have permission to read the value 739178354Ssam */ 740178354Ssamstatic int 741178354Ssamget_count(scf_propertygroup_t *pg, const char *propname, uint64_t *valuep) 742178354Ssam{ 743178354Ssam scf_handle_t *h; 744178354Ssam scf_property_t *prop; 745178354Ssam scf_value_t *val; 746178354Ssam int ret = 0, r; 747178354Ssam 748178354Ssam h = scf_pg_handle(pg); 749178354Ssam prop = safe_scf_property_create(h); 750178354Ssam val = safe_scf_value_create(h); 751178354Ssam 752178354Ssam if (scf_pg_get_property(pg, propname, prop) != 0) { 753178354Ssam switch (scf_error()) { 754178354Ssam case SCF_ERROR_CONNECTION_BROKEN: 755178354Ssam default: 756178354Ssam ret = ECONNABORTED; 757178354Ssam goto out; 758178354Ssam 759178354Ssam case SCF_ERROR_DELETED: 760178354Ssam ret = ECANCELED; 761178354Ssam goto out; 762178354Ssam 763178354Ssam case SCF_ERROR_NOT_FOUND: 764178354Ssam ret = ENOENT; 765178354Ssam goto out; 766178354Ssam 767178354Ssam case SCF_ERROR_HANDLE_MISMATCH: 768166012Ssam case SCF_ERROR_INVALID_ARGUMENT: 769166012Ssam case SCF_ERROR_NOT_SET: 770166012Ssam bad_error("scf_pg_get_property", scf_error()); 771166012Ssam } 772166012Ssam } 773166012Ssam 774166012Ssam if (scf_property_is_type(prop, SCF_TYPE_COUNT) != 0) { 775166012Ssam switch (scf_error()) { 776166012Ssam case SCF_ERROR_CONNECTION_BROKEN: 777166012Ssam default: 778166012Ssam ret = ECONNABORTED; 779166012Ssam goto out; 780166012Ssam 781166012Ssam case SCF_ERROR_TYPE_MISMATCH: 782166012Ssam ret = EINVAL; 783166012Ssam goto out; 784166012Ssam 785166012Ssam case SCF_ERROR_DELETED: 786166012Ssam ret = ECANCELED; 787166012Ssam goto out; 788116742Ssam 789116742Ssam case SCF_ERROR_INVALID_ARGUMENT: 790116742Ssam case SCF_ERROR_NOT_BOUND: 791152450Ssam case SCF_ERROR_NOT_SET: 792116742Ssam bad_error("scf_property_is_type", scf_error()); 793116742Ssam } 794167430Ssam } 795166012Ssam 796166012Ssam if (scf_property_get_value(prop, val) != 0) { 797116742Ssam switch (scf_error()) { 798116742Ssam case SCF_ERROR_CONNECTION_BROKEN: 799116742Ssam default: 800116742Ssam ret = ECONNABORTED; 801152450Ssam goto out; 802116742Ssam 803116742Ssam case SCF_ERROR_DELETED: 804116899Ssam ret = ECANCELED; 805165569Ssam goto out; 806170530Ssam 807167430Ssam case SCF_ERROR_NOT_FOUND: 808166012Ssam ret = ENOENT; 809152450Ssam goto out; 810165569Ssam 811152450Ssam case SCF_ERROR_CONSTRAINT_VIOLATED: 812116742Ssam ret = EINVAL; 813116742Ssam goto out; 814116742Ssam 815166012Ssam case SCF_ERROR_PERMISSION_DENIED: 816166012Ssam ret = EACCES; 817166012Ssam goto out; 818152450Ssam 819166012Ssam case SCF_ERROR_NOT_SET: 820152450Ssam bad_error("scf_property_get_value", scf_error()); 821167430Ssam } 822166012Ssam } 823165569Ssam 824152450Ssam r = scf_value_get_count(val, valuep); 825152450Ssam assert(r == 0); 826152450Ssam 827152450Ssamout: 828116742Ssam scf_value_destroy(val); 829116742Ssam scf_property_destroy(prop); 830167430Ssam return (ret); 831116742Ssam} 832116742Ssam 833116742Ssam 834116742Ssamstatic void 835116742Ssamget_restarter(scf_handle_t *h, scf_propertygroup_t *pg, char **restarter) 836152450Ssam{ 837165825Smjacob scf_property_t *prop = safe_scf_property_create(h); 838116742Ssam 839170530Ssam if (scf_pg_get_property(pg, SCF_PROPERTY_RESTARTER, prop) == -1 || 840138568Ssam libscf_read_single_astring(h, prop, restarter) != 0) 841117039Ssam *restarter[0] = '\0'; 842116742Ssam 843170530Ssam scf_property_destroy(prop); 844116742Ssam} 845116742Ssam 846116742Ssam/* 847116742Ssam * int libscf_instance_get_fmri(scf_instance_t *, char **) 848116742Ssam * Give a valid SCF instance, return its FMRI. Returns 0 on success, 849116742Ssam * ECONNABORTED, or ECANCELED if inst is deleted. 850116742Ssam */ 851116742Ssamint 852166012Ssamlibscf_instance_get_fmri(scf_instance_t *inst, char **retp) 853166012Ssam{ 854116742Ssam char *inst_fmri = startd_alloc(max_scf_fmri_size); 855116742Ssam 856116742Ssam inst_fmri[0] = 0; 857116742Ssam if (scf_instance_to_fmri(inst, inst_fmri, max_scf_fmri_size) <= 0) { 858116742Ssam startd_free(inst_fmri, max_scf_fmri_size); 859116742Ssam switch (scf_error()) { 860116742Ssam case SCF_ERROR_CONNECTION_BROKEN: 861116742Ssam default: 862165569Ssam return (ECONNABORTED); 863165569Ssam 864165569Ssam case SCF_ERROR_DELETED: 865165569Ssam return (ECANCELED); 866116742Ssam 867116742Ssam case SCF_ERROR_NOT_SET: 868166012Ssam assert(0); 869116742Ssam abort(); 870116742Ssam } 871116742Ssam } 872116742Ssam 873116742Ssam *retp = inst_fmri; 874116742Ssam return (0); 875116742Ssam} 876116742Ssam 877116742Ssam/* 878116742Ssam * int libscf_fmri_get_instance(scf_handle_t *, const char *, 879116742Ssam * scf_instance_t **) 880170530Ssam * Given a valid SCF handle and an FMRI, return the SCF instance that matches 881178354Ssam * exactly. The instance must be released using scf_instance_destroy(). 882170530Ssam * Returns 0 on success, EINVAL if the FMRI is invalid, ENOTSUP if the FMRI 883170530Ssam * is valid but designates something other than an instance, ECONNABORTED if 884170530Ssam * the repository connection is broken, or ENOENT if the instance does not 885170530Ssam * exist. 886170530Ssam */ 887170530Ssamint 888170530Ssamlibscf_fmri_get_instance(scf_handle_t *h, const char *fmri, 889170530Ssam scf_instance_t **instp) 890170530Ssam{ 891170530Ssam scf_instance_t *inst; 892170530Ssam int r; 893170530Ssam 894170530Ssam inst = safe_scf_instance_create(h); 895170530Ssam 896170530Ssam r = libscf_lookup_instance(fmri, inst); 897170530Ssam 898170530Ssam if (r == 0) 899170530Ssam *instp = inst; 900170530Ssam else 901170530Ssam scf_instance_destroy(inst); 902170530Ssam 903170530Ssam return (r); 904170530Ssam} 905173861Ssam 906173861Ssamint 907173861Ssamlibscf_lookup_instance(const char *fmri, scf_instance_t *inst) 908173861Ssam{ 909173861Ssam if (scf_handle_decode_fmri(scf_instance_handle(inst), fmri, NULL, NULL, 910173861Ssam inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 911173861Ssam switch (scf_error()) { 912173861Ssam case SCF_ERROR_INVALID_ARGUMENT: 913173861Ssam return (EINVAL); 914173861Ssam 915173861Ssam case SCF_ERROR_CONSTRAINT_VIOLATED: 916173861Ssam return (ENOTSUP); 917173861Ssam 918173861Ssam case SCF_ERROR_CONNECTION_BROKEN: 919173861Ssam return (ECONNABORTED); 920173861Ssam 921173861Ssam case SCF_ERROR_NOT_FOUND: 922173861Ssam return (ENOENT); 923173861Ssam 924173861Ssam case SCF_ERROR_HANDLE_MISMATCH: 925173861Ssam default: 926173861Ssam bad_error("scf_handle_decode_fmri", scf_error()); 927173861Ssam } 928173861Ssam } 929173861Ssam 930173861Ssam return (0); 931170530Ssam} 932178354Ssam 933170530Ssam/* 934170530Ssam * void libscf_get_basic_instance_data() 935178354Ssam * Read enabled, enabled_ovr, and restarter_fmri (into an allocated 936170530Ssam * buffer) for inst. Returns 0, ECONNABORTED if the connection to the 937170530Ssam * repository is broken, ECANCELED if inst is deleted, or ENOENT if inst 938188106Ssam * has no general property group. 939188106Ssam * 940188106Ssam * On success, restarter_fmri may be NULL. If general/enabled was missing 941188106Ssam * or invalid, *enabledp will be -1 and a debug message is logged. 942188106Ssam */ 943188106Ssamint 944188106Ssamlibscf_get_basic_instance_data(scf_handle_t *h, scf_instance_t *inst, 945188106Ssam const char *fmri, int *enabledp, int *enabled_ovrp, char **restarter_fmri) 946188782Ssam{ 947188782Ssam scf_propertygroup_t *pg; 948188106Ssam int r; 949188106Ssam uint8_t enabled_8; 950170530Ssam 951170530Ssam pg = safe_scf_pg_create(h); 952170530Ssam 953170530Ssam if (enabled_ovrp == NULL) 954178354Ssam goto enabled; 955178354Ssam 956178354Ssam if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_GENERAL_OVR, pg) != 957178354Ssam 0) { 958178354Ssam switch (scf_error()) { 959178354Ssam case SCF_ERROR_CONNECTION_BROKEN: 960178354Ssam default: 961178354Ssam scf_pg_destroy(pg); 962178354Ssam return (ECONNABORTED); 963178354Ssam 964178354Ssam case SCF_ERROR_DELETED: 965178354Ssam scf_pg_destroy(pg); 966195618Srpaulo return (ECANCELED); 967195618Srpaulo 968170530Ssam case SCF_ERROR_NOT_FOUND: 969170530Ssam *enabled_ovrp = -1; 970170530Ssam break; 971170530Ssam 972116742Ssam case SCF_ERROR_HANDLE_MISMATCH: 973178354Ssam case SCF_ERROR_INVALID_ARGUMENT: 974116742Ssam case SCF_ERROR_NOT_SET: 975178354Ssam bad_error("scf_instance_get_pg_composed", scf_error()); 976178354Ssam } 977178354Ssam } else { 978116742Ssam switch (r = get_boolean(pg, SCF_PROPERTY_ENABLED, &enabled_8)) { 979116742Ssam case 0: 980170530Ssam *enabled_ovrp = enabled_8; 981170530Ssam break; 982116742Ssam 983116742Ssam case ECONNABORTED: 984118887Ssam case ECANCELED: 985116742Ssam scf_pg_destroy(pg); 986116742Ssam return (r); 987178354Ssam 988116742Ssam case ENOENT: 989170530Ssam case EINVAL: 990170530Ssam *enabled_ovrp = -1; 991170530Ssam break; 992116742Ssam 993170530Ssam case EACCES: 994167468Ssam default: 995116742Ssam bad_error("get_boolean", r); 996178354Ssam } 997116742Ssam } 998116742Ssam 999116742Ssamenabled: 1000116742Ssam /* 1001116742Ssam * Since general/restarter can be at the service level, we must do 1002116742Ssam * a composed lookup. These properties are immediate, though, so we 1003116742Ssam * must use the "editing" snapshot. Technically enabled shouldn't be 1004116742Ssam * at the service level, but looking it up composed, too, doesn't 1005178354Ssam * hurt. 1006116742Ssam */ 1007170530Ssam if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_GENERAL, pg) != 0) { 1008116742Ssam scf_pg_destroy(pg); 1009116742Ssam switch (scf_error()) { 1010116742Ssam case SCF_ERROR_CONNECTION_BROKEN: 1011116742Ssam default: 1012116742Ssam return (ECONNABORTED); 1013116742Ssam 1014116742Ssam case SCF_ERROR_DELETED: 1015116742Ssam return (ECANCELED); 1016116742Ssam 1017116742Ssam case SCF_ERROR_NOT_FOUND: 1018116742Ssam return (ENOENT); 1019116742Ssam 1020116742Ssam case SCF_ERROR_NOT_SET: 1021116742Ssam bad_error("scf_instance_get_pg_composed", scf_error()); 1022116742Ssam } 1023116742Ssam } 1024116742Ssam 1025116742Ssam switch (r = get_boolean(pg, SCF_PROPERTY_ENABLED, &enabled_8)) { 1026116742Ssam case 0: 1027116742Ssam *enabledp = enabled_8; 1028170530Ssam break; 1029178354Ssam 1030178354Ssam case ECONNABORTED: 1031116742Ssam case ECANCELED: 1032170530Ssam scf_pg_destroy(pg); 1033170530Ssam return (r); 1034170530Ssam 1035170530Ssam case ENOENT: 1036170530Ssam /* 1037170530Ssam * DEBUG because this happens when svccfg import creates 1038188782Ssam * a temporary service. 1039170530Ssam */ 1040170530Ssam log_framework(LOG_DEBUG, 1041178354Ssam "general/enabled property of %s is missing.\n", fmri); 1042178354Ssam *enabledp = -1; 1043170530Ssam break; 1044170530Ssam 1045170530Ssam case EINVAL: 1046178354Ssam log_framework(LOG_ERR, 1047178354Ssam "general/enabled property of %s is invalid.\n", fmri); 1048170530Ssam *enabledp = -1; 1049170530Ssam break; 1050178354Ssam 1051178354Ssam case EACCES: 1052170530Ssam default: 1053178354Ssam bad_error("get_boolean", r); 1054178354Ssam } 1055116742Ssam 1056178354Ssam if (restarter_fmri != NULL) 1057178354Ssam get_restarter(h, pg, restarter_fmri); 1058178354Ssam 1059178354Ssam scf_pg_destroy(pg); 1060178354Ssam 1061178354Ssam return (0); 1062178354Ssam} 1063178354Ssam 1064178354Ssam 1065178354Ssam/* 1066178354Ssam * Sets pg to the name property group of s_inst. If it doesn't exist, it is 1067178354Ssam * added. 1068178354Ssam * 1069178354Ssam * Fails with 1070178354Ssam * ECONNABORTED - repository disconnection or unknown libscf error 1071178354Ssam * ECANCELED - inst is deleted 1072178354Ssam * EPERM - permission is denied 1073178354Ssam * EACCES - backend denied access 1074178354Ssam * EROFS - backend readonly 1075178354Ssam */ 1076178354Ssamint 1077178354Ssamlibscf_inst_get_or_add_pg(scf_instance_t *inst, const char *name, 1078178354Ssam const char *type, uint32_t flags, scf_propertygroup_t *pg) 1079170530Ssam{ 1080170530Ssam uint32_t f; 1081188106Ssam 1082188106Ssamagain: 1083116742Ssam if (scf_instance_get_pg(inst, name, pg) == 0) { 1084116742Ssam if (scf_pg_get_flags(pg, &f) != 0) { 1085178354Ssam switch (scf_error()) { 1086178354Ssam case SCF_ERROR_CONNECTION_BROKEN: 1087116742Ssam default: 1088116742Ssam return (ECONNABORTED); 1089188782Ssam 1090165569Ssam case SCF_ERROR_DELETED: 1091165569Ssam goto add; 1092165569Ssam 1093188774Ssam case SCF_ERROR_NOT_SET: 1094170530Ssam bad_error("scf_pg_get_flags", scf_error()); 1095165569Ssam } 1096165569Ssam } 1097138568Ssam 1098138568Ssam if (f == flags) 1099138568Ssam return (0); 1100138568Ssam 1101138568Ssam if (scf_pg_delete(pg) != 0) { 1102170530Ssam switch (scf_error()) { 1103138568Ssam case SCF_ERROR_CONNECTION_BROKEN: 1104172227Ssam default: 1105172227Ssam return (ECONNABORTED); 1106167468Ssam 1107138568Ssam case SCF_ERROR_DELETED: 1108138568Ssam break; 1109138568Ssam 1110138568Ssam case SCF_ERROR_PERMISSION_DENIED: 1111170530Ssam return (EPERM); 1112138568Ssam 1113138568Ssam case SCF_ERROR_BACKEND_ACCESS: 1114170530Ssam return (EACCES); 1115138568Ssam 1116170530Ssam case SCF_ERROR_BACKEND_READONLY: 1117138568Ssam return (EROFS); 1118138568Ssam 1119138568Ssam case SCF_ERROR_NOT_SET: 1120170530Ssam bad_error("scf_pg_delete", scf_error()); 1121138568Ssam } 1122138568Ssam } 1123170530Ssam } else { 1124170530Ssam switch (scf_error()) { 1125116742Ssam case SCF_ERROR_CONNECTION_BROKEN: 1126170530Ssam default: 1127170530Ssam return (ECONNABORTED); 1128170530Ssam 1129170530Ssam case SCF_ERROR_DELETED: 1130170530Ssam return (ECANCELED); 1131170530Ssam 1132170530Ssam case SCF_ERROR_NOT_FOUND: 1133170530Ssam break; 1134170530Ssam 1135170530Ssam case SCF_ERROR_HANDLE_MISMATCH: 1136170530Ssam case SCF_ERROR_INVALID_ARGUMENT: 1137170530Ssam case SCF_ERROR_NOT_SET: 1138170530Ssam bad_error("scf_instance_get_pg", scf_error()); 1139170530Ssam } 1140170530Ssam } 1141170530Ssam 1142170530Ssamadd: 1143170530Ssam if (scf_instance_add_pg(inst, name, type, flags, pg) == 0) 1144170530Ssam return (0); 1145170530Ssam 1146170530Ssam switch (scf_error()) { 1147170530Ssam case SCF_ERROR_CONNECTION_BROKEN: 1148170530Ssam default: 1149170530Ssam return (ECONNABORTED); 1150170530Ssam 1151170530Ssam case SCF_ERROR_DELETED: 1152170530Ssam return (ECANCELED); 1153170530Ssam 1154170530Ssam case SCF_ERROR_EXISTS: 1155170530Ssam goto again; 1156170530Ssam 1157170530Ssam case SCF_ERROR_PERMISSION_DENIED: 1158170530Ssam return (EPERM); 1159170530Ssam 1160170530Ssam case SCF_ERROR_BACKEND_ACCESS: 1161170530Ssam return (EACCES); 1162170530Ssam 1163170530Ssam case SCF_ERROR_BACKEND_READONLY: 1164170530Ssam return (EROFS); 1165170530Ssam 1166170530Ssam case SCF_ERROR_HANDLE_MISMATCH: 1167116742Ssam case SCF_ERROR_INVALID_ARGUMENT: 1168116742Ssam case SCF_ERROR_NOT_SET: 1169170530Ssam bad_error("scf_instance_add_pg", scf_error()); 1170184273Ssam /* NOTREACHED */ 1171170530Ssam } 1172116742Ssam} 1173116742Ssam 1174178354Ssam/* 1175116742Ssam * Returns 1176116742Ssam * 0 - success 1177178354Ssam * ECONNABORTED - repository connection broken 1178116742Ssam * - unknown libscf error 1179116742Ssam * ECANCELED 1180178354Ssam */ 1181116742Ssamstatic scf_error_t 1182124543Sonoetransaction_add_set(scf_transaction_t *tx, scf_transaction_entry_t *ent, 1183178354Ssam const char *pname, scf_type_t ty) 1184124543Sonoe{ 1185170530Ssam for (;;) { 1186178354Ssam if (scf_transaction_property_change_type(tx, ent, pname, 1187170530Ssam ty) == 0) 1188170530Ssam return (0); 1189178354Ssam 1190170530Ssam switch (scf_error()) { 1191116742Ssam case SCF_ERROR_CONNECTION_BROKEN: 1192178354Ssam default: 1193116742Ssam return (ECONNABORTED); 1194116742Ssam 1195178354Ssam case SCF_ERROR_DELETED: 1196116742Ssam return (ECANCELED); 1197116742Ssam 1198138568Ssam case SCF_ERROR_NOT_FOUND: 1199138568Ssam break; 1200116742Ssam 1201116742Ssam case SCF_ERROR_HANDLE_MISMATCH: 1202178354Ssam case SCF_ERROR_INVALID_ARGUMENT: 1203184273Ssam case SCF_ERROR_IN_USE: 1204178354Ssam case SCF_ERROR_NOT_SET: 1205170530Ssam bad_error("scf_transaction_property_change_type", 1206178354Ssam scf_error()); 1207178354Ssam } 1208178354Ssam 1209138568Ssam if (scf_transaction_property_new(tx, ent, pname, ty) == 0) 1210178354Ssam return (0); 1211116742Ssam 1212170530Ssam switch (scf_error()) { 1213178354Ssam case SCF_ERROR_CONNECTION_BROKEN: 1214178354Ssam default: 1215116742Ssam return (ECONNABORTED); 1216178354Ssam 1217184273Ssam case SCF_ERROR_DELETED: 1218178354Ssam return (ECANCELED); 1219178354Ssam 1220178354Ssam case SCF_ERROR_EXISTS: 1221178354Ssam break; 1222184273Ssam 1223178354Ssam case SCF_ERROR_HANDLE_MISMATCH: 1224116742Ssam case SCF_ERROR_INVALID_ARGUMENT: 1225178354Ssam case SCF_ERROR_IN_USE: 1226178354Ssam case SCF_ERROR_NOT_SET: 1227178354Ssam bad_error("scf_transaction_property_new", scf_error()); 1228178354Ssam /* NOTREACHED */ 1229178354Ssam } 1230178354Ssam } 1231178354Ssam} 1232178354Ssam 1233184273Ssam/* 1234178354Ssam * Returns 1235184273Ssam * 0 - success 1236178354Ssam * ECONNABORTED - repository connection broken 1237184273Ssam * - unknown libscf error 1238184273Ssam * ECANCELED - pg was deleted 1239193340Ssam * EPERM 1240178354Ssam * EACCES 1241178354Ssam * EROFS 1242116742Ssam */ 1243116742Ssamstatic int 1244170530Ssampg_set_prop_value(scf_propertygroup_t *pg, const char *pname, scf_value_t *v) 1245170530Ssam{ 1246170530Ssam scf_handle_t *h; 1247170530Ssam scf_transaction_t *tx; 1248170530Ssam scf_transaction_entry_t *e; 1249170530Ssam scf_type_t ty; 1250170530Ssam scf_error_t scfe; 1251170530Ssam int ret, r; 1252170530Ssam 1253170530Ssam h = scf_pg_handle(pg); 1254170530Ssam tx = safe_scf_transaction_create(h); 1255170530Ssam e = safe_scf_entry_create(h); 1256170530Ssam 1257170530Ssam ty = scf_value_type(v); 1258170530Ssam assert(ty != SCF_TYPE_INVALID); 1259170530Ssam 1260170530Ssam for (;;) { 1261170530Ssam if (scf_transaction_start(tx, pg) != 0) { 1262170530Ssam switch (scf_error()) { 1263170530Ssam case SCF_ERROR_CONNECTION_BROKEN: 1264170530Ssam default: 1265170530Ssam ret = ECONNABORTED; 1266170530Ssam goto out; 1267170530Ssam 1268170530Ssam case SCF_ERROR_DELETED: 1269170530Ssam ret = ECANCELED; 1270178354Ssam goto out; 1271170530Ssam 1272195618Srpaulo case SCF_ERROR_PERMISSION_DENIED: 1273195618Srpaulo ret = EPERM; 1274195618Srpaulo goto out; 1275170530Ssam 1276170530Ssam case SCF_ERROR_BACKEND_ACCESS: 1277170530Ssam ret = EACCES; 1278170530Ssam goto out; 1279170530Ssam 1280170530Ssam case SCF_ERROR_BACKEND_READONLY: 1281170530Ssam ret = EROFS; 1282170530Ssam goto out; 1283170530Ssam 1284170530Ssam case SCF_ERROR_NOT_SET: 1285170530Ssam bad_error("scf_transaction_start", ret); 1286170530Ssam } 1287170530Ssam } 1288170530Ssam 1289170530Ssam ret = transaction_add_set(tx, e, pname, ty); 1290170530Ssam switch (ret) { 1291170530Ssam case 0: 1292170530Ssam break; 1293178354Ssam 1294178354Ssam case ECONNABORTED: 1295178354Ssam case ECANCELED: 1296178354Ssam goto out; 1297178354Ssam 1298178354Ssam default: 1299170530Ssam bad_error("transaction_add_set", ret); 1300170530Ssam } 1301170530Ssam 1302178354Ssam r = scf_entry_add_value(e, v); 1303178354Ssam assert(r == 0); 1304178354Ssam 1305178354Ssam r = scf_transaction_commit(tx); 1306178354Ssam if (r == 1) 1307178354Ssam break; 1308178354Ssam if (r != 0) { 1309178354Ssam scfe = scf_error(); 1310178354Ssam scf_transaction_reset(tx); 1311178354Ssam switch (scfe) { 1312178354Ssam case SCF_ERROR_CONNECTION_BROKEN: 1313178354Ssam default: 1314178354Ssam ret = ECONNABORTED; 1315178354Ssam goto out; 1316178354Ssam 1317178354Ssam case SCF_ERROR_DELETED: 1318178354Ssam ret = ECANCELED; 1319116742Ssam goto out; 1320116742Ssam 1321116742Ssam case SCF_ERROR_PERMISSION_DENIED: 1322178354Ssam ret = EPERM; 1323178354Ssam goto out; 1324170530Ssam 1325116742Ssam case SCF_ERROR_BACKEND_ACCESS: 1326116742Ssam ret = EACCES; 1327170530Ssam goto out; 1328170530Ssam 1329170530Ssam case SCF_ERROR_BACKEND_READONLY: 1330170530Ssam ret = EROFS; 1331170530Ssam goto out; 1332178354Ssam 1333116742Ssam case SCF_ERROR_NOT_SET: 1334170530Ssam bad_error("scf_transaction_commit", scfe); 1335170530Ssam } 1336170530Ssam } 1337178354Ssam 1338138568Ssam scf_transaction_reset(tx); 1339138568Ssam 1340138568Ssam if (scf_pg_update(pg) == -1) { 1341178354Ssam switch (scf_error()) { 1342138568Ssam case SCF_ERROR_CONNECTION_BROKEN: 1343138568Ssam default: 1344138568Ssam ret = ECONNABORTED; 1345138568Ssam goto out; 1346178354Ssam 1347178354Ssam case SCF_ERROR_DELETED: 1348138568Ssam ret = ECANCELED; 1349138568Ssam goto out; 1350138568Ssam 1351138568Ssam case SCF_ERROR_NOT_SET: 1352178354Ssam bad_error("scf_pg_update", scf_error()); 1353128966Sandre } 1354138568Ssam } 1355178354Ssam } 1356178354Ssam 1357116742Ssam ret = 0; 1358116742Ssam 1359116742Ssamout: 1360116742Ssam scf_transaction_destroy(tx); 1361116742Ssam scf_entry_destroy(e); 1362116742Ssam return (ret); 1363116742Ssam} 1364116742Ssam 1365116742Ssam/* 1366116742Ssam * Returns 1367116742Ssam * 0 - success 1368116742Ssam * ECONNABORTED - repository connection broken 1369166012Ssam * - unknown libscf error 1370166012Ssam * ECANCELED - inst was deleted 1371166012Ssam * EPERM 1372166012Ssam * EACCES 1373116742Ssam * EROFS 1374166012Ssam */ 1375178354Ssamint 1376166012Ssamlibscf_inst_set_boolean_prop(scf_instance_t *inst, const char *pgname, 1377116742Ssam const char *pgtype, uint32_t pgflags, const char *pname, int val) 1378138568Ssam{ 1379138568Ssam scf_handle_t *h; 1380116742Ssam scf_propertygroup_t *pg = NULL; 1381116742Ssam scf_value_t *v; 1382116742Ssam int ret = 0; 1383116742Ssam 1384170530Ssam h = scf_instance_handle(inst); 1385116742Ssam pg = safe_scf_pg_create(h); 1386116742Ssam v = safe_scf_value_create(h); 1387170530Ssam 1388116742Ssam ret = libscf_inst_get_or_add_pg(inst, pgname, pgtype, pgflags, pg); 1389170530Ssam switch (ret) { 1390170530Ssam case 0: 1391170530Ssam break; 1392170530Ssam 1393170530Ssam case ECONNABORTED: 1394170530Ssam case ECANCELED: 1395170530Ssam case EPERM: 1396170530Ssam case EACCES: 1397170530Ssam case EROFS: 1398170530Ssam goto out; 1399153350Ssam 1400188782Ssam default: 1401188782Ssam bad_error("libscf_inst_get_or_add_pg", ret); 1402188782Ssam } 1403188782Ssam 1404170530Ssam scf_value_set_boolean(v, val); 1405116742Ssam 1406170530Ssam ret = pg_set_prop_value(pg, pname, v); 1407116742Ssam switch (ret) { 1408170530Ssam case 0: 1409116742Ssam case ECONNABORTED: 1410170530Ssam case ECANCELED: 1411170530Ssam case EPERM: 1412170530Ssam case EACCES: 1413170530Ssam case EROFS: 1414170530Ssam break; 1415170530Ssam 1416170530Ssam default: 1417116742Ssam bad_error("pg_set_prop_value", ret); 1418116742Ssam } 1419170530Ssam 1420170530Ssamout: 1421170530Ssam scf_pg_destroy(pg); 1422170530Ssam scf_value_destroy(v); 1423170530Ssam return (ret); 1424170530Ssam} 1425170530Ssam 1426170530Ssam/* 1427170530Ssam * Returns 1428170530Ssam * 0 - success 1429170530Ssam * ECONNABORTED - repository connection broken 1430170530Ssam * - unknown libscf error 1431170530Ssam * ECANCELED - inst was deleted 1432170530Ssam * EPERM 1433170530Ssam * EACCES 1434170530Ssam * EROFS 1435116742Ssam */ 1436170530Ssamint 1437170530Ssamlibscf_inst_set_count_prop(scf_instance_t *inst, const char *pgname, 1438170530Ssam const char *pgtype, uint32_t pgflags, const char *pname, uint64_t count) 1439116742Ssam{ 1440116742Ssam scf_handle_t *h; 1441116742Ssam scf_propertygroup_t *pg = NULL; 1442116742Ssam scf_value_t *v; 1443116742Ssam int ret = 0; 1444170530Ssam 1445124543Sonoe h = scf_instance_handle(inst); 1446124543Sonoe pg = safe_scf_pg_create(h); 1447124543Sonoe v = safe_scf_value_create(h); 1448124543Sonoe 1449124543Sonoe ret = libscf_inst_get_or_add_pg(inst, pgname, pgtype, pgflags, pg); 1450124543Sonoe switch (ret) { 1451124543Sonoe case 0: 1452124543Sonoe break; 1453124543Sonoe 1454124543Sonoe case ECONNABORTED: 1455124543Sonoe case ECANCELED: 1456124543Sonoe case EPERM: 1457124543Sonoe case EACCES: 1458124543Sonoe case EROFS: 1459124543Sonoe goto out; 1460124543Sonoe 1461124543Sonoe default: 1462124543Sonoe bad_error("libscf_inst_get_or_add_pg", ret); 1463124543Sonoe } 1464124543Sonoe 1465124543Sonoe scf_value_set_count(v, count); 1466124543Sonoe 1467124543Sonoe ret = pg_set_prop_value(pg, pname, v); 1468124543Sonoe switch (ret) { 1469124543Sonoe case 0: 1470124543Sonoe case ECONNABORTED: 1471124543Sonoe case ECANCELED: 1472165569Ssam case EPERM: 1473165569Ssam case EACCES: 1474165569Ssam case EROFS: 1475116742Ssam break; 1476116742Ssam 1477170530Ssam default: 1478170530Ssam bad_error("pg_set_prop_value", ret); 1479170530Ssam } 1480170530Ssam 1481170530Ssamout: 1482170530Ssam scf_pg_destroy(pg); 1483170530Ssam scf_value_destroy(v); 1484170530Ssam return (ret); 1485170530Ssam} 1486170530Ssam 1487170530Ssam/* 1488170530Ssam * Returns 0 on success, ECONNABORTED if the repository connection is broken, 1489170530Ssam * ECANCELED if inst is deleted, EROFS if the backend is readonly, or EPERM if 1490170530Ssam * permission was denied. 1491170530Ssam */ 1492170530Ssamint 1493170530Ssamlibscf_set_enable_ovr(scf_instance_t *inst, int enable) 1494170530Ssam{ 1495170530Ssam return (libscf_inst_set_boolean_prop(inst, SCF_PG_GENERAL_OVR, 1496116742Ssam SCF_PG_GENERAL_OVR_TYPE, SCF_PG_GENERAL_OVR_FLAGS, 1497170530Ssam SCF_PROPERTY_ENABLED, enable)); 1498170530Ssam} 1499170530Ssam 1500170530Ssam/* 1501172226Ssam * Returns 1502172226Ssam * 0 - success 1503170530Ssam * ECONNABORTED - repository connection broken 1504170530Ssam * ECANCELED - inst was deleted 1505170530Ssam * EPERM 1506170530Ssam * EACCES 1507170530Ssam * EROFS 1508170530Ssam */ 1509172226Ssamint 1510172226Ssamlibscf_inst_delete_prop(scf_instance_t *inst, const char *pgname, 1511170530Ssam const char *pname) 1512170530Ssam{ 1513170530Ssam scf_handle_t *h; 1514170530Ssam scf_propertygroup_t *pg; 1515170530Ssam scf_transaction_t *tx; 1516170530Ssam scf_transaction_entry_t *e; 1517116742Ssam scf_error_t serr; 1518116742Ssam int ret = 0, r; 1519188782Ssam 1520188782Ssam h = scf_instance_handle(inst); 1521170530Ssam pg = safe_scf_pg_create(h); 1522138568Ssam 1523170530Ssam if (scf_instance_get_pg(inst, pgname, pg) != 0) { 1524170530Ssam scf_pg_destroy(pg); 1525116742Ssam switch (scf_error()) { 1526170530Ssam case SCF_ERROR_CONNECTION_BROKEN: 1527124543Sonoe default: 1528170530Ssam return (ECONNABORTED); 1529116742Ssam 1530116742Ssam case SCF_ERROR_DELETED: 1531188775Ssam return (ECANCELED); 1532170530Ssam 1533170530Ssam case SCF_ERROR_NOT_FOUND: 1534116742Ssam return (0); 1535116742Ssam 1536116742Ssam case SCF_ERROR_NOT_SET: 1537170530Ssam bad_error("scf_instance_get_pg", scf_error()); 1538138568Ssam } 1539170530Ssam } 1540116742Ssam 1541116742Ssam tx = safe_scf_transaction_create(h); 1542116742Ssam e = safe_scf_entry_create(h); 1543116742Ssam 1544116742Ssam for (;;) { 1545116742Ssam if (scf_transaction_start(tx, pg) != 0) { 1546116742Ssam switch (scf_error()) { 1547116742Ssam case SCF_ERROR_CONNECTION_BROKEN: 1548116742Ssam default: 1549116742Ssam ret = ECONNABORTED; 1550116742Ssam goto out; 1551116742Ssam 1552116742Ssam case SCF_ERROR_DELETED: 1553116742Ssam ret = 0; 1554116742Ssam goto out; 1555116742Ssam 1556116742Ssam case SCF_ERROR_PERMISSION_DENIED: 1557116742Ssam ret = EPERM; 1558116742Ssam goto out; 1559116742Ssam 1560116742Ssam case SCF_ERROR_BACKEND_ACCESS: 1561116742Ssam ret = EACCES; 1562116742Ssam goto out; 1563116742Ssam 1564116742Ssam case SCF_ERROR_BACKEND_READONLY: 1565116742Ssam ret = EROFS; 1566116742Ssam goto out; 1567116742Ssam 1568116742Ssam case SCF_ERROR_HANDLE_MISMATCH: 1569165569Ssam case SCF_ERROR_INVALID_ARGUMENT: 1570165569Ssam case SCF_ERROR_NOT_SET: 1571165569Ssam bad_error("scf_transaction_start", scf_error()); 1572165569Ssam } 1573165569Ssam } 1574170530Ssam 1575116742Ssam if (scf_transaction_property_delete(tx, e, pname) != 0) { 1576116742Ssam switch (scf_error()) { 1577116742Ssam case SCF_ERROR_CONNECTION_BROKEN: 1578116742Ssam default: 1579116742Ssam ret = ECONNABORTED; 1580195379Ssam goto out; 1581195379Ssam 1582195379Ssam case SCF_ERROR_DELETED: 1583195379Ssam case SCF_ERROR_NOT_FOUND: 1584195379Ssam ret = 0; 1585195379Ssam goto out; 1586195379Ssam 1587195379Ssam case SCF_ERROR_NOT_SET: 1588195379Ssam case SCF_ERROR_HANDLE_MISMATCH: 1589195379Ssam case SCF_ERROR_NOT_BOUND: 1590195379Ssam case SCF_ERROR_INVALID_ARGUMENT: 1591195379Ssam bad_error("scf_transaction_property_delete", 1592195379Ssam scf_error()); 1593195379Ssam } 1594195379Ssam } 1595195379Ssam 1596195379Ssam r = scf_transaction_commit(tx); 1597195379Ssam if (r == 1) 1598195379Ssam break; 1599195379Ssam if (r != 0) { 1600195379Ssam serr = scf_error(); 1601195379Ssam scf_transaction_reset(tx); 1602195379Ssam switch (serr) { 1603195379Ssam case SCF_ERROR_CONNECTION_BROKEN: 1604195379Ssam default: 1605195379Ssam ret = ECONNABORTED; 1606195379Ssam goto out; 1607195379Ssam 1608195379Ssam case SCF_ERROR_DELETED: 1609195379Ssam ret = 0; 1610195379Ssam goto out; 1611195379Ssam 1612195379Ssam case SCF_ERROR_PERMISSION_DENIED: 1613195379Ssam ret = EPERM; 1614195379Ssam goto out; 1615195379Ssam 1616 case SCF_ERROR_BACKEND_ACCESS: 1617 ret = EACCES; 1618 goto out; 1619 1620 case SCF_ERROR_BACKEND_READONLY: 1621 ret = EROFS; 1622 goto out; 1623 1624 case SCF_ERROR_NOT_SET: 1625 case SCF_ERROR_INVALID_ARGUMENT: 1626 case SCF_ERROR_NOT_BOUND: 1627 bad_error("scf_transaction_commit", serr); 1628 } 1629 } 1630 1631 scf_transaction_reset(tx); 1632 1633 if (scf_pg_update(pg) == -1) { 1634 switch (scf_error()) { 1635 case SCF_ERROR_CONNECTION_BROKEN: 1636 default: 1637 ret = ECONNABORTED; 1638 goto out; 1639 1640 case SCF_ERROR_DELETED: 1641 ret = 0; 1642 goto out; 1643 1644 case SCF_ERROR_NOT_SET: 1645 case SCF_ERROR_NOT_BOUND: 1646 bad_error("scf_pg_update", scf_error()); 1647 } 1648 } 1649 } 1650 1651out: 1652 scf_transaction_destroy(tx); 1653 (void) scf_entry_destroy(e); 1654 scf_pg_destroy(pg); 1655 return (ret); 1656} 1657 1658/* 1659 * Returns 0, ECONNABORTED, ECANCELED, or EPERM. 1660 */ 1661int 1662libscf_delete_enable_ovr(scf_instance_t *inst) 1663{ 1664 return (libscf_inst_delete_prop(inst, SCF_PG_GENERAL_OVR, 1665 SCF_PROPERTY_ENABLED)); 1666} 1667 1668/* 1669 * Fails with 1670 * ECONNABORTED - repository connection was broken 1671 * ECANCELED - pg was deleted 1672 * ENOENT - pg has no milestone property 1673 * EINVAL - the milestone property is misconfigured 1674 */ 1675static int 1676pg_get_milestone(scf_propertygroup_t *pg, scf_property_t *prop, 1677 scf_value_t *val, char *buf, size_t buf_sz) 1678{ 1679 if (scf_pg_get_property(pg, SCF_PROPERTY_MILESTONE, prop) != 0) { 1680 switch (scf_error()) { 1681 case SCF_ERROR_CONNECTION_BROKEN: 1682 default: 1683 return (ECONNABORTED); 1684 1685 case SCF_ERROR_DELETED: 1686 return (ECANCELED); 1687 1688 case SCF_ERROR_NOT_FOUND: 1689 return (ENOENT); 1690 1691 case SCF_ERROR_HANDLE_MISMATCH: 1692 case SCF_ERROR_INVALID_ARGUMENT: 1693 case SCF_ERROR_NOT_SET: 1694 bad_error("scf_pg_get_property", scf_error()); 1695 } 1696 } 1697 1698 if (scf_property_get_value(prop, val) != 0) { 1699 switch (scf_error()) { 1700 case SCF_ERROR_CONNECTION_BROKEN: 1701 default: 1702 return (ECONNABORTED); 1703 1704 case SCF_ERROR_DELETED: 1705 case SCF_ERROR_CONSTRAINT_VIOLATED: 1706 case SCF_ERROR_NOT_FOUND: 1707 return (EINVAL); 1708 1709 case SCF_ERROR_NOT_SET: 1710 case SCF_ERROR_PERMISSION_DENIED: 1711 bad_error("scf_property_get_value", scf_error()); 1712 } 1713 } 1714 1715 if (scf_value_get_astring(val, buf, buf_sz) < 0) { 1716 switch (scf_error()) { 1717 case SCF_ERROR_TYPE_MISMATCH: 1718 return (EINVAL); 1719 1720 case SCF_ERROR_NOT_SET: 1721 default: 1722 bad_error("scf_value_get_astring", scf_error()); 1723 } 1724 } 1725 1726 return (0); 1727} 1728 1729/* 1730 * Fails with 1731 * ECONNABORTED - repository connection was broken 1732 * ECANCELED - inst was deleted 1733 * ENOENT - inst has no milestone property 1734 * EINVAL - the milestone property is misconfigured 1735 */ 1736int 1737libscf_get_milestone(scf_instance_t *inst, scf_property_t *prop, 1738 scf_value_t *val, char *buf, size_t buf_sz) 1739{ 1740 scf_propertygroup_t *pg; 1741 int r; 1742 1743 pg = safe_scf_pg_create(scf_instance_handle(inst)); 1744 1745 if (scf_instance_get_pg(inst, SCF_PG_OPTIONS_OVR, pg) == 0) { 1746 switch (r = pg_get_milestone(pg, prop, val, buf, buf_sz)) { 1747 case 0: 1748 case ECONNABORTED: 1749 case EINVAL: 1750 goto out; 1751 1752 case ECANCELED: 1753 case ENOENT: 1754 break; 1755 1756 default: 1757 bad_error("pg_get_milestone", r); 1758 } 1759 } else { 1760 switch (scf_error()) { 1761 case SCF_ERROR_CONNECTION_BROKEN: 1762 default: 1763 r = ECONNABORTED; 1764 goto out; 1765 1766 case SCF_ERROR_DELETED: 1767 r = ECANCELED; 1768 goto out; 1769 1770 case SCF_ERROR_NOT_FOUND: 1771 break; 1772 1773 case SCF_ERROR_HANDLE_MISMATCH: 1774 case SCF_ERROR_INVALID_ARGUMENT: 1775 case SCF_ERROR_NOT_SET: 1776 bad_error("scf_instance_get_pg", scf_error()); 1777 } 1778 } 1779 1780 if (scf_instance_get_pg(inst, SCF_PG_OPTIONS, pg) == 0) { 1781 r = pg_get_milestone(pg, prop, val, buf, buf_sz); 1782 } else { 1783 switch (scf_error()) { 1784 case SCF_ERROR_CONNECTION_BROKEN: 1785 default: 1786 r = ECONNABORTED; 1787 goto out; 1788 1789 case SCF_ERROR_DELETED: 1790 r = ECANCELED; 1791 goto out; 1792 1793 case SCF_ERROR_NOT_FOUND: 1794 r = ENOENT; 1795 break; 1796 1797 case SCF_ERROR_HANDLE_MISMATCH: 1798 case SCF_ERROR_INVALID_ARGUMENT: 1799 case SCF_ERROR_NOT_SET: 1800 bad_error("scf_instance_get_pg", scf_error()); 1801 } 1802 } 1803 1804out: 1805 scf_pg_destroy(pg); 1806 1807 return (r); 1808} 1809 1810/* 1811 * Get the runlevel character from the runlevel property of the given property 1812 * group. Fails with 1813 * ECONNABORTED - repository connection was broken 1814 * ECANCELED - prop's property group was deleted 1815 * ENOENT - the property has no values 1816 * EINVAL - the property has more than one value 1817 * the property is of the wrong type 1818 * the property value is malformed 1819 */ 1820int 1821libscf_extract_runlevel(scf_property_t *prop, char *rlp) 1822{ 1823 scf_value_t *val; 1824 char buf[2]; 1825 1826 val = safe_scf_value_create(scf_property_handle(prop)); 1827 1828 if (scf_property_get_value(prop, val) != 0) { 1829 switch (scf_error()) { 1830 case SCF_ERROR_CONNECTION_BROKEN: 1831 return (ECONNABORTED); 1832 1833 case SCF_ERROR_NOT_SET: 1834 return (ENOENT); 1835 1836 case SCF_ERROR_DELETED: 1837 return (ECANCELED); 1838 1839 case SCF_ERROR_CONSTRAINT_VIOLATED: 1840 return (EINVAL); 1841 1842 case SCF_ERROR_NOT_FOUND: 1843 return (ENOENT); 1844 1845 case SCF_ERROR_HANDLE_MISMATCH: 1846 case SCF_ERROR_NOT_BOUND: 1847 case SCF_ERROR_PERMISSION_DENIED: 1848 default: 1849 bad_error("scf_property_get_value", scf_error()); 1850 } 1851 } 1852 1853 if (scf_value_get_astring(val, buf, sizeof (buf)) < 0) { 1854 if (scf_error() != SCF_ERROR_TYPE_MISMATCH) 1855 bad_error("scf_value_get_astring", scf_error()); 1856 1857 return (EINVAL); 1858 } 1859 1860 if (buf[0] == '\0' || buf[1] != '\0') 1861 return (EINVAL); 1862 1863 *rlp = buf[0]; 1864 1865 return (0); 1866} 1867 1868/* 1869 * Delete the "runlevel" property from the given property group. Also set the 1870 * "milestone" property to the given string. Fails with ECONNABORTED, 1871 * ECANCELED, EPERM, EACCES, or EROFS. 1872 */ 1873int 1874libscf_clear_runlevel(scf_propertygroup_t *pg, const char *milestone) 1875{ 1876 scf_handle_t *h; 1877 scf_transaction_t *tx; 1878 scf_transaction_entry_t *e_rl, *e_ms; 1879 scf_value_t *val; 1880 scf_error_t serr; 1881 boolean_t isempty = B_TRUE; 1882 int ret = 0, r; 1883 1884 h = scf_pg_handle(pg); 1885 tx = safe_scf_transaction_create(h); 1886 e_rl = safe_scf_entry_create(h); 1887 e_ms = safe_scf_entry_create(h); 1888 val = safe_scf_value_create(h); 1889 1890 if (milestone) { 1891 r = scf_value_set_astring(val, milestone); 1892 assert(r == 0); 1893 } 1894 1895 for (;;) { 1896 if (scf_transaction_start(tx, pg) != 0) { 1897 switch (scf_error()) { 1898 case SCF_ERROR_CONNECTION_BROKEN: 1899 default: 1900 ret = ECONNABORTED; 1901 goto out; 1902 1903 case SCF_ERROR_DELETED: 1904 ret = ECANCELED; 1905 goto out; 1906 1907 case SCF_ERROR_PERMISSION_DENIED: 1908 ret = EPERM; 1909 goto out; 1910 1911 case SCF_ERROR_BACKEND_ACCESS: 1912 ret = EACCES; 1913 goto out; 1914 1915 case SCF_ERROR_BACKEND_READONLY: 1916 ret = EROFS; 1917 goto out; 1918 1919 case SCF_ERROR_NOT_SET: 1920 bad_error("scf_transaction_start", scf_error()); 1921 } 1922 } 1923 1924 if (scf_transaction_property_delete(tx, e_rl, 1925 "runlevel") == 0) { 1926 isempty = B_FALSE; 1927 } else { 1928 switch (scf_error()) { 1929 case SCF_ERROR_CONNECTION_BROKEN: 1930 default: 1931 ret = ECONNABORTED; 1932 goto out; 1933 1934 case SCF_ERROR_DELETED: 1935 ret = ECANCELED; 1936 goto out; 1937 1938 case SCF_ERROR_NOT_FOUND: 1939 break; 1940 1941 case SCF_ERROR_HANDLE_MISMATCH: 1942 case SCF_ERROR_NOT_BOUND: 1943 case SCF_ERROR_INVALID_ARGUMENT: 1944 bad_error("scf_transaction_property_delete", 1945 scf_error()); 1946 } 1947 } 1948 1949 if (milestone) { 1950 ret = transaction_add_set(tx, e_ms, 1951 SCF_PROPERTY_MILESTONE, SCF_TYPE_ASTRING); 1952 switch (ret) { 1953 case 0: 1954 break; 1955 1956 case ECONNABORTED: 1957 case ECANCELED: 1958 goto out; 1959 1960 default: 1961 bad_error("transaction_add_set", ret); 1962 } 1963 1964 isempty = B_FALSE; 1965 1966 r = scf_entry_add_value(e_ms, val); 1967 assert(r == 0); 1968 } 1969 1970 if (isempty) 1971 goto out; 1972 1973 r = scf_transaction_commit(tx); 1974 if (r == 1) 1975 break; 1976 if (r != 0) { 1977 serr = scf_error(); 1978 scf_transaction_reset(tx); 1979 switch (serr) { 1980 case SCF_ERROR_CONNECTION_BROKEN: 1981 ret = ECONNABORTED; 1982 goto out; 1983 1984 case SCF_ERROR_PERMISSION_DENIED: 1985 ret = EPERM; 1986 goto out; 1987 1988 case SCF_ERROR_BACKEND_ACCESS: 1989 ret = EACCES; 1990 goto out; 1991 1992 case SCF_ERROR_BACKEND_READONLY: 1993 ret = EROFS; 1994 goto out; 1995 1996 default: 1997 bad_error("scf_transaction_commit", serr); 1998 } 1999 } 2000 2001 scf_transaction_reset(tx); 2002 2003 if (scf_pg_update(pg) == -1) { 2004 switch (scf_error()) { 2005 case SCF_ERROR_CONNECTION_BROKEN: 2006 ret = ECONNABORTED; 2007 goto out; 2008 2009 case SCF_ERROR_NOT_SET: 2010 ret = ECANCELED; 2011 goto out; 2012 2013 default: 2014 assert(0); 2015 abort(); 2016 } 2017 } 2018 } 2019 2020out: 2021 scf_transaction_destroy(tx); 2022 scf_entry_destroy(e_rl); 2023 scf_entry_destroy(e_ms); 2024 scf_value_destroy(val); 2025 return (ret); 2026} 2027 2028/* 2029 * int libscf_get_template_values(scf_instance_t *, scf_snapshot_t *, 2030 * char **) 2031 * 2032 * Return template values for inst in *common_name suitable for use in 2033 * restarter_inst_t->ri_common_name. Called by restarter_insert_inst(). 2034 * 2035 * Returns 0 on success, ECANCELED if the instance is deleted, ECHILD if 2036 * a value fetch failed for a property, ENOENT if the instance has no 2037 * tm_common_name property group or the property group is deleted, and 2038 * ECONNABORTED if the repository connection is broken. 2039 */ 2040int 2041libscf_get_template_values(scf_instance_t *inst, scf_snapshot_t *snap, 2042 char **common_name, char **c_common_name) 2043{ 2044 scf_handle_t *h; 2045 scf_propertygroup_t *pg = NULL; 2046 scf_property_t *prop = NULL; 2047 int ret = 0, r; 2048 char *cname = startd_alloc(max_scf_value_size); 2049 char *c_cname = startd_alloc(max_scf_value_size); 2050 int common_name_initialized = B_FALSE; 2051 int c_common_name_initialized = B_FALSE; 2052 2053 h = scf_instance_handle(inst); 2054 pg = safe_scf_pg_create(h); 2055 prop = safe_scf_property_create(h); 2056 2057 /* 2058 * The tm_common_name property group, as with all template property 2059 * groups, is optional. 2060 */ 2061 if (scf_instance_get_pg_composed(inst, snap, SCF_PG_TM_COMMON_NAME, pg) 2062 == -1) { 2063 switch (scf_error()) { 2064 case SCF_ERROR_DELETED: 2065 ret = ECANCELED; 2066 goto template_values_out; 2067 2068 case SCF_ERROR_NOT_FOUND: 2069 goto template_values_out; 2070 2071 case SCF_ERROR_CONNECTION_BROKEN: 2072 default: 2073 ret = ECONNABORTED; 2074 goto template_values_out; 2075 2076 case SCF_ERROR_INVALID_ARGUMENT: 2077 case SCF_ERROR_HANDLE_MISMATCH: 2078 case SCF_ERROR_NOT_SET: 2079 bad_error("scf_instance_get_pg_composed", scf_error()); 2080 } 2081 } 2082 2083 /* 2084 * The name we wish uses the current locale name as the property name. 2085 */ 2086 if (st->st_locale != NULL) { 2087 if (scf_pg_get_property(pg, st->st_locale, prop) == -1) { 2088 switch (scf_error()) { 2089 case SCF_ERROR_DELETED: 2090 case SCF_ERROR_NOT_FOUND: 2091 break; 2092 2093 case SCF_ERROR_CONNECTION_BROKEN: 2094 default: 2095 ret = ECONNABORTED; 2096 goto template_values_out; 2097 2098 case SCF_ERROR_INVALID_ARGUMENT: 2099 case SCF_ERROR_HANDLE_MISMATCH: 2100 case SCF_ERROR_NOT_SET: 2101 bad_error("scf_pg_get_property", scf_error()); 2102 } 2103 } else { 2104 if ((r = libscf_read_single_astring(h, prop, &cname)) != 2105 0) { 2106 if (r != LIBSCF_PROPERTY_ABSENT) 2107 ret = ECHILD; 2108 goto template_values_out; 2109 } 2110 2111 *common_name = cname; 2112 common_name_initialized = B_TRUE; 2113 } 2114 } 2115 2116 /* 2117 * Also pull out the C locale name, as a fallback for the case where 2118 * service offers no localized name. 2119 */ 2120 if (scf_pg_get_property(pg, "C", prop) == -1) { 2121 switch (scf_error()) { 2122 case SCF_ERROR_DELETED: 2123 ret = ENOENT; 2124 goto template_values_out; 2125 2126 case SCF_ERROR_NOT_FOUND: 2127 break; 2128 2129 case SCF_ERROR_CONNECTION_BROKEN: 2130 default: 2131 ret = ECONNABORTED; 2132 goto template_values_out; 2133 2134 case SCF_ERROR_INVALID_ARGUMENT: 2135 case SCF_ERROR_HANDLE_MISMATCH: 2136 case SCF_ERROR_NOT_SET: 2137 bad_error("scf_pg_get_property", scf_error()); 2138 } 2139 } else { 2140 if ((r = libscf_read_single_astring(h, prop, &c_cname)) != 0) { 2141 if (r != LIBSCF_PROPERTY_ABSENT) 2142 ret = ECHILD; 2143 goto template_values_out; 2144 } 2145 2146 *c_common_name = c_cname; 2147 c_common_name_initialized = B_TRUE; 2148 } 2149 2150 2151template_values_out: 2152 if (common_name_initialized == B_FALSE) 2153 startd_free(cname, max_scf_value_size); 2154 if (c_common_name_initialized == B_FALSE) 2155 startd_free(c_cname, max_scf_value_size); 2156 scf_property_destroy(prop); 2157 scf_pg_destroy(pg); 2158 2159 return (ret); 2160} 2161 2162/* 2163 * int libscf_get_startd_properties(scf_handle_t *, scf_instance_t *, 2164 * scf_snapshot_t *, uint_t *, char **) 2165 * 2166 * Return startd settings for inst in *flags suitable for use in 2167 * restarter_inst_t->ri_flags. Called by restarter_insert_inst(). 2168 * 2169 * Returns 0 on success, ECANCELED if the instance is deleted, ECHILD if 2170 * a value fetch failed for a property, ENOENT if the instance has no 2171 * general property group or the property group is deleted, and 2172 * ECONNABORTED if the repository connection is broken. 2173 */ 2174int 2175libscf_get_startd_properties(scf_instance_t *inst, 2176 scf_snapshot_t *snap, uint_t *flags, char **prefixp) 2177{ 2178 scf_handle_t *h; 2179 scf_propertygroup_t *pg = NULL; 2180 scf_property_t *prop = NULL; 2181 int style = RINST_CONTRACT; 2182 char *style_str = startd_alloc(max_scf_value_size); 2183 int ret = 0, r; 2184 2185 h = scf_instance_handle(inst); 2186 pg = safe_scf_pg_create(h); 2187 prop = safe_scf_property_create(h); 2188 2189 /* 2190 * The startd property group is optional. 2191 */ 2192 if (scf_instance_get_pg_composed(inst, snap, SCF_PG_STARTD, pg) == -1) { 2193 switch (scf_error()) { 2194 case SCF_ERROR_DELETED: 2195 ret = ECANCELED; 2196 goto instance_flags_out; 2197 2198 case SCF_ERROR_NOT_FOUND: 2199 ret = ENOENT; 2200 goto instance_flags_out; 2201 2202 case SCF_ERROR_CONNECTION_BROKEN: 2203 default: 2204 ret = ECONNABORTED; 2205 goto instance_flags_out; 2206 2207 case SCF_ERROR_INVALID_ARGUMENT: 2208 case SCF_ERROR_HANDLE_MISMATCH: 2209 case SCF_ERROR_NOT_SET: 2210 bad_error("scf_instance_get_pg_composed", scf_error()); 2211 } 2212 } 2213 2214 /* 2215 * 1. Duration property. 2216 */ 2217 if (scf_pg_get_property(pg, SCF_PROPERTY_DURATION, prop) == -1) { 2218 switch (scf_error()) { 2219 case SCF_ERROR_DELETED: 2220 ret = ENOENT; 2221 goto instance_flags_out; 2222 2223 case SCF_ERROR_NOT_FOUND: 2224 break; 2225 2226 case SCF_ERROR_CONNECTION_BROKEN: 2227 default: 2228 ret = ECONNABORTED; 2229 goto instance_flags_out; 2230 2231 case SCF_ERROR_INVALID_ARGUMENT: 2232 case SCF_ERROR_HANDLE_MISMATCH: 2233 case SCF_ERROR_NOT_SET: 2234 bad_error("scf_pg_get_property", scf_error()); 2235 } 2236 } else { 2237 errno = 0; 2238 if ((r = libscf_read_single_astring(h, prop, &style_str)) 2239 != 0) { 2240 if (r != LIBSCF_PROPERTY_ABSENT) 2241 ret = ECHILD; 2242 goto instance_flags_out; 2243 } 2244 2245 if (strcmp(style_str, "child") == 0) 2246 style = RINST_WAIT; 2247 else if (strcmp(style_str, "transient") == 0) 2248 style = RINST_TRANSIENT; 2249 } 2250 2251 /* 2252 * 2. utmpx prefix property. 2253 */ 2254 if (scf_pg_get_property(pg, SCF_PROPERTY_UTMPX_PREFIX, prop) == 0) { 2255 errno = 0; 2256 if ((r = libscf_read_single_astring(h, prop, prefixp)) != 0) { 2257 if (r != LIBSCF_PROPERTY_ABSENT) 2258 ret = ECHILD; 2259 goto instance_flags_out; 2260 } 2261 } else { 2262 switch (scf_error()) { 2263 case SCF_ERROR_DELETED: 2264 ret = ENOENT; 2265 goto instance_flags_out; 2266 2267 case SCF_ERROR_NOT_FOUND: 2268 goto instance_flags_out; 2269 2270 case SCF_ERROR_CONNECTION_BROKEN: 2271 default: 2272 ret = ECONNABORTED; 2273 goto instance_flags_out; 2274 2275 case SCF_ERROR_INVALID_ARGUMENT: 2276 case SCF_ERROR_HANDLE_MISMATCH: 2277 case SCF_ERROR_NOT_SET: 2278 bad_error("scf_pg_get_property", scf_error()); 2279 } 2280 } 2281 2282instance_flags_out: 2283 startd_free(style_str, max_scf_value_size); 2284 *flags = (*flags & ~RINST_STYLE_MASK) | style; 2285 2286 scf_property_destroy(prop); 2287 scf_pg_destroy(pg); 2288 2289 return (ret); 2290} 2291 2292/* 2293 * int libscf_read_method_ids(scf_handle_t *, scf_instance_t *, ctid_t *, 2294 * ctid_t *, pid_t *) 2295 * 2296 * Sets given id_t variables to primary and transient contract IDs and start 2297 * PID. Returns 0, ECONNABORTED, and ECANCELED. 2298 */ 2299int 2300libscf_read_method_ids(scf_handle_t *h, scf_instance_t *inst, const char *fmri, 2301 ctid_t *primary, ctid_t *transient, pid_t *start_pid) 2302{ 2303 scf_propertygroup_t *pg = NULL; 2304 scf_property_t *prop = NULL; 2305 scf_value_t *val = NULL; 2306 uint64_t p, t; 2307 int ret = 0; 2308 2309 *primary = 0; 2310 *transient = 0; 2311 *start_pid = -1; 2312 2313 pg = safe_scf_pg_create(h); 2314 prop = safe_scf_property_create(h); 2315 val = safe_scf_value_create(h); 2316 2317 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) == -1) { 2318 switch (scf_error()) { 2319 case SCF_ERROR_CONNECTION_BROKEN: 2320 default: 2321 ret = ECONNABORTED; 2322 goto read_id_err; 2323 2324 case SCF_ERROR_DELETED: 2325 ret = ECANCELED; 2326 goto read_id_err; 2327 2328 case SCF_ERROR_NOT_FOUND: 2329 goto read_id_err; 2330 2331 case SCF_ERROR_NOT_SET: 2332 bad_error("scf_instance_get_pg", scf_error()); 2333 } 2334 } 2335 2336 ret = get_count(pg, SCF_PROPERTY_CONTRACT, &p); 2337 switch (ret) { 2338 case 0: 2339 break; 2340 2341 case EINVAL: 2342 log_error(LOG_NOTICE, 2343 "%s: Ignoring %s/%s: multivalued or not of type count\n", 2344 fmri, SCF_PG_RESTARTER, SCF_PROPERTY_CONTRACT); 2345 /* FALLTHROUGH */ 2346 case ENOENT: 2347 ret = 0; 2348 goto read_trans; 2349 2350 case ECONNABORTED: 2351 case ECANCELED: 2352 goto read_id_err; 2353 2354 case EACCES: 2355 default: 2356 bad_error("get_count", ret); 2357 } 2358 2359 *primary = p; 2360 2361read_trans: 2362 ret = get_count(pg, SCF_PROPERTY_TRANSIENT_CONTRACT, &t); 2363 switch (ret) { 2364 case 0: 2365 break; 2366 2367 case EINVAL: 2368 log_error(LOG_NOTICE, 2369 "%s: Ignoring %s/%s: multivalued or not of type count\n", 2370 fmri, SCF_PG_RESTARTER, SCF_PROPERTY_TRANSIENT_CONTRACT); 2371 /* FALLTHROUGH */ 2372 2373 case ENOENT: 2374 ret = 0; 2375 goto read_pid_only; 2376 2377 case ECONNABORTED: 2378 case ECANCELED: 2379 goto read_id_err; 2380 2381 case EACCES: 2382 default: 2383 bad_error("get_count", ret); 2384 } 2385 2386 *transient = t; 2387 2388read_pid_only: 2389 ret = get_count(pg, SCF_PROPERTY_START_PID, &p); 2390 switch (ret) { 2391 case 0: 2392 break; 2393 2394 case EINVAL: 2395 log_error(LOG_NOTICE, 2396 "%s: Ignoring %s/%s: multivalued or not of type count\n", 2397 fmri, SCF_PG_RESTARTER, SCF_PROPERTY_START_PID); 2398 /* FALLTHROUGH */ 2399 case ENOENT: 2400 ret = 0; 2401 goto read_id_err; 2402 2403 case ECONNABORTED: 2404 case ECANCELED: 2405 goto read_id_err; 2406 2407 case EACCES: 2408 default: 2409 bad_error("get_count", ret); 2410 } 2411 2412 *start_pid = p; 2413 2414read_id_err: 2415 scf_value_destroy(val); 2416 scf_property_destroy(prop); 2417 scf_pg_destroy(pg); 2418 return (ret); 2419} 2420 2421/* 2422 * Returns with 2423 * 0 - success 2424 * ECONNABORTED - repository connection broken 2425 * - unknown libscf error 2426 * ECANCELED - s_inst was deleted 2427 * EPERM 2428 * EACCES 2429 * EROFS 2430 */ 2431int 2432libscf_write_start_pid(scf_instance_t *s_inst, pid_t pid) 2433{ 2434 scf_handle_t *h; 2435 scf_transaction_entry_t *t_pid; 2436 scf_value_t *v_pid; 2437 scf_propertygroup_t *pg; 2438 int ret = 0; 2439 2440 h = scf_instance_handle(s_inst); 2441 2442 pg = safe_scf_pg_create(h); 2443 t_pid = safe_scf_entry_create(h); 2444 v_pid = safe_scf_value_create(h); 2445 2446get_pg: 2447 ret = libscf_inst_get_or_add_pg(s_inst, SCF_PG_RESTARTER, 2448 SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg); 2449 switch (ret) { 2450 case 0: 2451 break; 2452 2453 case ECONNABORTED: 2454 case ECANCELED: 2455 case EPERM: 2456 case EACCES: 2457 case EROFS: 2458 goto write_start_err; 2459 2460 default: 2461 bad_error("libscf_inst_get_or_add_pg", ret); 2462 } 2463 2464 scf_value_set_count(v_pid, pid); 2465 2466 ret = pg_set_prop_value(pg, SCF_PROPERTY_START_PID, v_pid); 2467 switch (ret) { 2468 case 0: 2469 case ECONNABORTED: 2470 case EPERM: 2471 case EACCES: 2472 case EROFS: 2473 break; 2474 2475 case ECANCELED: 2476 goto get_pg; 2477 2478 default: 2479 bad_error("pg_set_prop_value", ret); 2480 } 2481 2482write_start_err: 2483 scf_entry_destroy(t_pid); 2484 scf_value_destroy(v_pid); 2485 scf_pg_destroy(pg); 2486 2487 return (ret); 2488} 2489 2490/* 2491 * Add a property indicating the instance log file. If the dir is 2492 * equal to LOG_PREFIX_EARLY, then the property restarter/alt_logfile 2493 * of the instance is used; otherwise, restarter/logfile is used. 2494 * 2495 * Returns 2496 * 0 - success 2497 * ECONNABORTED 2498 * ECANCELED 2499 * EPERM 2500 * EACCES 2501 * EROFS 2502 * EAGAIN 2503 */ 2504int 2505libscf_note_method_log(scf_instance_t *inst, const char *dir, const char *file) 2506{ 2507 scf_handle_t *h; 2508 scf_value_t *v; 2509 scf_propertygroup_t *pg; 2510 int ret = 0; 2511 char *logname; 2512 const char *propname; 2513 2514 h = scf_instance_handle(inst); 2515 pg = safe_scf_pg_create(h); 2516 v = safe_scf_value_create(h); 2517 2518 logname = uu_msprintf("%s%s", dir, file); 2519 2520 if (logname == NULL) { 2521 ret = errno; 2522 goto out; 2523 } 2524 2525 ret = libscf_inst_get_or_add_pg(inst, SCF_PG_RESTARTER, 2526 SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg); 2527 switch (ret) { 2528 case 0: 2529 break; 2530 2531 case ECONNABORTED: 2532 case ECANCELED: 2533 case EPERM: 2534 case EACCES: 2535 case EROFS: 2536 goto out; 2537 2538 default: 2539 bad_error("libscf_inst_get_or_add_pg", ret); 2540 } 2541 2542 (void) scf_value_set_astring(v, logname); 2543 2544 if (strcmp(LOG_PREFIX_EARLY, dir) == 0) 2545 propname = SCF_PROPERTY_ALT_LOGFILE; 2546 else 2547 propname = SCF_PROPERTY_LOGFILE; 2548 2549 ret = pg_set_prop_value(pg, propname, v); 2550 switch (ret) { 2551 case 0: 2552 case ECONNABORTED: 2553 case ECANCELED: 2554 case EPERM: 2555 case EACCES: 2556 case EROFS: 2557 break; 2558 2559 default: 2560 bad_error("pg_set_prop_value", ret); 2561 } 2562 2563out: 2564 scf_pg_destroy(pg); 2565 scf_value_destroy(v); 2566 uu_free(logname); 2567 return (ret); 2568} 2569 2570/* 2571 * Returns 2572 * 0 - success 2573 * ENAMETOOLONG - name is too long 2574 * ECONNABORTED 2575 * ECANCELED 2576 * EPERM 2577 * EACCES 2578 * EROFS 2579 */ 2580int 2581libscf_write_method_status(scf_instance_t *s_inst, const char *name, 2582 int status) 2583{ 2584 scf_handle_t *h; 2585 scf_transaction_t *tx; 2586 scf_transaction_entry_t *e_time, *e_stat; 2587 scf_value_t *v_time, *v_stat; 2588 scf_propertygroup_t *pg; 2589 int ret = 0, r; 2590 char pname[30]; 2591 struct timeval tv; 2592 scf_error_t scfe; 2593 2594 if (strlen(name) + sizeof ("_method_waitstatus") > sizeof (pname)) 2595 return (ENAMETOOLONG); 2596 2597 h = scf_instance_handle(s_inst); 2598 2599 pg = safe_scf_pg_create(h); 2600 tx = safe_scf_transaction_create(h); 2601 e_time = safe_scf_entry_create(h); 2602 v_time = safe_scf_value_create(h); 2603 e_stat = safe_scf_entry_create(h); 2604 v_stat = safe_scf_value_create(h); 2605 2606get_pg: 2607 ret = libscf_inst_get_or_add_pg(s_inst, SCF_PG_RESTARTER, 2608 SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg); 2609 switch (ret) { 2610 case 0: 2611 break; 2612 2613 case ECONNABORTED: 2614 case ECANCELED: 2615 case EPERM: 2616 case EACCES: 2617 case EROFS: 2618 goto out; 2619 2620 default: 2621 bad_error("libscf_inst_get_or_add_pg", ret); 2622 } 2623 2624 (void) gettimeofday(&tv, NULL); 2625 2626 r = scf_value_set_time(v_time, tv.tv_sec, tv.tv_usec * 1000); 2627 assert(r == 0); 2628 2629 scf_value_set_integer(v_stat, status); 2630 2631 for (;;) { 2632 if (scf_transaction_start(tx, pg) != 0) { 2633 switch (scf_error()) { 2634 case SCF_ERROR_CONNECTION_BROKEN: 2635 default: 2636 ret = ECONNABORTED; 2637 goto out; 2638 2639 case SCF_ERROR_DELETED: 2640 ret = ECANCELED; 2641 goto out; 2642 2643 case SCF_ERROR_PERMISSION_DENIED: 2644 ret = EPERM; 2645 goto out; 2646 2647 case SCF_ERROR_BACKEND_ACCESS: 2648 ret = EACCES; 2649 goto out; 2650 2651 case SCF_ERROR_BACKEND_READONLY: 2652 ret = EROFS; 2653 goto out; 2654 2655 case SCF_ERROR_NOT_SET: 2656 bad_error("scf_transaction_start", ret); 2657 } 2658 } 2659 2660 (void) snprintf(pname, sizeof (pname), "%s_method_timestamp", 2661 name); 2662 ret = transaction_add_set(tx, e_time, pname, SCF_TYPE_TIME); 2663 switch (ret) { 2664 case 0: 2665 break; 2666 2667 case ECONNABORTED: 2668 case ECANCELED: 2669 goto out; 2670 2671 default: 2672 bad_error("transaction_add_set", ret); 2673 } 2674 2675 r = scf_entry_add_value(e_time, v_time); 2676 assert(r == 0); 2677 2678 (void) snprintf(pname, sizeof (pname), "%s_method_waitstatus", 2679 name); 2680 ret = transaction_add_set(tx, e_stat, pname, SCF_TYPE_INTEGER); 2681 switch (ret) { 2682 case 0: 2683 break; 2684 2685 case ECONNABORTED: 2686 case ECANCELED: 2687 goto out; 2688 2689 default: 2690 bad_error("transaction_add_set", ret); 2691 } 2692 2693 r = scf_entry_add_value(e_stat, v_stat); 2694 if (r != 0) 2695 bad_error("scf_entry_add_value", scf_error()); 2696 2697 r = scf_transaction_commit(tx); 2698 if (r == 1) 2699 break; 2700 if (r != 0) { 2701 scfe = scf_error(); 2702 scf_transaction_reset_all(tx); 2703 switch (scfe) { 2704 case SCF_ERROR_CONNECTION_BROKEN: 2705 default: 2706 ret = ECONNABORTED; 2707 goto out; 2708 2709 case SCF_ERROR_DELETED: 2710 ret = ECANCELED; 2711 goto out; 2712 2713 case SCF_ERROR_PERMISSION_DENIED: 2714 ret = EPERM; 2715 goto out; 2716 2717 case SCF_ERROR_BACKEND_ACCESS: 2718 ret = EACCES; 2719 goto out; 2720 2721 case SCF_ERROR_BACKEND_READONLY: 2722 ret = EROFS; 2723 goto out; 2724 2725 case SCF_ERROR_NOT_SET: 2726 bad_error("scf_transaction_commit", scfe); 2727 } 2728 } 2729 2730 scf_transaction_reset_all(tx); 2731 2732 if (scf_pg_update(pg) == -1) { 2733 switch (scf_error()) { 2734 case SCF_ERROR_CONNECTION_BROKEN: 2735 default: 2736 ret = ECONNABORTED; 2737 goto out; 2738 2739 case SCF_ERROR_DELETED: 2740 ret = ECANCELED; 2741 goto out; 2742 2743 case SCF_ERROR_NOT_SET: 2744 bad_error("scf_pg_update", scf_error()); 2745 } 2746 } 2747 } 2748 2749out: 2750 scf_transaction_destroy(tx); 2751 scf_entry_destroy(e_time); 2752 scf_value_destroy(v_time); 2753 scf_entry_destroy(e_stat); 2754 scf_value_destroy(v_stat); 2755 scf_pg_destroy(pg); 2756 2757 return (ret); 2758} 2759 2760/* 2761 * Call dgraph_add_instance() for each instance in the repository. 2762 */ 2763void 2764libscf_populate_graph(scf_handle_t *h) 2765{ 2766 scf_scope_t *scope; 2767 scf_service_t *svc; 2768 scf_instance_t *inst; 2769 scf_iter_t *svc_iter; 2770 scf_iter_t *inst_iter; 2771 int ret; 2772 2773 scope = safe_scf_scope_create(h); 2774 svc = safe_scf_service_create(h); 2775 inst = safe_scf_instance_create(h); 2776 svc_iter = safe_scf_iter_create(h); 2777 inst_iter = safe_scf_iter_create(h); 2778 2779 if ((ret = scf_handle_get_local_scope(h, scope)) != 2780 SCF_SUCCESS) 2781 uu_die("retrieving local scope failed: %d\n", ret); 2782 2783 if (scf_iter_scope_services(svc_iter, scope) == -1) 2784 uu_die("walking local scope's services failed\n"); 2785 2786 while (scf_iter_next_service(svc_iter, svc) > 0) { 2787 if (scf_iter_service_instances(inst_iter, svc) == -1) 2788 uu_die("unable to walk service's instances"); 2789 2790 while (scf_iter_next_instance(inst_iter, inst) > 0) { 2791 char *fmri; 2792 2793 if (libscf_instance_get_fmri(inst, &fmri) == 0) { 2794 int err; 2795 2796 err = dgraph_add_instance(fmri, inst, B_TRUE); 2797 if (err != 0 && err != EEXIST) 2798 log_error(LOG_WARNING, 2799 "Failed to add %s (%s).\n", fmri, 2800 strerror(err)); 2801 startd_free(fmri, max_scf_fmri_size); 2802 } 2803 } 2804 } 2805 2806 scf_iter_destroy(inst_iter); 2807 scf_iter_destroy(svc_iter); 2808 scf_instance_destroy(inst); 2809 scf_service_destroy(svc); 2810 scf_scope_destroy(scope); 2811} 2812 2813/* 2814 * Monitors get handled differently since there can be multiple of them. 2815 * 2816 * Returns exec string on success. If method not defined, returns 2817 * LIBSCF_PGROUP_ABSENT; if exec property missing, returns 2818 * LIBSCF_PROPERTY_ABSENT. Returns LIBSCF_PROPERTY_ERROR on other failures. 2819 */ 2820char * 2821libscf_get_method(scf_handle_t *h, int type, restarter_inst_t *inst, 2822 scf_snapshot_t *snap, method_restart_t *restart_on, uint_t *cte_mask, 2823 uint8_t *need_sessionp, uint64_t *timeout, uint8_t *timeout_retry) 2824{ 2825 scf_instance_t *scf_inst = NULL; 2826 scf_propertygroup_t *pg = NULL, *pg_startd = NULL; 2827 scf_property_t *prop = NULL; 2828 const char *name; 2829 char *method = startd_alloc(max_scf_value_size); 2830 char *ig = startd_alloc(max_scf_value_size); 2831 char *restart = startd_alloc(max_scf_value_size); 2832 char *ret; 2833 int error = 0, r; 2834 2835 scf_inst = safe_scf_instance_create(h); 2836 pg = safe_scf_pg_create(h); 2837 pg_startd = safe_scf_pg_create(h); 2838 prop = safe_scf_property_create(h); 2839 2840 ret = NULL; 2841 2842 *restart_on = METHOD_RESTART_UNKNOWN; 2843 2844 switch (type) { 2845 case METHOD_START: 2846 name = "start"; 2847 break; 2848 case METHOD_STOP: 2849 name = "stop"; 2850 break; 2851 case METHOD_REFRESH: 2852 name = "refresh"; 2853 break; 2854 default: 2855 error = LIBSCF_PROPERTY_ERROR; 2856 goto get_method_cleanup; 2857 } 2858 2859 if (scf_handle_decode_fmri(h, inst->ri_i.i_fmri, NULL, NULL, scf_inst, 2860 NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) { 2861 log_error(LOG_WARNING, 2862 "%s: get_method decode instance FMRI failed: %s\n", 2863 inst->ri_i.i_fmri, scf_strerror(scf_error())); 2864 error = LIBSCF_PROPERTY_ERROR; 2865 goto get_method_cleanup; 2866 } 2867 2868 if (scf_instance_get_pg_composed(scf_inst, snap, name, pg) == -1) { 2869 if (scf_error() == SCF_ERROR_NOT_FOUND) 2870 error = LIBSCF_PGROUP_ABSENT; 2871 else 2872 error = LIBSCF_PROPERTY_ERROR; 2873 goto get_method_cleanup; 2874 } 2875 2876 if (scf_pg_get_property(pg, SCF_PROPERTY_EXEC, prop) == -1) { 2877 if (scf_error() == SCF_ERROR_NOT_FOUND) 2878 error = LIBSCF_PROPERTY_ABSENT; 2879 else 2880 error = LIBSCF_PROPERTY_ERROR; 2881 goto get_method_cleanup; 2882 } 2883 2884 error = libscf_read_single_astring(h, prop, &method); 2885 if (error != 0) { 2886 log_error(LOG_WARNING, 2887 "%s: get_method failed: can't get a single astring " 2888 "from %s/%s\n", inst->ri_i.i_fmri, name, SCF_PROPERTY_EXEC); 2889 goto get_method_cleanup; 2890 } 2891 2892 error = expand_method_tokens(method, scf_inst, snap, type, &ret); 2893 if (error != 0) { 2894 log_instance(inst, B_TRUE, "Could not expand method tokens " 2895 "in \"%s\": %s.", method, ret); 2896 error = LIBSCF_PROPERTY_ERROR; 2897 goto get_method_cleanup; 2898 } 2899 2900 r = get_count(pg, SCF_PROPERTY_TIMEOUT, timeout); 2901 switch (r) { 2902 case 0: 2903 break; 2904 2905 case ECONNABORTED: 2906 error = LIBSCF_PROPERTY_ERROR; 2907 goto get_method_cleanup; 2908 2909 case EINVAL: 2910 log_instance(inst, B_TRUE, "%s/%s is multi-valued or not of " 2911 "type count. Using infinite timeout.", name, 2912 SCF_PROPERTY_TIMEOUT); 2913 /* FALLTHROUGH */ 2914 case ECANCELED: 2915 case ENOENT: 2916 *timeout = METHOD_TIMEOUT_INFINITE; 2917 break; 2918 2919 case EACCES: 2920 default: 2921 bad_error("get_count", r); 2922 } 2923 2924 /* Both 0 and -1 (ugh) are considered infinite timeouts. */ 2925 if (*timeout == -1 || *timeout == 0) 2926 *timeout = METHOD_TIMEOUT_INFINITE; 2927 2928 if (scf_instance_get_pg_composed(scf_inst, snap, SCF_PG_STARTD, 2929 pg_startd) == -1) { 2930 switch (scf_error()) { 2931 case SCF_ERROR_CONNECTION_BROKEN: 2932 case SCF_ERROR_DELETED: 2933 error = LIBSCF_PROPERTY_ERROR; 2934 goto get_method_cleanup; 2935 2936 case SCF_ERROR_NOT_FOUND: 2937 *cte_mask = 0; 2938 break; 2939 2940 case SCF_ERROR_INVALID_ARGUMENT: 2941 case SCF_ERROR_HANDLE_MISMATCH: 2942 case SCF_ERROR_NOT_BOUND: 2943 case SCF_ERROR_NOT_SET: 2944 bad_error("scf_instance_get_pg_composed", scf_error()); 2945 } 2946 } else { 2947 if (scf_pg_get_property(pg_startd, SCF_PROPERTY_IGNORE, 2948 prop) == -1) { 2949 if (scf_error() == SCF_ERROR_NOT_FOUND) 2950 *cte_mask = 0; 2951 else { 2952 error = LIBSCF_PROPERTY_ERROR; 2953 goto get_method_cleanup; 2954 } 2955 } else { 2956 error = libscf_read_single_astring(h, prop, &ig); 2957 if (error != 0) { 2958 log_error(LOG_WARNING, 2959 "%s: get_method failed: can't get a single " 2960 "astring from %s/%s\n", inst->ri_i.i_fmri, 2961 name, SCF_PROPERTY_IGNORE); 2962 goto get_method_cleanup; 2963 } 2964 2965 if (strcmp(ig, "core") == 0) 2966 *cte_mask = CT_PR_EV_CORE; 2967 else if (strcmp(ig, "signal") == 0) 2968 *cte_mask = CT_PR_EV_SIGNAL; 2969 else if (strcmp(ig, "core,signal") == 0 || 2970 strcmp(ig, "signal,core") == 0) 2971 *cte_mask = CT_PR_EV_CORE | CT_PR_EV_SIGNAL; 2972 else 2973 *cte_mask = 0; 2974 } 2975 2976 r = get_boolean(pg_startd, SCF_PROPERTY_NEED_SESSION, 2977 need_sessionp); 2978 switch (r) { 2979 case 0: 2980 break; 2981 2982 case ECONNABORTED: 2983 error = LIBSCF_PROPERTY_ERROR; 2984 goto get_method_cleanup; 2985 2986 case ECANCELED: 2987 case ENOENT: 2988 case EINVAL: 2989 *need_sessionp = 0; 2990 break; 2991 2992 case EACCES: 2993 default: 2994 bad_error("get_boolean", r); 2995 } 2996 2997 /* 2998 * Determine whether service has overriden retry after 2999 * method timeout. Default to retry if no value is 3000 * specified. 3001 */ 3002 r = get_boolean(pg_startd, SCF_PROPERTY_TIMEOUT_RETRY, 3003 timeout_retry); 3004 switch (r) { 3005 case 0: 3006 break; 3007 3008 case ECONNABORTED: 3009 error = LIBSCF_PROPERTY_ERROR; 3010 goto get_method_cleanup; 3011 3012 case ECANCELED: 3013 case ENOENT: 3014 case EINVAL: 3015 *timeout_retry = 1; 3016 break; 3017 3018 case EACCES: 3019 default: 3020 bad_error("get_boolean", r); 3021 } 3022 } 3023 3024 if (type != METHOD_START) 3025 goto get_method_cleanup; 3026 3027 /* Only start methods need to honor the restart_on property. */ 3028 3029 if (scf_pg_get_property(pg, SCF_PROPERTY_RESTART_ON, prop) == -1) { 3030 if (scf_error() == SCF_ERROR_NOT_FOUND) 3031 *restart_on = METHOD_RESTART_ALL; 3032 else 3033 error = LIBSCF_PROPERTY_ERROR; 3034 goto get_method_cleanup; 3035 } 3036 3037 error = libscf_read_single_astring(h, prop, &restart); 3038 if (error != 0) { 3039 log_error(LOG_WARNING, 3040 "%s: get_method failed: can't get a single astring " 3041 "from %s/%s\n", inst->ri_i.i_fmri, name, 3042 SCF_PROPERTY_RESTART_ON); 3043 goto get_method_cleanup; 3044 } 3045 3046 if (strcmp(restart, "all") == 0) 3047 *restart_on = METHOD_RESTART_ALL; 3048 else if (strcmp(restart, "external_fault") == 0) 3049 *restart_on = METHOD_RESTART_EXTERNAL_FAULT; 3050 else if (strcmp(restart, "any_fault") == 0) 3051 *restart_on = METHOD_RESTART_ANY_FAULT; 3052 3053get_method_cleanup: 3054 startd_free(ig, max_scf_value_size); 3055 startd_free(method, max_scf_value_size); 3056 startd_free(restart, max_scf_value_size); 3057 3058 scf_instance_destroy(scf_inst); 3059 scf_pg_destroy(pg); 3060 scf_pg_destroy(pg_startd); 3061 scf_property_destroy(prop); 3062 3063 if (error != 0 && ret != NULL) { 3064 free(ret); 3065 ret = NULL; 3066 } 3067 3068 errno = error; 3069 return (ret); 3070} 3071 3072/* 3073 * Returns 1 if we've reached the fault threshold 3074 */ 3075int 3076update_fault_count(restarter_inst_t *inst, int type) 3077{ 3078 assert(type == FAULT_COUNT_INCR || type == FAULT_COUNT_RESET); 3079 3080 if (type == FAULT_COUNT_INCR) { 3081 inst->ri_i.i_fault_count++; 3082 log_framework(LOG_INFO, "%s: Increasing fault count to %d\n", 3083 inst->ri_i.i_fmri, inst->ri_i.i_fault_count); 3084 } 3085 if (type == FAULT_COUNT_RESET) 3086 inst->ri_i.i_fault_count = 0; 3087 3088 if (inst->ri_i.i_fault_count >= FAULT_THRESHOLD) 3089 return (1); 3090 3091 return (0); 3092} 3093 3094/* 3095 * int libscf_unset_action() 3096 * Delete any pending timestamps for the specified action which is 3097 * older than the supplied ts. 3098 * 3099 * Returns 0 on success, ECONNABORTED, EACCES, or EPERM on failure. 3100 */ 3101int 3102libscf_unset_action(scf_handle_t *h, scf_propertygroup_t *pg, 3103 admin_action_t a, hrtime_t ts) 3104{ 3105 scf_transaction_t *t; 3106 scf_transaction_entry_t *e; 3107 scf_property_t *prop; 3108 scf_value_t *val; 3109 hrtime_t rep_ts; 3110 int ret = 0, r; 3111 3112 t = safe_scf_transaction_create(h); 3113 e = safe_scf_entry_create(h); 3114 prop = safe_scf_property_create(h); 3115 val = safe_scf_value_create(h); 3116 3117 for (;;) { 3118 if (scf_pg_update(pg) == -1) { 3119 switch (scf_error()) { 3120 case SCF_ERROR_CONNECTION_BROKEN: 3121 default: 3122 ret = ECONNABORTED; 3123 goto unset_action_cleanup; 3124 3125 case SCF_ERROR_DELETED: 3126 goto unset_action_cleanup; 3127 3128 case SCF_ERROR_NOT_SET: 3129 assert(0); 3130 abort(); 3131 } 3132 } 3133 3134 if (scf_transaction_start(t, pg) == -1) { 3135 switch (scf_error()) { 3136 case SCF_ERROR_CONNECTION_BROKEN: 3137 default: 3138 ret = ECONNABORTED; 3139 goto unset_action_cleanup; 3140 3141 case SCF_ERROR_DELETED: 3142 goto unset_action_cleanup; 3143 3144 case SCF_ERROR_PERMISSION_DENIED: 3145 ret = EPERM; 3146 goto unset_action_cleanup; 3147 3148 case SCF_ERROR_BACKEND_ACCESS: 3149 case SCF_ERROR_BACKEND_READONLY: 3150 ret = EACCES; 3151 goto unset_action_cleanup; 3152 3153 case SCF_ERROR_IN_USE: 3154 case SCF_ERROR_HANDLE_MISMATCH: 3155 case SCF_ERROR_NOT_SET: 3156 assert(0); 3157 abort(); 3158 } 3159 } 3160 3161 /* Return failure only if the property hasn't been deleted. */ 3162 if (scf_pg_get_property(pg, admin_actions[a], prop) == -1) { 3163 switch (scf_error()) { 3164 case SCF_ERROR_CONNECTION_BROKEN: 3165 default: 3166 ret = ECONNABORTED; 3167 goto unset_action_cleanup; 3168 3169 case SCF_ERROR_DELETED: 3170 case SCF_ERROR_NOT_FOUND: 3171 goto unset_action_cleanup; 3172 3173 case SCF_ERROR_HANDLE_MISMATCH: 3174 case SCF_ERROR_INVALID_ARGUMENT: 3175 case SCF_ERROR_NOT_SET: 3176 assert(0); 3177 abort(); 3178 } 3179 } 3180 3181 if (scf_property_get_value(prop, val) == -1) { 3182 switch (scf_error()) { 3183 case SCF_ERROR_CONNECTION_BROKEN: 3184 default: 3185 ret = ECONNABORTED; 3186 goto unset_action_cleanup; 3187 3188 case SCF_ERROR_DELETED: 3189 case SCF_ERROR_NOT_FOUND: 3190 goto unset_action_cleanup; 3191 3192 case SCF_ERROR_CONSTRAINT_VIOLATED: 3193 /* 3194 * More than one value was associated with 3195 * this property -- this is incorrect. Take 3196 * the opportunity to clean up and clear the 3197 * entire property. 3198 */ 3199 rep_ts = ts; 3200 break; 3201 3202 case SCF_ERROR_PERMISSION_DENIED: 3203 case SCF_ERROR_NOT_SET: 3204 assert(0); 3205 abort(); 3206 } 3207 } else if (scf_value_get_integer(val, &rep_ts) == -1) { 3208 assert(scf_error() == SCF_ERROR_TYPE_MISMATCH); 3209 rep_ts = 0; 3210 } 3211 3212 /* Repository ts is more current. Don't clear the action. */ 3213 if (rep_ts > ts) 3214 goto unset_action_cleanup; 3215 3216 r = scf_transaction_property_change_type(t, e, 3217 admin_actions[a], SCF_TYPE_INTEGER); 3218 assert(r == 0); 3219 3220 r = scf_transaction_commit(t); 3221 if (r == 1) 3222 break; 3223 3224 if (r != 0) { 3225 switch (scf_error()) { 3226 case SCF_ERROR_CONNECTION_BROKEN: 3227 default: 3228 ret = ECONNABORTED; 3229 goto unset_action_cleanup; 3230 3231 case SCF_ERROR_DELETED: 3232 break; 3233 3234 case SCF_ERROR_PERMISSION_DENIED: 3235 ret = EPERM; 3236 goto unset_action_cleanup; 3237 3238 case SCF_ERROR_BACKEND_ACCESS: 3239 case SCF_ERROR_BACKEND_READONLY: 3240 ret = EACCES; 3241 goto unset_action_cleanup; 3242 3243 case SCF_ERROR_INVALID_ARGUMENT: 3244 case SCF_ERROR_NOT_SET: 3245 assert(0); 3246 abort(); 3247 } 3248 } 3249 3250 scf_transaction_reset(t); 3251 } 3252 3253unset_action_cleanup: 3254 scf_transaction_destroy(t); 3255 scf_entry_destroy(e); 3256 scf_property_destroy(prop); 3257 scf_value_destroy(val); 3258 3259 return (ret); 3260} 3261 3262/* 3263 * Decorates & binds hndl. hndl must be unbound. Returns 3264 * 0 - success 3265 * -1 - repository server is not running 3266 * -1 - repository server is out of resources 3267 */ 3268static int 3269handle_decorate_and_bind(scf_handle_t *hndl) 3270{ 3271 scf_value_t *door_dec_value; 3272 3273 door_dec_value = safe_scf_value_create(hndl); 3274 3275 /* 3276 * Decorate if alternate door path set. 3277 */ 3278 if (st->st_door_path) { 3279 if (scf_value_set_astring(door_dec_value, st->st_door_path) != 3280 0) 3281 uu_die("$STARTD_ALT_DOOR is too long.\n"); 3282 3283 if (scf_handle_decorate(hndl, "door_path", door_dec_value) != 0) 3284 bad_error("scf_handle_decorate", scf_error()); 3285 } 3286 3287 scf_value_destroy(door_dec_value); 3288 3289 if (scf_handle_bind(hndl) == 0) 3290 return (0); 3291 3292 switch (scf_error()) { 3293 case SCF_ERROR_NO_SERVER: 3294 case SCF_ERROR_NO_RESOURCES: 3295 return (-1); 3296 3297 case SCF_ERROR_INVALID_ARGUMENT: 3298 case SCF_ERROR_IN_USE: 3299 default: 3300 bad_error("scf_handle_bind", scf_error()); 3301 /* NOTREACHED */ 3302 } 3303} 3304 3305scf_handle_t * 3306libscf_handle_create_bound(scf_version_t v) 3307{ 3308 scf_handle_t *hndl = scf_handle_create(v); 3309 3310 if (hndl == NULL) 3311 return (hndl); 3312 3313 if (handle_decorate_and_bind(hndl) == 0) 3314 return (hndl); 3315 3316 scf_handle_destroy(hndl); 3317 return (NULL); 3318} 3319 3320void 3321libscf_handle_rebind(scf_handle_t *h) 3322{ 3323 (void) scf_handle_unbind(h); 3324 3325 MUTEX_LOCK(&st->st_configd_live_lock); 3326 3327 /* 3328 * Try to rebind the handle before sleeping in case the server isn't 3329 * really dead. 3330 */ 3331 while (handle_decorate_and_bind(h) != 0) 3332 (void) pthread_cond_wait(&st->st_configd_live_cv, 3333 &st->st_configd_live_lock); 3334 3335 MUTEX_UNLOCK(&st->st_configd_live_lock); 3336} 3337 3338/* 3339 * Create a handle and try to bind it until it succeeds. Always returns 3340 * a bound handle. 3341 */ 3342scf_handle_t * 3343libscf_handle_create_bound_loop() 3344{ 3345 scf_handle_t *h; 3346 3347 while ((h = scf_handle_create(SCF_VERSION)) == NULL) { 3348 /* This should have been caught earlier. */ 3349 assert(scf_error() != SCF_ERROR_VERSION_MISMATCH); 3350 (void) sleep(2); 3351 } 3352 3353 if (handle_decorate_and_bind(h) != 0) 3354 libscf_handle_rebind(h); 3355 3356 return (h); 3357} 3358 3359/* 3360 * Call cb for each dependency property group of inst. cb is invoked with 3361 * a pointer to the scf_propertygroup_t and arg. If the repository connection 3362 * is broken, returns ECONNABORTED. If inst is deleted, returns ECANCELED. 3363 * If cb returns non-zero, the walk is stopped and EINTR is returned. 3364 * Otherwise returns 0. 3365 */ 3366int 3367walk_dependency_pgs(scf_instance_t *inst, callback_t cb, void *arg) 3368{ 3369 scf_handle_t *h; 3370 scf_snapshot_t *snap; 3371 scf_iter_t *iter; 3372 scf_propertygroup_t *pg; 3373 int r; 3374 3375 h = scf_instance_handle(inst); 3376 3377 iter = safe_scf_iter_create(h); 3378 pg = safe_scf_pg_create(h); 3379 3380 snap = libscf_get_running_snapshot(inst); 3381 3382 if (scf_iter_instance_pgs_typed_composed(iter, inst, snap, 3383 SCF_GROUP_DEPENDENCY) != 0) { 3384 scf_snapshot_destroy(snap); 3385 scf_pg_destroy(pg); 3386 scf_iter_destroy(iter); 3387 switch (scf_error()) { 3388 case SCF_ERROR_CONNECTION_BROKEN: 3389 default: 3390 return (ECONNABORTED); 3391 3392 case SCF_ERROR_DELETED: 3393 return (ECANCELED); 3394 3395 case SCF_ERROR_HANDLE_MISMATCH: 3396 case SCF_ERROR_INVALID_ARGUMENT: 3397 case SCF_ERROR_NOT_SET: 3398 assert(0); 3399 abort(); 3400 } 3401 } 3402 3403 for (;;) { 3404 r = scf_iter_next_pg(iter, pg); 3405 if (r == 0) 3406 break; 3407 if (r == -1) { 3408 scf_snapshot_destroy(snap); 3409 scf_pg_destroy(pg); 3410 scf_iter_destroy(iter); 3411 3412 switch (scf_error()) { 3413 case SCF_ERROR_CONNECTION_BROKEN: 3414 return (ECONNABORTED); 3415 3416 case SCF_ERROR_DELETED: 3417 return (ECANCELED); 3418 3419 case SCF_ERROR_NOT_SET: 3420 case SCF_ERROR_INVALID_ARGUMENT: 3421 case SCF_ERROR_NOT_BOUND: 3422 case SCF_ERROR_HANDLE_MISMATCH: 3423 default: 3424 bad_error("scf_iter_next_pg", scf_error()); 3425 } 3426 } 3427 3428 r = cb(pg, arg); 3429 3430 if (r != 0) 3431 break; 3432 } 3433 3434 scf_snapshot_destroy(snap); 3435 scf_pg_destroy(pg); 3436 scf_iter_destroy(iter); 3437 3438 return (r == 0 ? 0 : EINTR); 3439} 3440 3441/* 3442 * Call cb for each of the string values of prop. cb is invoked with 3443 * a pointer to the string and arg. If the connection to the repository is 3444 * broken, ECONNABORTED is returned. If the property is deleted, ECANCELED is 3445 * returned. If the property does not have astring type, EINVAL is returned. 3446 * If cb returns non-zero, the walk is stopped and EINTR is returned. 3447 * Otherwise 0 is returned. 3448 */ 3449int 3450walk_property_astrings(scf_property_t *prop, callback_t cb, void *arg) 3451{ 3452 scf_handle_t *h; 3453 scf_value_t *val; 3454 scf_iter_t *iter; 3455 char *buf; 3456 int r; 3457 ssize_t sz; 3458 3459 if (scf_property_is_type(prop, SCF_TYPE_ASTRING) != 0) { 3460 switch (scf_error()) { 3461 case SCF_ERROR_CONNECTION_BROKEN: 3462 default: 3463 return (ECONNABORTED); 3464 3465 case SCF_ERROR_DELETED: 3466 return (ECANCELED); 3467 3468 case SCF_ERROR_TYPE_MISMATCH: 3469 return (EINVAL); 3470 3471 case SCF_ERROR_NOT_SET: 3472 assert(0); 3473 abort(); 3474 } 3475 } 3476 3477 h = scf_property_handle(prop); 3478 3479 val = safe_scf_value_create(h); 3480 iter = safe_scf_iter_create(h); 3481 3482 if (scf_iter_property_values(iter, prop) != 0) { 3483 scf_iter_destroy(iter); 3484 scf_value_destroy(val); 3485 switch (scf_error()) { 3486 case SCF_ERROR_CONNECTION_BROKEN: 3487 default: 3488 return (ECONNABORTED); 3489 3490 case SCF_ERROR_DELETED: 3491 return (ECANCELED); 3492 3493 case SCF_ERROR_HANDLE_MISMATCH: 3494 case SCF_ERROR_NOT_SET: 3495 assert(0); 3496 abort(); 3497 } 3498 } 3499 3500 buf = startd_alloc(max_scf_value_size); 3501 3502 for (;;) { 3503 r = scf_iter_next_value(iter, val); 3504 if (r < 0) { 3505 startd_free(buf, max_scf_value_size); 3506 scf_iter_destroy(iter); 3507 scf_value_destroy(val); 3508 3509 switch (scf_error()) { 3510 case SCF_ERROR_CONNECTION_BROKEN: 3511 return (ECONNABORTED); 3512 3513 case SCF_ERROR_DELETED: 3514 return (ECANCELED); 3515 3516 case SCF_ERROR_NOT_SET: 3517 case SCF_ERROR_INVALID_ARGUMENT: 3518 case SCF_ERROR_NOT_BOUND: 3519 case SCF_ERROR_HANDLE_MISMATCH: 3520 case SCF_ERROR_PERMISSION_DENIED: 3521 default: 3522 bad_error("scf_iter_next_value", scf_error()); 3523 } 3524 } 3525 if (r == 0) 3526 break; 3527 3528 sz = scf_value_get_astring(val, buf, max_scf_value_size); 3529 assert(sz >= 0); 3530 3531 r = cb(buf, arg); 3532 3533 if (r != 0) 3534 break; 3535 } 3536 3537 startd_free(buf, max_scf_value_size); 3538 scf_value_destroy(val); 3539 scf_iter_destroy(iter); 3540 3541 return (r == 0 ? 0 : EINTR); 3542} 3543 3544/* 3545 * Returns 0 or ECONNABORTED. 3546 */ 3547int 3548libscf_create_self(scf_handle_t *h) 3549{ 3550 scf_scope_t *scope; 3551 scf_service_t *svc; 3552 scf_instance_t *inst; 3553 instance_data_t idata; 3554 int ret = 0, r; 3555 ctid_t ctid; 3556 uint64_t uint64; 3557 uint_t count = 0, msecs = ALLOC_DELAY; 3558 3559 const char * const startd_svc = "system/svc/restarter"; 3560 const char * const startd_inst = "default"; 3561 3562 /* If SCF_SERVICE_STARTD changes, our strings must change, too. */ 3563 assert(strcmp(SCF_SERVICE_STARTD, 3564 "svc:/system/svc/restarter:default") == 0); 3565 3566 scope = safe_scf_scope_create(h); 3567 svc = safe_scf_service_create(h); 3568 inst = safe_scf_instance_create(h); 3569 3570 if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, scope) != 0) { 3571 assert(scf_error() == SCF_ERROR_CONNECTION_BROKEN); 3572 ret = ECONNABORTED; 3573 goto out; 3574 } 3575 3576get_svc: 3577 if (scf_scope_get_service(scope, startd_svc, svc) != 0) { 3578 switch (scf_error()) { 3579 case SCF_ERROR_CONNECTION_BROKEN: 3580 case SCF_ERROR_DELETED: 3581 default: 3582 ret = ECONNABORTED; 3583 goto out; 3584 3585 case SCF_ERROR_NOT_FOUND: 3586 break; 3587 3588 case SCF_ERROR_HANDLE_MISMATCH: 3589 case SCF_ERROR_INVALID_ARGUMENT: 3590 case SCF_ERROR_NOT_SET: 3591 bad_error("scf_scope_get_service", scf_error()); 3592 } 3593 3594add_svc: 3595 if (scf_scope_add_service(scope, startd_svc, svc) != 0) { 3596 switch (scf_error()) { 3597 case SCF_ERROR_CONNECTION_BROKEN: 3598 case SCF_ERROR_DELETED: 3599 default: 3600 ret = ECONNABORTED; 3601 goto out; 3602 3603 case SCF_ERROR_EXISTS: 3604 goto get_svc; 3605 3606 case SCF_ERROR_PERMISSION_DENIED: 3607 case SCF_ERROR_BACKEND_ACCESS: 3608 case SCF_ERROR_BACKEND_READONLY: 3609 uu_warn("Could not create %s: %s\n", 3610 SCF_SERVICE_STARTD, 3611 scf_strerror(scf_error())); 3612 goto out; 3613 3614 case SCF_ERROR_HANDLE_MISMATCH: 3615 case SCF_ERROR_INVALID_ARGUMENT: 3616 case SCF_ERROR_NOT_SET: 3617 bad_error("scf_scope_add_service", scf_error()); 3618 } 3619 } 3620 } 3621 3622 if (scf_service_get_instance(svc, startd_inst, NULL) == 0) 3623 goto out; 3624 3625 switch (scf_error()) { 3626 case SCF_ERROR_CONNECTION_BROKEN: 3627 default: 3628 ret = ECONNABORTED; 3629 goto out; 3630 3631 case SCF_ERROR_NOT_FOUND: 3632 break; 3633 3634 case SCF_ERROR_DELETED: 3635 goto add_svc; 3636 3637 case SCF_ERROR_HANDLE_MISMATCH: 3638 case SCF_ERROR_INVALID_ARGUMENT: 3639 case SCF_ERROR_NOT_SET: 3640 bad_error("scf_service_get_instance", scf_error()); 3641 } 3642 3643add_inst: 3644 if (scf_service_add_instance(svc, startd_inst, inst) != 0) { 3645 switch (scf_error()) { 3646 case SCF_ERROR_CONNECTION_BROKEN: 3647 default: 3648 ret = ECONNABORTED; 3649 goto out; 3650 3651 case SCF_ERROR_EXISTS: 3652 break; 3653 3654 case SCF_ERROR_PERMISSION_DENIED: 3655 case SCF_ERROR_BACKEND_ACCESS: 3656 uu_die("Could not create %s: %s\n", SCF_SERVICE_STARTD, 3657 scf_strerror(scf_error())); 3658 /* NOTREACHED */ 3659 3660 case SCF_ERROR_BACKEND_READONLY: 3661 log_error(LOG_NOTICE, 3662 "Could not create %s: backend readonly.\n", 3663 SCF_SERVICE_STARTD); 3664 goto out; 3665 3666 case SCF_ERROR_DELETED: 3667 goto add_svc; 3668 3669 case SCF_ERROR_HANDLE_MISMATCH: 3670 case SCF_ERROR_INVALID_ARGUMENT: 3671 case SCF_ERROR_NOT_SET: 3672 bad_error("scf_service_add_instance", scf_error()); 3673 } 3674 } 3675 3676 /* Set start time. */ 3677 idata.i_fmri = SCF_SERVICE_STARTD; 3678 idata.i_state = RESTARTER_STATE_NONE; 3679 idata.i_next_state = RESTARTER_STATE_NONE; 3680set_state: 3681 switch (r = _restarter_commit_states(h, &idata, RESTARTER_STATE_ONLINE, 3682 RESTARTER_STATE_NONE, NULL)) { 3683 case 0: 3684 break; 3685 3686 case ENOMEM: 3687 ++count; 3688 if (count < ALLOC_RETRY) { 3689 (void) poll(NULL, 0, msecs); 3690 msecs *= ALLOC_DELAY_MULT; 3691 goto set_state; 3692 } 3693 3694 uu_die("Insufficient memory.\n"); 3695 /* NOTREACHED */ 3696 3697 case ECONNABORTED: 3698 ret = ECONNABORTED; 3699 goto out; 3700 3701 case ENOENT: 3702 goto add_inst; 3703 3704 case EPERM: 3705 case EACCES: 3706 case EROFS: 3707 uu_warn("Could not timestamp %s: %s\n", idata.i_fmri, 3708 strerror(r)); 3709 break; 3710 3711 case EINVAL: 3712 default: 3713 bad_error("_restarter_commit_states", r); 3714 } 3715 3716 /* Set general/enabled. */ 3717 ret = libscf_inst_set_boolean_prop(inst, SCF_PG_GENERAL, 3718 SCF_PG_GENERAL_TYPE, SCF_PG_GENERAL_FLAGS, SCF_PROPERTY_ENABLED, 1); 3719 switch (ret) { 3720 case 0: 3721 case ECONNABORTED: 3722 case EPERM: 3723 case EACCES: 3724 case EROFS: 3725 break; 3726 3727 case ECANCELED: 3728 goto add_inst; 3729 3730 default: 3731 bad_error("libscf_inst_set_boolean_prop", ret); 3732 } 3733 3734 ret = libscf_write_start_pid(inst, getpid()); 3735 switch (ret) { 3736 case 0: 3737 case ECONNABORTED: 3738 case EPERM: 3739 case EACCES: 3740 case EROFS: 3741 break; 3742 3743 case ECANCELED: 3744 goto add_inst; 3745 3746 default: 3747 bad_error("libscf_write_start_pid", ret); 3748 } 3749 3750 ctid = proc_get_ctid(); 3751 if (ctid > 0) { 3752 3753 uint64 = (uint64_t)ctid; 3754 ret = libscf_inst_set_count_prop(inst, 3755 SCF_PG_RESTARTER, SCF_PG_RESTARTER_TYPE, 3756 SCF_PG_RESTARTER_FLAGS, SCF_PROPERTY_CONTRACT, uint64); 3757 3758 switch (ret) { 3759 case 0: 3760 case ECONNABORTED: 3761 case EPERM: 3762 case EACCES: 3763 case EROFS: 3764 break; 3765 3766 case ECANCELED: 3767 goto add_inst; 3768 3769 default: 3770 bad_error("libscf_inst_set_count_prop", ret); 3771 } 3772 } 3773 3774 ret = libscf_note_method_log(inst, LOG_PREFIX_EARLY, 3775 STARTD_DEFAULT_LOG); 3776 if (ret == 0) { 3777 ret = libscf_note_method_log(inst, LOG_PREFIX_NORMAL, 3778 STARTD_DEFAULT_LOG); 3779 } 3780 3781 switch (ret) { 3782 case ECONNABORTED: 3783 case EPERM: 3784 case EACCES: 3785 case EROFS: 3786 case EAGAIN: 3787 break; 3788 3789 case ECANCELED: 3790 goto add_inst; 3791 3792 default: 3793 bad_error("libscf_note_method_log", ret); 3794 } 3795 3796out: 3797 scf_instance_destroy(inst); 3798 scf_service_destroy(svc); 3799 scf_scope_destroy(scope); 3800 return (ret); 3801} 3802 3803/* 3804 * Returns 3805 * 0 - success 3806 * ENOENT - SCF_SERVICE_STARTD does not exist in repository 3807 * EPERM 3808 * EACCES 3809 * EROFS 3810 */ 3811int 3812libscf_set_reconfig(int set) 3813{ 3814 scf_handle_t *h; 3815 scf_instance_t *inst; 3816 scf_propertygroup_t *pg; 3817 int ret = 0; 3818 3819 h = libscf_handle_create_bound_loop(); 3820 inst = safe_scf_instance_create(h); 3821 pg = safe_scf_pg_create(h); 3822 3823again: 3824 if (scf_handle_decode_fmri(h, SCF_SERVICE_STARTD, NULL, NULL, 3825 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) { 3826 switch (scf_error()) { 3827 case SCF_ERROR_CONNECTION_BROKEN: 3828 default: 3829 libscf_handle_rebind(h); 3830 goto again; 3831 3832 case SCF_ERROR_NOT_FOUND: 3833 ret = ENOENT; 3834 goto reconfig_out; 3835 3836 case SCF_ERROR_HANDLE_MISMATCH: 3837 case SCF_ERROR_INVALID_ARGUMENT: 3838 case SCF_ERROR_CONSTRAINT_VIOLATED: 3839 bad_error("scf_handle_decode_fmri", scf_error()); 3840 } 3841 } 3842 3843 ret = libscf_inst_set_boolean_prop(inst, "system", SCF_GROUP_FRAMEWORK, 3844 SCF_PG_FLAG_NONPERSISTENT, "reconfigure", set); 3845 switch (ret) { 3846 case 0: 3847 case EPERM: 3848 case EACCES: 3849 case EROFS: 3850 break; 3851 3852 case ECONNABORTED: 3853 libscf_handle_rebind(h); 3854 goto again; 3855 3856 case ECANCELED: 3857 ret = ENOENT; 3858 break; 3859 3860 default: 3861 bad_error("libscf_inst_set_boolean_prop", ret); 3862 } 3863 3864reconfig_out: 3865 scf_pg_destroy(pg); 3866 scf_instance_destroy(inst); 3867 scf_handle_destroy(h); 3868 return (ret); 3869} 3870 3871/* 3872 * Set inst->ri_m_inst to the scf instance for inst. If it has been deleted, 3873 * set inst->ri_mi_deleted to true. If the repository connection is broken, it 3874 * is rebound with libscf_handle_rebound(). 3875 */ 3876void 3877libscf_reget_instance(restarter_inst_t *inst) 3878{ 3879 scf_handle_t *h; 3880 int r; 3881 3882 h = scf_instance_handle(inst->ri_m_inst); 3883 3884again: 3885 r = libscf_lookup_instance(inst->ri_i.i_fmri, inst->ri_m_inst); 3886 switch (r) { 3887 case 0: 3888 case ENOENT: 3889 inst->ri_mi_deleted = (r == ENOENT); 3890 return; 3891 3892 case ECONNABORTED: 3893 libscf_handle_rebind(h); 3894 goto again; 3895 3896 case EINVAL: 3897 case ENOTSUP: 3898 default: 3899 bad_error("libscf_lookup_instance", r); 3900 } 3901} 3902