/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#include "libscf_impl.h"
#include <assert.h>
#include <libuutil.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <libgen.h>
#include <assert.h>
#include "midlevel_impl.h"
#include "lowlevel_impl.h"
#ifndef NDEBUG
uu_warn("%s:%d: %s failed with unexpected error %d. Aborting.\n", \
abort(); \
}
#else
#endif
/* Path to speedy files area must end with a slash */
void
{
return;
}
/*
* Given a base service FMRI and the names of a property group and property,
* assemble_fmri() merges them into a property FMRI. Note that if the base
* FMRI is NULL, assemble_fmri() gets the base FMRI from scf_myname().
*/
static char *
const char *prop)
{
char *fmri_buf;
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
return (NULL);
}
else
return (NULL);
} else {
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
return (NULL);
}
} else {
}
else
return (fmri_buf);
}
/*
* Given a property, this function allocates and fills an scf_simple_prop_t
* with the data it contains.
*/
static scf_simple_prop_t *
scf_handle_t *h)
{
int iterret, i;
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
else
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
goto error3;
goto error3;
goto error3;
}
goto error1;
numvals++) {
goto error1;
}
case SCF_TYPE_BOOLEAN:
if (scf_value_get_boolean(val,
goto error1;
break;
case SCF_TYPE_COUNT:
if (scf_value_get_count(val,
goto error1;
break;
case SCF_TYPE_INTEGER:
if (scf_value_get_integer(val,
goto error1;
break;
case SCF_TYPE_TIME:
if (scf_value_get_time(val,
goto error1;
break;
case SCF_TYPE_ASTRING:
-1)
goto error1;
NULL) {
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto error1;
}
if (scf_value_get_astring(val,
goto error1;
}
break;
case SCF_TYPE_USTRING:
case SCF_TYPE_HOST:
case SCF_TYPE_HOSTNAME:
case SCF_TYPE_NET_ADDR:
case SCF_TYPE_NET_ADDR_V4:
case SCF_TYPE_NET_ADDR_V6:
case SCF_TYPE_URI:
case SCF_TYPE_FMRI:
-1)
goto error1;
NULL) {
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto error1;
}
if (scf_value_get_ustring(val,
goto error1;
}
break;
case SCF_TYPE_OPAQUE:
goto error1;
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto error1;
}
if (scf_value_get_opaque(val,
goto error1;
}
break;
default:
(void) scf_set_error(SCF_ERROR_INTERNAL);
goto error1;
}
}
if (iterret == -1) {
if (err != SCF_ERROR_CONNECTION_BROKEN &&
(void) scf_set_error(SCF_ERROR_INTERNAL);
goto error1;
}
(void) scf_value_destroy(val);
return (ret);
/*
* Exit point for a successful call. Below this line are exit points
* for failures at various stages during the function.
*/
goto error2;
case SCF_TYPE_ASTRING:
case SCF_TYPE_USTRING:
case SCF_TYPE_HOST:
case SCF_TYPE_HOSTNAME:
case SCF_TYPE_NET_ADDR:
case SCF_TYPE_NET_ADDR_V4:
case SCF_TYPE_NET_ADDR_V6:
case SCF_TYPE_URI:
case SCF_TYPE_FMRI: {
for (i = 0; i < numvals; i++) {
}
break;
}
case SCF_TYPE_OPAQUE: {
for (i = 0; i < numvals; i++) {
}
break;
}
default:
break;
}
(void) scf_value_destroy(val);
return (NULL);
}
/*
* insert_app_props iterates over a property iterator, getting all the
* properties from a property group, and adding or overwriting them into
* a simple_app_props_t. This is used by scf_simple_app_props_get to provide
* insert_app_props iterates over a single property group.
*/
static int
scf_handle_t *h)
{
int propiter_ret;
if (scf_error() == SCF_ERROR_NOT_SET)
(void) scf_set_error(SCF_ERROR_INTERNAL);
return (-1);
}
found = 0;
found = 1;
return (-1);
else
} else {
}
}
if (!found) {
NULL)
return (-1);
else
}
}
if (propiter_ret == -1) {
if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
(void) scf_set_error(SCF_ERROR_INTERNAL);
return (-1);
}
return (0);
}
/*
* Sets up e in tx to set pname's values. Returns 0 on success or -1 on
* failure, with scf_error() set to
* SCF_ERROR_HANDLE_MISMATCH - tx & e are derived from different handles
* SCF_ERROR_INVALID_ARGUMENT - pname or ty are invalid
* SCF_ERROR_NOT_BOUND - handle is not bound
* SCF_ERROR_CONNECTION_BROKEN - connection was broken
* SCF_ERROR_NOT_SET - tx has not been started
* SCF_ERROR_DELETED - the pg tx was started on was deleted
*/
static int
{
for (;;) {
return (0);
switch (scf_error()) {
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_DELETED:
default:
return (-1);
case SCF_ERROR_NOT_FOUND:
break;
}
return (0);
switch (scf_error()) {
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_DELETED:
default:
return (-1);
case SCF_ERROR_EXISTS:
break;
}
}
}
static int
{
scf_value_t *v = NULL;
scf_handle_t *h = NULL;
return (-1);
(v = scf_value_create(h)) == NULL)
goto out;
scf_property_get_value(eprop, v) ||
scf_value_get_boolean(v, &enabled))
goto out;
out:
return (ret);
}
/*
* instance and the desired state for the enabled bit in the instance's
* named property group. If the group doesn't exist, it's created with the
* given flags. Called by smf_{dis,en}able_instance().
*/
static int
{
scf_value_t *v = NULL;
scf_handle_t *h = NULL;
int committed;
uint8_t b;
return (-1);
(v = scf_value_create(h)) == NULL ||
goto out;
if (scf_error() != SCF_ERROR_NOT_FOUND)
goto out;
if (scf_error() != SCF_ERROR_EXISTS)
goto out;
goto general_pg_get;
}
}
get:
if (scf_error() != SCF_ERROR_NOT_FOUND)
goto out;
if (scf_error() != SCF_ERROR_EXISTS)
goto out;
goto get;
}
}
}
if (scf_error() != SCF_ERROR_NOT_FOUND)
goto out;
else
goto set;
}
/*
* If it's already set the way we want, forgo the transaction.
*/
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
/* Misconfigured, so set anyway. */
goto set;
default:
goto out;
}
}
if (scf_value_get_boolean(v, &b) == -1) {
if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
goto out;
goto set;
}
if (b == desired) {
ret = 0;
goto out;
}
set:
do {
goto out;
SCF_TYPE_BOOLEAN) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
default:
goto out;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
bad_error("transaction_property_set",
scf_error());
}
}
goto out;
if (committed == -1)
goto out;
if (committed == 0) { /* out-of-sync */
goto out;
}
} while (committed == 0);
ret = 0;
out:
return (ret);
}
static int
{
scf_handle_t *h = NULL;
int committed;
return (-1);
goto out;
goto error;
do {
SCF_PROPERTY_ENABLED) == -1 ||
goto error;
goto error;
} while (committed == 0);
ret = 0;
goto out;
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_NOT_FOUND:
/* success */
ret = 0;
}
out:
return (ret);
}
/*
* Returns 0 on success or -1 on failure. On failure leaves scf_error() set to
* SCF_ERROR_HANDLE_DESTROYED - inst's handle has been destroyed
* SCF_ERROR_NOT_BOUND - inst's handle is not bound
* SCF_ERROR_CONNECTION_BROKEN - the repository connection was broken
* SCF_ERROR_NOT_SET - inst is not set
* SCF_ERROR_DELETED - inst was deleted
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_BACKEND_READONLY
*/
static int
{
scf_handle_t *h;
scf_value_t *v = NULL;
int64_t t;
(v = scf_value_create(h)) == NULL ||
goto out;
get:
switch (scf_error()) {
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_DELETED:
default:
goto out;
case SCF_ERROR_NOT_FOUND:
break;
}
/* Try creating the restarter_actions property group. */
add:
switch (scf_error()) {
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_DELETED:
case SCF_ERROR_BACKEND_ACCESS:
default:
goto out;
case SCF_ERROR_EXISTS:
goto get;
}
}
}
for (;;) {
switch (scf_error()) {
default:
goto out;
case SCF_ERROR_DELETED:
goto add;
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
}
} else if (scf_property_get_value(prop, v) != 0) {
switch (scf_error()) {
default:
goto out;
case SCF_ERROR_DELETED:
goto add;
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
bad_error("scf_property_get_value",
scf_error());
}
} else if (scf_value_get_integer(v, &t) != 0) {
} else if (t > timestamp) {
break;
}
switch (scf_error()) {
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_BACKEND_ACCESS:
default:
goto out;
case SCF_ERROR_DELETED:
goto add;
case SCF_ERROR_NOT_SET:
case SCF_ERROR_IN_USE:
}
}
SCF_TYPE_INTEGER) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_DELETED:
default:
goto out;
case SCF_ERROR_NOT_SET:
bad_error("transaction_property_set",
scf_error());
}
}
if (trans == 1)
break;
if (trans != 0) {
switch (scf_error()) {
case SCF_ERROR_BACKEND_ACCESS:
default:
goto out;
case SCF_ERROR_DELETED:
goto add;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
bad_error("scf_transaction_commit",
scf_error());
}
}
switch (scf_error()) {
default:
goto out;
case SCF_ERROR_DELETED:
goto add;
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
}
}
}
ret = 0;
out:
return (ret);
}
static int
{
scf_handle_t *h;
if (h == NULL)
return (-1);
inst = scf_instance_create(h);
NULL, SCF_DECODE_FMRI_EXACT) == 0) {
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
} else {
switch (scf_error()) {
(void) scf_set_error(
break;
case SCF_ERROR_DELETED:
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
break;
}
}
}
return (ret);
}
/*
* get_inst_state() gets the state string from an instance, and returns
* the SCF_STATE_* constant that coincides with the instance's current state.
*/
static int
{
goto out;
/* Pull the state property from the instance */
if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
(void) scf_set_error(SCF_ERROR_INTERNAL);
goto out;
}
(void) scf_set_error(SCF_ERROR_INTERNAL);
goto out;
}
}
out:
(void) scf_value_destroy(val);
return (ret);
}
/*
* Sets an instance to be enabled or disabled after reboot, using the
* temporary (overriding) general_ovr property group to reflect the
* present state, if it is different.
*/
static int
{
int enabled;
int persistent;
if (scf_error() != SCF_ERROR_NOT_FOUND)
goto out;
}
if (persistent != desired) {
/*
* Temporarily store the present enabled state.
*/
goto out;
}
}
if (persistent != desired)
goto out;
else
ret = 0;
out:
return (ret);
}
static int
{
scf_handle_t *h;
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
return (ret);
}
return (ret);
return (ret);
}
SCF_DECODE_FMRI_EXACT) == -1) {
if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
goto out;
}
if (flags & SMF_AT_NEXT_BOOT) {
} else {
goto out;
/*
* Make the persistent value effective by deleting the
* temporary one.
*/
if (flags & SMF_TEMPORARY)
ret = 0;
else
}
out:
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
return (ret);
}
/*
* Create and return a pg from the instance associated with the given handle.
* This function is only called in scf_transaction_setup and
* scf_transaction_restart where the h->rh_instance pointer is properly filled
* in by scf_general_setup_pg().
*/
static scf_propertygroup_t *
{
char *pg_name;
return (NULL);
}
if (scf_error() == SCF_ERROR_NOT_SET) {
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
}
return (NULL);
}
if (scf_error() == SCF_ERROR_NOT_SET) {
(void) scf_set_error(SCF_ERROR_INTERNAL);
}
return (NULL);
}
/* Get pg from instance */
return (NULL);
}
return (ret_pg);
}
int
{
}
int
{
}
int
{
}
int
{
scf_handle_t *h = scf_service_handle(s);
scf_instance_t *i = scf_instance_create(h);
goto error;
if (scf_iter_service_instances(it, s) != 0)
goto error;
if (_smf_refresh_instance_i(i) != 0)
goto error;
if (err == -1)
goto error;
r = 0;
return (r);
}
int
{
}
int
{
}
int
{
if (flags & SMF_TEMPORARY)
return (set_inst_action(instance,
(flags & SMF_IMMEDIATE) ?
else
return (set_inst_action(instance,
(flags & SMF_IMMEDIATE) ?
}
int
{
const char *state_str;
if (flags & SMF_TEMPORARY)
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
SCF_PROPERTY_STATE)) == NULL)
return (SCF_FAILED);
return (SCF_FAILED);
}
return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
}
}
int
{
const char *state_str;
int ret;
SCF_PROPERTY_STATE)) == NULL)
return (SCF_FAILED);
return (SCF_FAILED);
}
} else {
}
return (ret);
}
char *
{
const char *state_str;
char *ret;
SCF_PROPERTY_STATE)) == NULL)
return (NULL);
return (NULL);
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (ret);
}
/*
* scf_general_pg_setup(fmri, pg_name)
* Create a scf_simple_handle_t and fill in the instance, snapshot, and
* property group fields associated with the given fmri and property group
* name.
* Returns:
* Handle on success
* Null on error with scf_error set to:
* SCF_ERROR_HANDLE_MISMATCH,
* SCF_ERROR_INVALID_ARGUMENT,
* SCF_ERROR_CONSTRAINT_VIOLATED,
* SCF_ERROR_NOT_FOUND,
* SCF_ERROR_NOT_SET,
* SCF_ERROR_DELETED,
* SCF_ERROR_NOT_BOUND,
* SCF_ERROR_CONNECTION_BROKEN,
* SCF_ERROR_INTERNAL,
* SCF_ERROR_NO_RESOURCES,
* SCF_ERROR_BACKEND_ACCESS
*/
{
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
} else {
}
goto out;
}
goto out;
}
!= 0) {
goto out;
}
ret->running_pg) != 0) {
goto out;
}
return (ret);
out:
return (NULL);
}
/*
* scf_transaction_setup(h)
* creates and starts the transaction
* Returns:
* transaction on success
* NULL on failure with scf_error set to:
* SCF_ERROR_NO_MEMORY,
* SCF_ERROR_INVALID_ARGUMENT,
* SCF_ERROR_HANDLE_DESTROYED,
* SCF_ERROR_INTERNAL,
* SCF_ERROR_NO_RESOURCES,
* SCF_ERROR_NOT_BOUND,
* SCF_ERROR_CONNECTION_BROKEN,
* SCF_ERROR_NOT_SET,
* SCF_ERROR_DELETED,
* SCF_ERROR_CONSTRAINT_VIOLATED,
* SCF_ERROR_HANDLE_MISMATCH,
* SCF_ERROR_BACKEND_ACCESS,
* SCF_ERROR_IN_USE
*/
{
return (NULL);
}
return (NULL);
}
return (NULL);
}
return (tx);
}
int
{
return (SCF_FAILED);
}
return (SCF_FAILED);
}
return (SCF_SUCCESS);
}
/*
* scf_read_count_property(scf_simple_handle_t *simple_h, char *prop_name,
* uint64_t *ret_count)
*
* For the given property name, return the count value.
* RETURNS:
* SCF_SUCCESS
* SCF_FAILED on failure with scf_error() set to:
* SCF_ERROR_HANDLE_DESTROYED
* SCF_ERROR_INTERNAL
* SCF_ERROR_NO_RESOURCES
* SCF_ERROR_NO_MEMORY
* SCF_ERROR_HANDLE_MISMATCH
* SCF_ERROR_INVALID_ARGUMENT
* SCF_ERROR_NOT_BOUND
* SCF_ERROR_CONNECTION_BROKEN
* SCF_ERROR_NOT_SET
* SCF_ERROR_DELETED
* SCF_ERROR_BACKEND_ACCESS
* SCF_ERROR_CONSTRAINT_VIOLATED
* SCF_ERROR_TYPE_MISMATCH
*/
int
char *prop_name,
{
goto out;
}
/*
* Get the property struct that goes with this property group and
* property name.
*/
goto out;
}
/* Get the value structure */
goto out;
}
/*
* Now get the count value.
*/
goto out;
}
ret = SCF_SUCCESS;
out:
return (ret);
}
/*
* scf_trans_add_count_property(trans, propname, count, create_flag)
*
* Set a count property transaction entry into the pending SMF transaction.
* The transaction is created and committed outside of this function.
* Returns:
* SCF_SUCCESS
* SCF_FAILED on failure with scf_error() set to:
* SCF_ERROR_HANDLE_DESTROYED,
* SCF_ERROR_INVALID_ARGUMENT,
* SCF_ERROR_NO_MEMORY,
* SCF_ERROR_HANDLE_MISMATCH,
* SCF_ERROR_NOT_SET,
* SCF_ERROR_IN_USE,
* SCF_ERROR_NOT_FOUND,
* SCF_ERROR_EXISTS,
* SCF_ERROR_TYPE_MISMATCH,
* SCF_ERROR_NOT_BOUND,
* SCF_ERROR_CONNECTION_BROKEN,
* SCF_ERROR_INTERNAL,
* SCF_ERROR_DELETED,
* SCF_ERROR_NO_RESOURCES,
* SCF_ERROR_BACKEND_ACCESS
*/
int
char *propname,
{
return (SCF_FAILED);
}
/*
* Property must be set in transaction and won't take
* effect until the transaction is committed.
*
* Attempt to change the current value. However, create new property
* if it doesn't exist and the create flag is set.
*/
SCF_TYPE_COUNT) == 0) {
return (SCF_SUCCESS);
}
} else {
if ((create_flag == B_TRUE) &&
(scf_error() == SCF_ERROR_NOT_FOUND)) {
SCF_TYPE_COUNT) == 0) {
return (SCF_SUCCESS);
}
}
}
}
/*
* cleanup if there were any errors that didn't leave these
* values where they would be cleaned up later.
*/
return (SCF_FAILED);
}
int
{
scf_handle_t *h = NULL;
int inst_state;
return (ret);
goto out;
/*
* Get the local scope, and set up nested iteration through every
* local service, and every instance of every service.
*/
goto out;
goto out;
while ((inst_iter_ret =
/*
* If get_inst_state fails from an internal error,
* IE, being unable to get the property group or
* property containing the state of the instance,
* we continue instead of failing, as this might just
* be an improperly configured instance.
*/
if (scf_error() == SCF_ERROR_INTERNAL) {
continue;
} else {
goto out;
}
}
SCF_SUCCESS) {
(void) scf_set_error(
goto out;
}
}
}
if (inst_iter_ret == -1)
goto out;
}
if (svc_iter_ret != -1)
ret = SCF_SUCCESS;
out:
return (ret);
}
static scf_property_t *
const char *propname)
{
scf_handle_t *h = NULL;
/* If the user passed in a handle, use it. */
h = hin;
}
return (NULL);
if (local_h)
return (NULL);
}
goto out;
SCF_DECODE_FMRI_REQUIRE_INSTANCE) == -1) {
switch (scf_error()) {
/*
* If the property isn't found in the instance, we grab the
* underlying service, create an FMRI out of it, and then
* query the datastore again at the service level for the
* property.
*/
case SCF_ERROR_NOT_FOUND:
goto out;
goto out;
goto out;
goto out;
}
break;
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
default:
goto out;
}
}
out:
if (err) {
}
if (local_h)
return (prop);
}
const char *propname)
{
scf_handle_t *h = NULL;
/* If the user passed in a handle, use it. */
h = hin;
}
return (NULL);
}
if (local_h)
return (ret);
}
void
{
int i;
return;
case SCF_TYPE_OPAQUE: {
for (i = 0; i < prop->pr_numvalues; i++) {
}
break;
}
case SCF_TYPE_ASTRING:
case SCF_TYPE_USTRING:
case SCF_TYPE_HOST:
case SCF_TYPE_HOSTNAME:
case SCF_TYPE_NET_ADDR:
case SCF_TYPE_NET_ADDR_V4:
case SCF_TYPE_NET_ADDR_V6:
case SCF_TYPE_URI:
case SCF_TYPE_FMRI: {
for (i = 0; i < prop->pr_numvalues; i++) {
}
break;
}
default:
break;
}
}
{
scf_handle_t *h = NULL;
/* If the user passed in a handle, use it. */
h = hin;
}
return (NULL);
if (local_h)
return (NULL);
}
if (local_h)
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
if (local_h)
return (NULL);
}
} else {
if (local_h)
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (NULL);
}
}
goto error2;
SCF_DECODE_FMRI_REQUIRE_INSTANCE) == -1) {
if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
goto error2;
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto error2;
}
0) {
if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
(void) scf_set_error(SCF_ERROR_INTERNAL);
goto error1;
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto error1;
}
} else {
/* This is the first iteration */
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto error1;
}
if (scf_error() == SCF_ERROR_NOT_SET)
(void) scf_set_error(SCF_ERROR_INTERNAL);
goto error1;
}
if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
(void) scf_set_error(SCF_ERROR_INTERNAL);
goto error1;
}
== 1) {
0) {
if (scf_error() == SCF_ERROR_NOT_SET)
(void) scf_set_error(
goto error1;
}
goto error1;
} else {
/* This is the first iteration */
goto error1;
}
}
if (propiter_ret == -1) {
if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
(void) scf_set_error(SCF_ERROR_INTERNAL);
goto error1;
}
}
if (pgiter_ret == -1) {
if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
(void) scf_set_error(SCF_ERROR_INTERNAL);
goto error1;
}
/*
* At this point, we've filled the scf_simple_app_props_t with all the
* properties at the service level. Now we iterate over all the
* properties at the instance level, overwriting any duplicate
*/
!= 0) {
if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
(void) scf_set_error(SCF_ERROR_INTERNAL);
goto error1;
}
found = 0;
/*
* Find either the end of the list, so we can append the
* property group, or an existing property group that matches
*/
if (scf_error() == SCF_ERROR_NOT_SET)
(void) scf_set_error(SCF_ERROR_INTERNAL);
goto error1;
}
found = 1;
break;
}
break;
}
if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
(void) scf_set_error(SCF_ERROR_INTERNAL);
goto error1;
}
if (found) {
/*
* insert_app_props inserts or overwrites the
* properties in thispg.
*/
goto error1;
} else {
/*
* If the property group wasn't found, we're adding
* a newly allocated property group to the end of the
* list.
*/
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto error1;
}
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
goto error1;
}
} else {
}
while ((propiter_ret =
namelen) < 0) {
if (scf_error() == SCF_ERROR_NOT_SET)
(void) scf_set_error(
goto error1;
}
NULL)
goto error1;
} else {
/* This is the first iteration */
NULL)
goto error1;
}
}
if (propiter_ret == -1) {
if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
(void) scf_set_error(
goto error1;
}
}
}
if (pgiter_ret == -1) {
if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
(void) scf_set_error(SCF_ERROR_INTERNAL);
goto error1;
}
if (local_h)
return (NULL);
return (ret);
/*
* Exit point for a successful call. Below this line are exit points
* for failures at various stages during the function.
*/
if (local_h)
return (NULL);
}
void
{
return;
}
}
}
const scf_simple_prop_t *
{
(void) scf_set_error(SCF_ERROR_NOT_SET);
return (NULL);
}
/*
* We're looking for the first property in this block if last is
* NULL
*/
/* An empty pglist is legal, it just means no properties */
(void) scf_set_error(SCF_ERROR_NONE);
return (NULL);
}
/*
* Walk until we find a pg with a property in it, or we run
* out of property groups.
*/
(void) scf_set_error(SCF_ERROR_NONE);
return (NULL);
}
return (this->pg_proplist);
}
/*
* If last isn't NULL, then return the next prop in the property group,
* or walk the property groups until we find another property, or
* run out of property groups.
*/
(void) scf_set_error(SCF_ERROR_NONE);
return (NULL);
}
(void) scf_set_error(SCF_ERROR_NONE);
return (NULL);
}
return (this->pg_proplist);
}
const scf_simple_prop_t *
{
(void) scf_set_error(SCF_ERROR_NOT_SET);
return (NULL);
}
/*
* If pgname is NULL, we're searching the default application
* property group, otherwise we look for the specified group.
*/
} else {
}
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
return (NULL);
}
(void) scf_set_error(SCF_ERROR_NOT_FOUND);
return (NULL);
}
return (prop);
}
void
{
return;
}
{
return (scf_set_error(SCF_ERROR_NOT_SET));
return (prop->pr_numvalues);
}
{
return (scf_set_error(SCF_ERROR_NOT_SET));
}
char *
{
(void) scf_set_error(SCF_ERROR_NOT_SET);
return (NULL);
}
return (prop->pr_propname);
}
char *
{
(void) scf_set_error(SCF_ERROR_NOT_SET);
return (NULL);
}
}
static union scf_simple_prop_val *
{
(void) scf_set_error(SCF_ERROR_NOT_SET);
return (NULL);
}
case SCF_TYPE_USTRING:
case SCF_TYPE_HOST:
case SCF_TYPE_HOSTNAME:
case SCF_TYPE_NET_ADDR:
case SCF_TYPE_NET_ADDR_V4:
case SCF_TYPE_NET_ADDR_V6:
case SCF_TYPE_URI:
case SCF_TYPE_FMRI: {
if (type != SCF_TYPE_USTRING) {
(void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
return (NULL);
}
break;
}
default: {
(void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
return (NULL);
}
break;
}
}
(void) scf_set_error(SCF_ERROR_NONE);
return (NULL);
}
}
uint8_t *
{
return (NULL);
}
uint64_t *
{
return (NULL);
}
int64_t *
{
return (NULL);
}
int64_t *
{
return (NULL);
}
char *
{
return (NULL);
}
char *
{
return (NULL);
}
void *
{
*length = 0;
return (NULL);
}
}
/*
* Generate a filename based on the fmri and the given name and return
* it in the buffer of MAXPATHLEN provided by the caller.
* If temp_filename is non-zero, also generate a temporary, unique filename
* and return it in the temp buffer of MAXPATHLEN provided by the caller.
* The path to the generated pathname is also created.
* Given fmri should begin with a scheme such as "svc:".
* Returns
* 0 on success
* -1 if filename would exceed MAXPATHLEN or
* -2 if unable to create directory to filename path
*/
int
char *temp_filename)
{
int len;
if (len > MAXPATHLEN)
return (-1);
/* Construct directory name first - speedy path ends in slash */
/* errno is set */
return (-2);
}
if (temp_filename) {
}
return (0);
}
{
do {
return (base);
}
/*
* Cleanup just the linked list of scf_propvec_mval_t nodes and respective
* pv_ptr entries created by scf_read_propvec_mval().
*/
static void
{
while (pv_ptr_node != NULL) {
}
}
}
/*
* Convenience routine which frees all strings and opaque data
* allocated by scf_read_propvec.
*
* Like free(3C), this function preserves the value of errno.
*/
void
{
continue;
}
}
}
errno = saved_errno;
}
/*
* Read values for given multi-valued property. The results are put to the
* linked list of scf_propvec_mval_t pointed by the pv_ptr in the original
* scf_propvec_t.
*/
static int
scf_property_t *p)
{
return (SCF_FAILED);
}
if (scf_iter_property_values(pi, p) != 0) {
goto out;
}
int ret = 0;
goto out;
}
if (pv_ptr_ll_end != NULL) {
} else {
}
case SCF_TYPE_BOOLEAN: {
uint8_t b;
break;
}
goto out;
}
break;
}
case SCF_TYPE_COUNT:
goto out;
}
break;
case SCF_TYPE_INTEGER:
goto out;
}
break;
case SCF_TYPE_TIME: {
goto out;
}
break;
}
case SCF_TYPE_OPAQUE: {
goto out;
}
goto out;
}
goto out;
}
break;
}
default: {
if (size == -1) {
goto out;
}
goto out;
}
break;
}
}
if (ret == -1) {
goto out;
}
}
out:
if (error != SCF_ERROR_NONE) {
(void) scf_set_error(error);
return (SCF_FAILED);
}
return (SCF_SUCCESS);
}
/*
* If 'running' is true, reads from the running snapshot instead of the
* editing snapshot.
*
* For string types, a buffer is allocated using malloc(3C) to hold the
* zero-terminated string, a pointer to which is stored in the
* caller-provided char **. It is the caller's responsbility to free
* this string. To simplify error handling, unread strings are
* initialized to NULL.
*
* For opaque types, a buffer is allocated using malloc(3C) to hold the
* opaque data. A pointer to this buffer and its size are stored in
* the caller-provided scf_opaque_t. It is the caller's responsibility
* to free this buffer. To simplify error handling, the address fields
* for unread opaque data are initialized to NULL.
*
* Multi-valued properties are stored in the linked list of scf_propvec_mval_t.
* The list itself and each of the pv_ptr entries holding the actual values are
* allocated using malloc(3C). It is the caller's responsibility to free the
* buffers either manually or using scf_clean_propvec().
*
* All other data is stored directly in caller-provided variables or
* structures.
*
* If this function fails to read a specific property, *badprop is set
* to point at that property's entry in the properties array.
*
* On all failures, all memory allocated by this function is freed.
*/
int
{
scf_service_t *s = scf_service_create(h);
scf_instance_t *i = scf_instance_create(h);
scf_property_t *p = scf_property_create(h);
scf_value_t *v = scf_value_create(h);
}
goto scferror;
goto scferror;
if (scf_error() != SCF_ERROR_NOT_SET)
goto scferror;
}
if (running) {
if (!instance) {
goto out;
}
goto scferror;
}
goto scferror;
int ret = 0;
goto scferror;
}
goto scferror;
}
continue;
}
if (scf_property_get_value(p, v) == -1) {
goto scferror;
}
case SCF_TYPE_BOOLEAN: {
uint8_t b;
break;
}
} else {
}
break;
}
case SCF_TYPE_COUNT:
break;
case SCF_TYPE_INTEGER:
break;
case SCF_TYPE_TIME: {
break;
}
case SCF_TYPE_OPAQUE: {
goto scferror;
}
goto out;
}
break;
}
default: {
char *s;
if (size == -1) {
goto scferror;
}
goto out;
}
}
}
if (ret == -1) {
goto scferror;
}
}
goto out;
out:
if (error != SCF_ERROR_NONE) {
(void) scf_set_error(error);
return (SCF_FAILED);
}
return (SCF_SUCCESS);
}
/*
* Adds entries for the given multi-valued property to the respective
* transaction entry of transaction initiated in scf_write_propvec().
*/
int
{
int ret;
scf_value_t *v;
if ((v = scf_value_create(h)) == NULL) {
return (SCF_FAILED);
}
case SCF_TYPE_BOOLEAN:
break;
case SCF_TYPE_COUNT:
break;
case SCF_TYPE_INTEGER:
break;
case SCF_TYPE_TIME: {
ret = scf_value_set_time(v,
break;
}
case SCF_TYPE_OPAQUE: {
ret = scf_value_set_opaque(v,
break;
}
case SCF_TYPE_ASTRING:
ret = scf_value_set_astring(v,
(const char *)pv_ptr_node->pv_ptr);
break;
default:
(const char *)pv_ptr_node->pv_ptr);
}
return (SCF_FAILED);
}
}
return (SCF_SUCCESS);
}
/*
*
* If this function fails to write a specific property, *badprop is set
* to point at that property's entry in the properties array.
*
* One significant difference between this function and the
* scf_read_propvec function is that for string types, pv_ptr is a
* char *, not a char **. This means that you can't write a propvec
* you just read, but makes other uses (hopefully the majority) simpler.
*/
int
{
scf_service_t *s = scf_service_create(h);
scf_property_t *p = scf_property_create(h);
scf_value_t *v;
int i, ret;
goto scferror;
!= SCF_SUCCESS)
goto scferror;
if (scf_error() != SCF_ERROR_NOT_SET)
goto scferror;
}
goto scferror;
top:
goto scferror;
if ((e = scf_entry_create(h)) == NULL) {
goto scferror;
}
if (ret == -1) {
goto scferror;
}
goto scferror;
}
continue;
}
if ((v = scf_value_create(h)) == NULL) {
goto scferror;
}
case SCF_TYPE_BOOLEAN: {
scf_value_set_boolean(v, b ? 1 : 0);
break;
}
case SCF_TYPE_COUNT:
break;
case SCF_TYPE_INTEGER:
break;
case SCF_TYPE_TIME: {
break;
}
case SCF_TYPE_OPAQUE: {
break;
}
case SCF_TYPE_ASTRING:
ret = scf_value_set_astring(v,
break;
default:
}
goto scferror;
}
}
if (ret == 1)
goto out;
goto top;
}
out:
if (error != SCF_ERROR_NONE) {
(void) scf_set_error(error);
return (SCF_FAILED);
}
return (SCF_SUCCESS);
}
/*
* Returns
* 0 - success
* ECONNABORTED - repository connection broken
* ECANCELED - inst was deleted
* EPERM
* EACCES
* EROFS
* ENOMEM
*/
int
const char *pname)
{
scf_handle_t *h;
h = scf_instance_handle(inst);
return (ENOMEM);
}
switch (error) {
case SCF_ERROR_NOT_FOUND:
return (SCF_SUCCESS);
case SCF_ERROR_DELETED:
return (ECANCELED);
default:
return (ECONNABORTED);
case SCF_ERROR_NOT_SET:
}
}
tx = scf_transaction_create(h);
e = scf_entry_create(h);
goto out;
}
for (;;) {
goto scferror;
}
goto scferror;
}
ret = 0;
goto out;
}
if (r == -1) {
goto scferror;
}
goto scferror;
}
}
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_NOT_FOUND:
ret = 0;
break;
break;
case SCF_ERROR_BACKEND_ACCESS:
break;
break;
default:
ret = ECONNABORTED;
break;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
}
out:
return (ret);
}
/*
* Check the "application/auto_enable" property for the passed FMRI.
* scf_simple_prop_get() should find the property on an instance
* or on the service FMRI. The routine returns:
* -1: inconclusive (likely no such property or FMRI)
* 0: auto_enable is false
* 1: auto_enable is true
*/
static int
{
"auto_enable");
if (!prop)
return (retval);
return (retval);
}
/*
* Check an array of services and enable any that don't have the
* "application/auto_enable" property set to "false", which is
* the interface to turn off this behaviour (see PSARC 2004/739).
*/
void
{
char *s;
if (is_auto_enabled(*svcs) == 0)
continue;
if (strcmp(SCF_STATE_STRING_DISABLED, s) == 0)
(void) smf_enable_instance(*svcs,
free(s);
}
}
}
/*ARGSUSED*/
static int
{
}
static int
{
}
{
if (l == 0)
else
return (SCF_STATE_UNINIT);
return (SCF_STATE_MAINT);
return (SCF_STATE_OFFLINE);
return (SCF_STATE_DISABLED);
return (SCF_STATE_ONLINE);
return (SCF_STATE_DEGRADED);
return (SCF_STATE_ALL);
else
return (-1);
}
/*
* int32_t smf_state_from_string()
* return the value of the macro SCF_STATE_* for the corresponding state
* it returns SCF_STATE_ALL if "all" is passed. -1 if the string passed doesn't
* correspond to any valid state.
*/
{
return (state_from_string(state, 0));
}
/*
* smf_state_to_string()
* Takes an int32_t representing an SMF state and returns
* the corresponding string. The string is read only and need not to be
* freed.
* returns NULL on invalid input.
*/
const char *
{
switch (s) {
case SCF_STATE_UNINIT:
return (SCF_STATE_STRING_UNINIT);
case SCF_STATE_MAINT:
return (SCF_STATE_STRING_MAINT);
case SCF_STATE_OFFLINE:
return (SCF_STATE_STRING_OFFLINE);
case SCF_STATE_DISABLED:
return (SCF_STATE_STRING_DISABLED);
case SCF_STATE_ONLINE:
return (SCF_STATE_STRING_ONLINE);
case SCF_STATE_DEGRADED:
return (SCF_STATE_STRING_DEGRADED);
case SCF_STATE_ALL:
return ("all");
default:
return (NULL);
}
}
static int
{
scf_handle_t *h;
lsnap = scf_snapshot_create(h);
}
switch (scf_error()) {
case SCF_ERROR_NO_RESOURCES:
case SCF_ERROR_NOT_SET:
default:
return (-1);
}
}
} else {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_DELETED:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
return (-1);
}
switch (scf_error()) {
case SCF_ERROR_EXISTS:
goto again;
case SCF_ERROR_NO_RESOURCES:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_INTERNAL:
return (-1);
default:
return (-1);
}
}
}
return (0);
}
static int
{
int committed;
goto out;
}
/* Make sure that the restarter fmri is fully qualified. */
if (restarter_fmri != NULL &&
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
goto out;
}
do {
goto out;
if ((restarter_fmri == NULL &&
SCF_PROPERTY_RESTARTER, SCF_TYPE_FMRI) != 0)) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
default:
goto out;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
bad_error("transaction_property_set",
scf_error());
}
}
if (restarter_fmri != NULL) {
strrest) == -1 ||
goto out;
}
}
if (committed == -1)
goto out;
if (committed == 0) {
goto out;
}
} while (committed == 0);
/*
* Update the running snapshot so that the new restarter is properly
* visible.
*/
out:
return (ret);
}
/*
* smf_set_restarter()
* Takes two char strings, each an fmri representation. The first is the
* fmri for the instance whose restarter is to be set. The second is the fmri
* for the delegated restarter.
*
* Validate that the restarter fmri is a valid fmri instance.
*/
int
{
scf_handle_t *h = NULL;
scf_value_t *v = NULL;
(void) scf_set_error(SCF_ERROR_NO_MEMORY);
return (ret);
}
(v = scf_value_create(h)) == NULL) {
goto out;
}
if (restarter_fmri != NULL &&
NULL,
if (scf_error() != SCF_ERROR_NOT_FOUND)
goto out;
}
SCF_DECODE_FMRI_EXACT) == -1) {
if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
goto out;
}
if (scf_error() != SCF_ERROR_NOT_FOUND)
goto out;
if (scf_error() != SCF_ERROR_EXISTS)
goto out;
}
}
if (scf_error() == SCF_ERROR_NOT_FOUND ||
scf_error() == SCF_ERROR_DELETED) {
if (restarter_fmri != NULL) {
goto out;
} else {
ret = 0;
}
}
goto out;
}
if (restarter_fmri == NULL) {
goto out;
}
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
pg, v);
default:
goto out;
}
}
if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
goto out;
goto out;
}
ret = 0;
goto out;
}
out:
return (ret);
}
/*
* It is the responsibility of the caller to free the dfmri if it is returned.
* dfmri can be set if the rfmri is NULL, requesting a reset of the restarter.
* The dfmri will be filled in with the restarter under the admin layer for
* reporting purposes by the caller.
*
* return :
* -2 failed to get the restarter state
* -1 restarter does not exist
* 0 restarter is in a valid state (e.g online)
* restarter_state restarter state that needs to be managed
*/
int
char **dfmri)
{
char *d = NULL;
char *state_str;
/*
* If the rfmri is NULL, then this is a reset, so we have to get the
* restarter below admin layer restarter and determine its state and
* return.
*
* If there is no admin layer then return (0) as the restarter is not
* going to be reset so we are fine.
*
* If there is an admin layer take the entry just below that.
*/
scf_handle_t *h;
int iter_ret;
if (h == NULL)
return (-2);
if (scf_error() == SCF_ERROR_NOT_FOUND)
return (0);
return (-2);
}
return (-2);
}
return (-2);
}
return (-2);
}
if (scf_decoration_get_layer(dec, &l)) {
iter_ret = -1;
break;
}
/*
* If the layer is not an admin layer, and it's greater
* than the current higheset found layer then lets get
* the value for the restarter and set the rmfri.
*/
if (l > SCF_CUSTOMIZATION_BOUNDARY || l < hl)
continue;
hl = l;
iter_ret = -1;
break;
}
}
if (iter_ret == -1) {
free(d);
return (-2);
}
*dfmri = d;
if (hl == SCF_DECORATION_INVALID)
return (0);
rfmri = d;
}
return (-1);
if (state == SCF_STATE_ONLINE)
return (0);
return (state);
}
void
const char *textdomain)
{
char *f = NULL;
scf_handle_t *h = NULL;
scf_transaction_t *t = NULL;
scf_instance_t *i = NULL;
int commit_retry;
(i = scf_instance_create(h)) == NULL ||
(t = scf_transaction_create(h)) == NULL ||
(textdomain != NULL &&
goto failed;
}
"smf_method_exit_%-3d", semantic);
SCF_PG_FLAG_NONPERSISTENT, pg) != 0) {
if (scf_error() != SCF_ERROR_EXISTS)
goto failed;
goto failed;
}
if (scf_transaction_start(t, pg) != 0)
goto failed;
if ((scf_transaction_property_new(t, t_ms,
(scf_error() != SCF_ERROR_EXISTS ||
SCF_PROPERTY_AUX_STATE_CUSTOM, SCF_TYPE_ASTRING) != 0)) ||
goto failed;
if ((scf_transaction_property_new(t, t_ml,
SCF_PROPERTY_AUX_REASON, SCF_TYPE_ASTRING) != 0 &&
(scf_error() != SCF_ERROR_EXISTS ||
SCF_PROPERTY_AUX_REASON, SCF_TYPE_ASTRING) != 0)) ||
goto failed;
if (textdomain != NULL &&
SCF_TYPE_ASTRING) != 0 &&
(scf_error() != SCF_ERROR_EXISTS ||
SCF_PROPERTY_AUX_TEXTDOMAIN, SCF_TYPE_ASTRING) != 0)) ||
goto failed;
switch (scf_transaction_commit(t)) {
case -1:
goto failed;
case 0:
if (scf_pg_update(pg) != 0)
goto failed;
break;
case 1:
}
}
/*
* If semantic requires smf_method_exit(), it may be ignored by the
* restarter. If smf_method_exit() was simply used to provide custom
* messages, then semantic may still be honored, even if those messages
* were not successfully transmitted.
*/
}