smb_scfutil.c revision c8ec8eea9849cac239663c46be8a7f5d2ba7ca00
1N/A/*
1N/A * CDDL HEADER START
1N/A *
1N/A * The contents of this file are subject to the terms of the
1N/A * Common Development and Distribution License (the "License").
1N/A * You may not use this file except in compliance with the License.
1N/A *
1N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1N/A * or http://www.opensolaris.org/os/licensing.
1N/A * See the License for the specific language governing permissions
1N/A * and limitations under the License.
1N/A *
1N/A * When distributing Covered Code, include this CDDL HEADER in each
1N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1N/A * If applicable, add the following below this CDDL HEADER, with the
1N/A * fields enclosed by brackets "[]" replaced with your own identifying
1N/A * information: Portions Copyright [yyyy] [name of copyright owner]
1N/A *
1N/A * CDDL HEADER END
1N/A */
1N/A/*
1N/A * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
1N/A * Use is subject to license terms.
1N/A */
1N/A
1N/A#pragma ident "@(#)smb_scfutil.c 1.5 08/07/30 SMI"
1N/A
1N/A/* helper functions for using libscf with CIFS */
1N/A
1N/A#include <libscf.h>
1N/A#include <string.h>
1N/A#include <stdio.h>
1N/A#include <stdlib.h>
1N/A#include <syslog.h>
1N/A#include <errno.h>
1N/A#include <libintl.h>
1N/A#include <assert.h>
1N/A#include <strings.h>
1N/A
1N/A#include <uuid/uuid.h>
1N/A#include <sys/param.h>
1N/A
1N/A#include <smbsrv/libsmb.h>
1N/A
1N/A/*
1N/A * smb_smf_scf_log_error(msg)
1N/A * Logs error messages from scf API's
1N/A */
1N/Astatic void
1N/Asmb_smf_scf_log_error(char *msg)
1N/A{
1N/A if (!msg) {
1N/A syslog(LOG_ERR, " SMBD SMF problem: %s\n",
1N/A scf_strerror(scf_error()));
1N/A } else { /*LINTED E_SEC_PRINTF_E_VAR_FMT*/
1N/A syslog(LOG_ERR, msg, scf_strerror(scf_error()));
1N/A }
1N/A}
1N/A
1N/A/*
1N/A * smb_smf_create_service_pgroup(handle, pgroup)
1N/A *
1N/A * create a new property group at service level.
1N/A */
1N/Aint
1N/Asmb_smf_create_service_pgroup(smb_scfhandle_t *handle, char *pgroup)
1N/A{
1N/A int ret = SMBD_SMF_OK;
1N/A int err;
1N/A
1N/A if (handle == NULL)
1N/A return (SMBD_SMF_SYSTEM_ERR);
1N/A
1N/A /*
1N/A * only create a handle if it doesn't exist. It is ok to exist
1N/A * since the pg handle will be set as a side effect.
1N/A */
1N/A if (handle->scf_pg == NULL)
1N/A if ((handle->scf_pg =
1N/A scf_pg_create(handle->scf_handle)) == NULL)
1N/A return (SMBD_SMF_SYSTEM_ERR);
1N/A
1N/A /*
1N/A * if the pgroup exists, we are done. If it doesn't, then we
1N/A * need to actually add one to the service instance.
1N/A */
1N/A if (scf_service_get_pg(handle->scf_service,
1N/A pgroup, handle->scf_pg) != 0) {
1N/A /* doesn't exist so create one */
1N/A if (scf_service_add_pg(handle->scf_service, pgroup,
1N/A SCF_GROUP_APPLICATION, 0, handle->scf_pg) != 0) {
1N/A err = scf_error();
1N/A if (err != SCF_ERROR_NONE)
1N/A smb_smf_scf_log_error(NULL);
1N/A switch (err) {
1N/A case SCF_ERROR_PERMISSION_DENIED:
1N/A ret = SMBD_SMF_NO_PERMISSION;
1N/A break;
1N/A default:
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A break;
1N/A }
1N/A }
1N/A }
1N/A return (ret);
1N/A}
1N/A
1N/A/*
1N/A * Start transaction on current pg in handle.
1N/A * The pg could be service or instance level.
1N/A * Must be called after pg handle is obtained
1N/A * from create or get.
1N/A */
1N/Aint
1N/Asmb_smf_start_transaction(smb_scfhandle_t *handle)
1N/A{
1N/A int ret = SMBD_SMF_OK;
1N/A
1N/A if (!handle || (!handle->scf_pg))
1N/A return (SMBD_SMF_SYSTEM_ERR);
1N/A
1N/A /*
1N/A * lookup the property group and create it if it doesn't already
1N/A * exist.
1N/A */
1N/A if (handle->scf_state == SCH_STATE_INIT) {
1N/A if (ret == SMBD_SMF_OK) {
1N/A handle->scf_trans =
1N/A scf_transaction_create(handle->scf_handle);
1N/A if (handle->scf_trans != NULL) {
1N/A if (scf_transaction_start(handle->scf_trans,
1N/A handle->scf_pg) != 0) {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A scf_transaction_destroy(
1N/A handle->scf_trans);
1N/A handle->scf_trans = NULL;
1N/A }
1N/A } else {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A }
1N/A }
1N/A }
1N/A if (ret == SMBD_SMF_SYSTEM_ERR &&
1N/A scf_error() == SCF_ERROR_PERMISSION_DENIED)
1N/A ret = SMBD_SMF_NO_PERMISSION;
1N/A
1N/A return (ret);
1N/A}
1N/A
1N/A/*
1N/A * smb_smf_end_transaction(handle)
1N/A *
1N/A * Commit the changes that were added to the transaction in the
1N/A * handle. Do all necessary cleanup.
1N/A */
1N/Aint
1N/Asmb_smf_end_transaction(smb_scfhandle_t *handle)
1N/A{
1N/A int ret = SMBD_SMF_OK;
1N/A
1N/A if (handle == NULL)
1N/A return (SMBD_SMF_SYSTEM_ERR);
1N/A
1N/A if (handle->scf_trans == NULL) {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A } else {
1N/A if (scf_transaction_commit(handle->scf_trans) < 0) {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A smb_smf_scf_log_error("Failed to commit "
1N/A "transaction: %s");
1N/A }
1N/A scf_transaction_destroy_children(handle->scf_trans);
1N/A scf_transaction_destroy(handle->scf_trans);
1N/A handle->scf_trans = NULL;
1N/A }
1N/A return (ret);
1N/A}
1N/A
1N/A/*
1N/A * Sets string property in current pg
1N/A */
1N/Aint
1N/Asmb_smf_set_string_property(smb_scfhandle_t *handle,
1N/A char *propname, char *valstr)
1N/A{
1N/A int ret = SMBD_SMF_OK;
1N/A scf_value_t *value = NULL;
1N/A scf_transaction_entry_t *entry = NULL;
1N/A
1N/A if (handle == NULL)
1N/A return (SMBD_SMF_SYSTEM_ERR);
1N/A
1N/A /*
1N/A * properties must be set in transactions and don't take
1N/A * effect until the transaction has been ended/committed.
1N/A */
1N/A value = scf_value_create(handle->scf_handle);
1N/A entry = scf_entry_create(handle->scf_handle);
1N/A if (value != NULL && entry != NULL) {
1N/A if (scf_transaction_property_change(handle->scf_trans, entry,
1N/A propname, SCF_TYPE_ASTRING) == 0 ||
1N/A scf_transaction_property_new(handle->scf_trans, entry,
1N/A propname, SCF_TYPE_ASTRING) == 0) {
1N/A if (scf_value_set_astring(value, valstr) == 0) {
1N/A if (scf_entry_add_value(entry, value) != 0) {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A scf_value_destroy(value);
1N/A }
1N/A /* the value is in the transaction */
1N/A value = NULL;
1N/A } else {
1N/A /* value couldn't be constructed */
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A }
1N/A /* the entry is in the transaction */
1N/A entry = NULL;
1N/A } else {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A }
1N/A } else {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A }
1N/A if (ret == SMBD_SMF_SYSTEM_ERR) {
1N/A switch (scf_error()) {
1N/A case SCF_ERROR_PERMISSION_DENIED:
1N/A ret = SMBD_SMF_NO_PERMISSION;
1N/A break;
1N/A }
1N/A }
1N/A
1N/A /*
1N/A * cleanup if there were any errors that didn't leave these
1N/A * values where they would be cleaned up later.
1N/A */
1N/A if (value != NULL)
1N/A scf_value_destroy(value);
1N/A if (entry != NULL)
1N/A scf_entry_destroy(entry);
1N/A return (ret);
1N/A}
1N/A
1N/A/*
1N/A * Gets string property value.upto sz size.
1N/A * Caller is responsible to have enough memory allocated.
1N/A */
1N/Aint
1N/Asmb_smf_get_string_property(smb_scfhandle_t *handle, char *propname,
1N/A char *valstr, size_t sz)
1N/A{
1N/A int ret = SMBD_SMF_OK;
1N/A scf_value_t *value;
1N/A scf_property_t *prop;
1N/A
1N/A if (handle == NULL)
1N/A return (SMBD_SMF_SYSTEM_ERR);
1N/A
1N/A value = scf_value_create(handle->scf_handle);
1N/A prop = scf_property_create(handle->scf_handle);
1N/A if (value && prop &&
1N/A (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
1N/A if (scf_property_get_value(prop, value) == 0) {
1N/A if (scf_value_get_astring(value, valstr, sz) < 0) {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A }
1N/A } else {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A }
1N/A } else {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A }
1N/A if (value != NULL)
1N/A scf_value_destroy(value);
1N/A if (prop != NULL)
1N/A scf_property_destroy(prop);
1N/A return (ret);
1N/A}
1N/A
1N/A/*
1N/A * Set integer value of property.
1N/A * The value is returned as int64_t value
1N/A * Caller ensures appropriate translation.
1N/A */
1N/Aint
1N/Asmb_smf_set_integer_property(smb_scfhandle_t *handle, char *propname,
1N/A int64_t valint)
1N/A{
1N/A int ret = SMBD_SMF_OK;
1N/A scf_value_t *value = NULL;
1N/A scf_transaction_entry_t *entry = NULL;
1N/A
1N/A if (handle == NULL)
1N/A return (SMBD_SMF_SYSTEM_ERR);
1N/A
1N/A /*
1N/A * properties must be set in transactions and don't take
1N/A * effect until the transaction has been ended/committed.
1N/A */
1N/A value = scf_value_create(handle->scf_handle);
1N/A entry = scf_entry_create(handle->scf_handle);
1N/A if (value != NULL && entry != NULL) {
1N/A if (scf_transaction_property_change(handle->scf_trans, entry,
1N/A propname, SCF_TYPE_INTEGER) == 0 ||
1N/A scf_transaction_property_new(handle->scf_trans, entry,
1N/A propname, SCF_TYPE_INTEGER) == 0) {
1N/A scf_value_set_integer(value, valint);
1N/A if (scf_entry_add_value(entry, value) != 0) {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A scf_value_destroy(value);
1N/A }
1N/A /* the value is in the transaction */
1N/A value = NULL;
1N/A }
1N/A /* the entry is in the transaction */
1N/A entry = NULL;
1N/A } else {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A }
1N/A if (ret == SMBD_SMF_SYSTEM_ERR) {
1N/A switch (scf_error()) {
1N/A case SCF_ERROR_PERMISSION_DENIED:
1N/A ret = SMBD_SMF_NO_PERMISSION;
1N/A break;
1N/A }
1N/A }
1N/A /*
1N/A * cleanup if there were any errors that didn't leave these
1N/A * values where they would be cleaned up later.
1N/A */
1N/A if (value != NULL)
1N/A scf_value_destroy(value);
1N/A if (entry != NULL)
1N/A scf_entry_destroy(entry);
1N/A return (ret);
1N/A}
1N/A
1N/A/*
1N/A * Gets integer property value.
1N/A * Caller is responsible to have enough memory allocated.
1N/A */
1N/Aint
1N/Asmb_smf_get_integer_property(smb_scfhandle_t *handle, char *propname,
1N/A int64_t *valint)
1N/A{
1N/A int ret = SMBD_SMF_OK;
1N/A scf_value_t *value = NULL;
1N/A scf_property_t *prop = NULL;
1N/A
1N/A if (handle == NULL)
1N/A return (SMBD_SMF_SYSTEM_ERR);
1N/A
1N/A value = scf_value_create(handle->scf_handle);
1N/A prop = scf_property_create(handle->scf_handle);
1N/A if ((prop) && (value) &&
1N/A (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
1N/A if (scf_property_get_value(prop, value) == 0) {
1N/A if (scf_value_get_integer(value,
1N/A valint) != 0) {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A }
1N/A } else {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A }
1N/A } else {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A }
1N/A if (value != NULL)
1N/A scf_value_destroy(value);
1N/A if (prop != NULL)
1N/A scf_property_destroy(prop);
1N/A return (ret);
1N/A}
1N/A
1N/A/*
1N/A * Set boolean value of property.
1N/A * The value is returned as int64_t value
1N/A * Caller ensures appropriate translation.
1N/A */
1N/Aint
1N/Asmb_smf_set_boolean_property(smb_scfhandle_t *handle, char *propname,
1N/A uint8_t valbool)
1N/A{
1N/A int ret = SMBD_SMF_OK;
1N/A scf_value_t *value = NULL;
1N/A scf_transaction_entry_t *entry = NULL;
1N/A
1N/A if (handle == NULL)
1N/A return (SMBD_SMF_SYSTEM_ERR);
1N/A
1N/A /*
1N/A * properties must be set in transactions and don't take
1N/A * effect until the transaction has been ended/committed.
1N/A */
1N/A value = scf_value_create(handle->scf_handle);
1N/A entry = scf_entry_create(handle->scf_handle);
1N/A if (value != NULL && entry != NULL) {
1N/A if (scf_transaction_property_change(handle->scf_trans, entry,
1N/A propname, SCF_TYPE_BOOLEAN) == 0 ||
1N/A scf_transaction_property_new(handle->scf_trans, entry,
1N/A propname, SCF_TYPE_BOOLEAN) == 0) {
1N/A scf_value_set_boolean(value, valbool);
1N/A if (scf_entry_add_value(entry, value) != 0) {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A scf_value_destroy(value);
1N/A }
1N/A /* the value is in the transaction */
1N/A value = NULL;
1N/A }
1N/A /* the entry is in the transaction */
1N/A entry = NULL;
1N/A } else {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A }
1N/A if (ret == SMBD_SMF_SYSTEM_ERR) {
1N/A switch (scf_error()) {
1N/A case SCF_ERROR_PERMISSION_DENIED:
1N/A ret = SMBD_SMF_NO_PERMISSION;
1N/A break;
1N/A }
1N/A }
1N/A /*
1N/A * cleanup if there were any errors that didn't leave these
1N/A * values where they would be cleaned up later.
1N/A */
1N/A if (value != NULL)
1N/A scf_value_destroy(value);
1N/A if (entry != NULL)
1N/A scf_entry_destroy(entry);
1N/A return (ret);
1N/A}
1N/A
1N/A/*
1N/A * Gets boolean property value.
1N/A * Caller is responsible to have enough memory allocated.
1N/A */
1N/Aint
1N/Asmb_smf_get_boolean_property(smb_scfhandle_t *handle, char *propname,
1N/A uint8_t *valbool)
1N/A{
1N/A int ret = SMBD_SMF_OK;
1N/A scf_value_t *value = NULL;
1N/A scf_property_t *prop = NULL;
1N/A
1N/A if (handle == NULL)
1N/A return (SMBD_SMF_SYSTEM_ERR);
1N/A
1N/A value = scf_value_create(handle->scf_handle);
1N/A prop = scf_property_create(handle->scf_handle);
1N/A if ((prop) && (value) &&
1N/A (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
1N/A if (scf_property_get_value(prop, value) == 0) {
1N/A if (scf_value_get_boolean(value,
1N/A valbool) != 0) {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A }
1N/A } else {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A }
1N/A } else {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A }
1N/A if (value != NULL)
1N/A scf_value_destroy(value);
1N/A if (prop != NULL)
1N/A scf_property_destroy(prop);
1N/A return (ret);
1N/A}
1N/A
1N/A/*
1N/A * Sets a blob property value.
1N/A */
1N/Aint
1N/Asmb_smf_set_opaque_property(smb_scfhandle_t *handle, char *propname,
1N/A void *voidval, size_t sz)
1N/A{
1N/A int ret = SMBD_SMF_OK;
1N/A scf_value_t *value;
1N/A scf_transaction_entry_t *entry;
1N/A
1N/A if (handle == NULL)
1N/A return (SMBD_SMF_SYSTEM_ERR);
1N/A
1N/A /*
1N/A * properties must be set in transactions and don't take
1N/A * effect until the transaction has been ended/committed.
1N/A */
1N/A value = scf_value_create(handle->scf_handle);
1N/A entry = scf_entry_create(handle->scf_handle);
1N/A if (value != NULL && entry != NULL) {
1N/A if (scf_transaction_property_change(handle->scf_trans, entry,
1N/A propname, SCF_TYPE_OPAQUE) == 0 ||
1N/A scf_transaction_property_new(handle->scf_trans, entry,
1N/A propname, SCF_TYPE_OPAQUE) == 0) {
1N/A if (scf_value_set_opaque(value, voidval, sz) == 0) {
1N/A if (scf_entry_add_value(entry, value) != 0) {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A scf_value_destroy(value);
1N/A }
1N/A /* the value is in the transaction */
1N/A value = NULL;
1N/A } else {
1N/A /* value couldn't be constructed */
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A }
1N/A /* the entry is in the transaction */
1N/A entry = NULL;
1N/A } else {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A }
1N/A } else {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A }
1N/A if (ret == SMBD_SMF_SYSTEM_ERR) {
1N/A switch (scf_error()) {
1N/A case SCF_ERROR_PERMISSION_DENIED:
1N/A ret = SMBD_SMF_NO_PERMISSION;
1N/A break;
1N/A }
1N/A }
1N/A /*
1N/A * cleanup if there were any errors that didn't leave these
1N/A * values where they would be cleaned up later.
1N/A */
1N/A if (value != NULL)
1N/A scf_value_destroy(value);
1N/A if (entry != NULL)
1N/A scf_entry_destroy(entry);
1N/A return (ret);
1N/A}
1N/A
1N/A/*
1N/A * Gets a blob property value.
1N/A * Caller is responsible to have enough memory allocated.
1N/A */
1N/Aint
1N/Asmb_smf_get_opaque_property(smb_scfhandle_t *handle, char *propname,
1N/A void *v, size_t sz)
1N/A{
1N/A int ret = SMBD_SMF_OK;
1N/A scf_value_t *value = NULL;
1N/A scf_property_t *prop = NULL;
1N/A
1N/A if (handle == NULL)
1N/A return (SMBD_SMF_SYSTEM_ERR);
1N/A
1N/A value = scf_value_create(handle->scf_handle);
1N/A prop = scf_property_create(handle->scf_handle);
1N/A if ((prop) && (value) &&
1N/A (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
1N/A if (scf_property_get_value(prop, value) == 0) {
1N/A if (scf_value_get_opaque(value, (char *)v, sz) != sz) {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A }
1N/A } else {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A }
1N/A } else {
1N/A ret = SMBD_SMF_SYSTEM_ERR;
1N/A }
1N/A if (value != NULL)
1N/A scf_value_destroy(value);
1N/A if (prop != NULL)
1N/A scf_property_destroy(prop);
1N/A return (ret);
1N/A}
1N/A
1N/A/*
1N/A * smb_smf_restart_service()
1N/A *
1N/A * Restarts SMB SMF service.
1N/A */
1N/Aint
1N/Asmb_smf_restart_service(void)
1N/A{
1N/A return (smf_restart_instance(SMBD_DEFAULT_INSTANCE_FMRI));
1N/A}
1N/A
1N/A/*
1N/A * smb_smf_scf_init()
1N/A *
1N/A * must be called before using any of the SCF functions.
1N/A * Returns smb_scfhandle_t pointer if success.
1N/A */
1N/Asmb_scfhandle_t *
1N/Asmb_smf_scf_init(char *svc_name)
1N/A{
1N/A smb_scfhandle_t *handle;
1N/A
1N/A handle = malloc(sizeof (smb_scfhandle_t));
1N/A if (handle != NULL) {
1N/A bzero((char *)handle, sizeof (smb_scfhandle_t));
1N/A handle->scf_state = SCH_STATE_INITIALIZING;
1N/A handle->scf_handle = scf_handle_create(SCF_VERSION);
if (handle->scf_handle != NULL) {
if (scf_handle_bind(handle->scf_handle) == 0) {
handle->scf_scope =
scf_scope_create(handle->scf_handle);
if (handle->scf_scope == NULL)
goto err;
if (scf_handle_get_local_scope(
handle->scf_handle, handle->scf_scope) != 0)
goto err;
handle->scf_service =
scf_service_create(handle->scf_handle);
if (handle->scf_service == NULL)
goto err;
if (scf_scope_get_service(handle->scf_scope,
svc_name, handle->scf_service)
!= SCF_SUCCESS) {
goto err;
}
handle->scf_pg =
scf_pg_create(handle->scf_handle);
if (handle->scf_pg == NULL)
goto err;
handle->scf_state = SCH_STATE_INIT;
} else {
goto err;
}
} else {
free(handle);
handle = NULL;
smb_smf_scf_log_error("Could not access SMF "
"repository: %s\n");
}
}
return (handle);
/* error handling/unwinding */
err:
(void) smb_smf_scf_fini(handle);
(void) smb_smf_scf_log_error("SMF initialization problem: %s\n");
return (NULL);
}
/*
* smb_smf_scf_fini(handle)
*
* must be called when done. Called with the handle allocated in
* smb_smf_scf_init(), it cleans up the state and frees any SCF resources
* still in use.
*/
void
smb_smf_scf_fini(smb_scfhandle_t *handle)
{
if (handle != NULL) {
int unbind = 0;
scf_iter_destroy(handle->scf_pg_iter);
handle->scf_pg_iter = NULL;
scf_iter_destroy(handle->scf_inst_iter);
handle->scf_inst_iter = NULL;
unbind = 1;
scf_scope_destroy(handle->scf_scope);
handle->scf_scope = NULL;
scf_instance_destroy(handle->scf_instance);
handle->scf_instance = NULL;
scf_service_destroy(handle->scf_service);
handle->scf_service = NULL;
scf_pg_destroy(handle->scf_pg);
handle->scf_pg = NULL;
handle->scf_state = SCH_STATE_UNINIT;
if (unbind)
(void) scf_handle_unbind(handle->scf_handle);
scf_handle_destroy(handle->scf_handle);
handle->scf_handle = NULL;
free(handle);
}
}