#include <stdio.h>
#include <stdlib.h>
#include <synch.h>
#include <libintl.h>
#include <strings.h>
#include <libndmp.h>
#define NDMP_GROUP_FMRI_PREFIX "system/ndmpd"
#define NDMP_INST "svc:/system/ndmpd:default"
#define NDMP_PROP_LEN 600
static char *ndmp_pg[] = {
"ndmpd",
"read"
};
#define NPG (sizeof (ndmp_pg) / sizeof (ndmp_pg[0]))
#define NDMP_SCH_STATE_UNINIT 0
#define NDMP_SCH_STATE_INITIALIZING 1
#define NDMP_SCH_STATE_INIT 2
typedef struct ndmp_scfhandle {
scf_handle_t *scf_handle;
int scf_state;
scf_service_t *scf_service;
scf_scope_t *scf_scope;
scf_transaction_t *scf_trans;
scf_propertygroup_t *scf_pg;
} ndmp_scfhandle_t;
static int ndmp_config_saveenv(ndmp_scfhandle_t *, boolean_t);
static ndmp_scfhandle_t *ndmp_smf_scf_init(const char *);
static void ndmp_smf_scf_fini(ndmp_scfhandle_t *);
static int ndmp_smf_start_transaction(ndmp_scfhandle_t *);
static int ndmp_smf_end_transaction(ndmp_scfhandle_t *, boolean_t);
static int ndmp_smf_set_property(ndmp_scfhandle_t *, const char *,
const char *);
static int ndmp_smf_get_property(ndmp_scfhandle_t *, const char *, char *,
size_t);
static int ndmp_smf_create_service_pgroup(ndmp_scfhandle_t *, const char *);
static int ndmp_smf_delete_property(ndmp_scfhandle_t *, const char *);
static int ndmp_smf_get_pg_name(ndmp_scfhandle_t *, const char *, char **);
int
ndmp_service_refresh(void)
{
int rc = smf_refresh_instance(NDMP_INST);
if (rc != 0)
ndmp_errno = ENDMP_SMF_INTERNAL;
return (rc);
}
int
ndmp_get_prop(const char *prop, char **value)
{
ndmp_scfhandle_t *handle;
char *lval;
char *pgname;
*value = NULL;
if ((handle = ndmp_smf_scf_init(NDMP_GROUP_FMRI_PREFIX)) == NULL) {
return (-1);
}
if (ndmp_smf_get_pg_name(handle, prop, &pgname)) {
ndmp_smf_scf_fini(handle);
ndmp_errno = ENDMP_SMF_PROP_GRP;
return (-1);
}
if (ndmp_smf_create_service_pgroup(handle, pgname)) {
ndmp_smf_scf_fini(handle);
return (-1);
}
if ((lval = malloc(NDMP_PROP_LEN)) == NULL) {
ndmp_smf_scf_fini(handle);
ndmp_errno = ENDMP_MEM_ALLOC;
return (-1);
}
if (ndmp_smf_get_property(handle, prop, lval, NDMP_PROP_LEN) != 0) {
ndmp_smf_scf_fini(handle);
free(lval);
ndmp_errno = ENDMP_SMF_PROP;
return (-1);
}
*value = lval;
ndmp_smf_scf_fini(handle);
return (0);
}
int
ndmp_set_prop(const char *env, const char *env_val)
{
ndmp_scfhandle_t *handle;
char *pgname;
int rc;
if ((handle = ndmp_smf_scf_init(NDMP_GROUP_FMRI_PREFIX)) == NULL)
return (-1);
if (ndmp_smf_get_pg_name(handle, env, &pgname)) {
ndmp_smf_scf_fini(handle);
ndmp_errno = ENDMP_SMF_PROP_GRP;
return (-1);
}
if (ndmp_smf_create_service_pgroup(handle, pgname)) {
ndmp_smf_scf_fini(handle);
return (-1);
}
if (ndmp_smf_start_transaction(handle)) {
ndmp_smf_scf_fini(handle);
return (-1);
}
if (env_val)
rc = ndmp_smf_set_property(handle, env, env_val);
else
rc = ndmp_smf_delete_property(handle, env);
if (ndmp_config_saveenv(handle, (rc == 0)) == 0)
return (rc);
else
return (-1);
}
static int
ndmp_smf_get_pg_name(ndmp_scfhandle_t *h, const char *pname, char **pgname)
{
scf_value_t *value;
scf_property_t *prop;
int i;
for (i = 0; i < NPG; i++) {
if (scf_service_get_pg(h->scf_service, ndmp_pg[i],
h->scf_pg) != 0)
return (-1);
if ((value = scf_value_create(h->scf_handle)) == NULL)
return (-1);
if ((prop = scf_property_create(h->scf_handle)) == NULL) {
scf_value_destroy(value);
return (-1);
}
if ((scf_pg_get_property(h->scf_pg, pname, prop)) != 0) {
scf_value_destroy(value);
scf_property_destroy(prop);
continue;
}
*pgname = ndmp_pg[i];
scf_value_destroy(value);
scf_property_destroy(prop);
return (0);
}
return (-1);
}
static int
ndmp_config_saveenv(ndmp_scfhandle_t *handle, boolean_t commit)
{
int ret = 0;
ret = ndmp_smf_end_transaction(handle, commit);
ndmp_smf_scf_fini(handle);
return (ret);
}
static void
ndmp_smf_scf_fini(ndmp_scfhandle_t *handle)
{
if (handle == NULL)
return;
scf_scope_destroy(handle->scf_scope);
scf_service_destroy(handle->scf_service);
scf_pg_destroy(handle->scf_pg);
handle->scf_state = NDMP_SCH_STATE_UNINIT;
(void) scf_handle_unbind(handle->scf_handle);
scf_handle_destroy(handle->scf_handle);
free(handle);
}
static ndmp_scfhandle_t *
ndmp_smf_scf_init(const char *svc_name)
{
ndmp_scfhandle_t *handle;
handle = (ndmp_scfhandle_t *)calloc(1, sizeof (ndmp_scfhandle_t));
if (handle != NULL) {
handle->scf_state = NDMP_SCH_STATE_INITIALIZING;
if (((handle->scf_handle =
scf_handle_create(SCF_VERSION)) != NULL) &&
(scf_handle_bind(handle->scf_handle) == 0)) {
if ((handle->scf_scope =
scf_scope_create(handle->scf_handle)) == NULL)
goto err;
if (scf_handle_get_local_scope(handle->scf_handle,
handle->scf_scope) != 0)
goto err;
if ((handle->scf_service =
scf_service_create(handle->scf_handle)) == NULL)
goto err;
if (scf_scope_get_service(handle->scf_scope, svc_name,
handle->scf_service) != SCF_SUCCESS)
goto err;
if ((handle->scf_pg =
scf_pg_create(handle->scf_handle)) == NULL)
goto err;
handle->scf_state = NDMP_SCH_STATE_INIT;
} else {
goto err;
}
} else {
ndmp_errno = ENDMP_MEM_ALLOC;
handle = NULL;
}
return (handle);
err:
(void) ndmp_smf_scf_fini(handle);
ndmp_errno = ENDMP_SMF_INTERNAL;
return (NULL);
}
static int
ndmp_smf_create_service_pgroup(ndmp_scfhandle_t *handle, const char *pgroup)
{
int err;
if (handle->scf_pg == NULL) {
if ((handle->scf_pg =
scf_pg_create(handle->scf_handle)) == NULL) {
ndmp_errno = ENDMP_SMF_INTERNAL;
return (-1);
}
}
if (scf_service_get_pg(handle->scf_service,
pgroup, handle->scf_pg) != 0) {
if (scf_service_add_pg(handle->scf_service, pgroup,
SCF_GROUP_FRAMEWORK, 0, handle->scf_pg) != 0) {
err = scf_error();
switch (err) {
case SCF_ERROR_PERMISSION_DENIED:
ndmp_errno = ENDMP_SMF_PERM;
return (-1);
default:
ndmp_errno = ENDMP_SMF_INTERNAL;
return (-1);
}
}
}
return (0);
}
static int
ndmp_smf_start_transaction(ndmp_scfhandle_t *handle)
{
if (handle->scf_state == NDMP_SCH_STATE_INIT) {
if ((handle->scf_trans =
scf_transaction_create(handle->scf_handle)) != NULL) {
if (scf_transaction_start(handle->scf_trans,
handle->scf_pg) != 0) {
scf_transaction_destroy(handle->scf_trans);
handle->scf_trans = NULL;
ndmp_errno = ENDMP_SMF_INTERNAL;
return (-1);
}
} else {
ndmp_errno = ENDMP_SMF_INTERNAL;
return (-1);
}
}
if (scf_error() == SCF_ERROR_PERMISSION_DENIED) {
ndmp_errno = ENDMP_SMF_PERM;
return (-1);
}
return (0);
}
static int
ndmp_smf_end_transaction(ndmp_scfhandle_t *handle, boolean_t commit)
{
int rc = 0;
if (commit) {
if (scf_transaction_commit(handle->scf_trans) < 0) {
ndmp_errno = ENDMP_SMF_INTERNAL;
rc = -1;
}
}
scf_transaction_destroy_children(handle->scf_trans);
scf_transaction_destroy(handle->scf_trans);
handle->scf_trans = NULL;
return (rc);
}
static int
ndmp_smf_delete_property(ndmp_scfhandle_t *handle, const char *propname)
{
scf_transaction_entry_t *entry = NULL;
if ((entry = scf_entry_create(handle->scf_handle)) != NULL) {
if (scf_transaction_property_delete(handle->scf_trans, entry,
propname) != 0) {
scf_entry_destroy(entry);
ndmp_errno = ENDMP_SMF_INTERNAL;
return (-1);
}
} else {
ndmp_errno = ENDMP_SMF_INTERNAL;
return (-1);
}
if ((scf_error()) == SCF_ERROR_PERMISSION_DENIED) {
ndmp_errno = ENDMP_SMF_PERM;
scf_entry_destroy(entry);
return (-1);
}
return (0);
}
static int
ndmp_smf_set_property(ndmp_scfhandle_t *handle, const char *propname,
const char *valstr)
{
int ret = 0;
scf_value_t *value = NULL;
scf_transaction_entry_t *entry = NULL;
scf_property_t *prop = NULL;
scf_type_t type;
int64_t valint;
uint8_t valbool;
if (((value = scf_value_create(handle->scf_handle)) == NULL) ||
((entry = scf_entry_create(handle->scf_handle)) == NULL) ||
((prop = scf_property_create(handle->scf_handle)) == NULL) ||
(scf_pg_get_property(handle->scf_pg, propname, prop) != 0) ||
(scf_property_get_value(prop, value) != 0)) {
ret = -1;
goto out;
}
type = scf_value_type(value);
if ((scf_transaction_property_change(handle->scf_trans, entry, propname,
type) != 0) &&
(scf_transaction_property_new(handle->scf_trans, entry, propname,
type) != 0)) {
ret = -1;
goto out;
}
switch (type) {
case SCF_TYPE_ASTRING:
if ((scf_value_set_astring(value, valstr)) != SCF_SUCCESS)
ret = -1;
break;
case SCF_TYPE_INTEGER:
valint = strtoll(valstr, 0, 0);
scf_value_set_integer(value, valint);
break;
case SCF_TYPE_BOOLEAN:
if (strncmp(valstr, "yes", 3))
valbool = 0;
else
valbool = 1;
scf_value_set_boolean(value, valbool);
break;
default:
ret = -1;
}
if (scf_entry_add_value(entry, value) == 0) {
value = NULL;
} else {
ret = -1;
}
entry = NULL;
out:
if (ret == -1) {
if ((scf_error() == SCF_ERROR_PERMISSION_DENIED))
ndmp_errno = ENDMP_SMF_PERM;
else
ndmp_errno = ENDMP_SMF_INTERNAL;
}
scf_property_destroy(prop);
scf_value_destroy(value);
scf_entry_destroy(entry);
return (ret);
}
static int
ndmp_smf_get_property(ndmp_scfhandle_t *handle, const char *propname,
char *valstr, size_t sz)
{
int ret = 0;
scf_value_t *value = NULL;
scf_property_t *prop = NULL;
scf_type_t type;
int64_t valint;
uint8_t valbool;
char valstrbuf[NDMP_PROP_LEN];
if (((value = scf_value_create(handle->scf_handle)) != NULL) &&
((prop = scf_property_create(handle->scf_handle)) != NULL) &&
(scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
if (scf_property_get_value(prop, value) == 0) {
type = scf_value_type(value);
switch (type) {
case SCF_TYPE_ASTRING:
if (scf_value_get_astring(value, valstr,
sz) < 0) {
ret = -1;
}
break;
case SCF_TYPE_INTEGER:
if (scf_value_get_integer(value,
&valint) != 0) {
ret = -1;
break;
}
valstrbuf[NDMP_PROP_LEN - 1] = '\0';
(void) strncpy(valstr, lltostr(valint,
&valstrbuf[NDMP_PROP_LEN - 1]),
NDMP_PROP_LEN);
break;
case SCF_TYPE_BOOLEAN:
if (scf_value_get_boolean(value,
&valbool) != 0) {
ret = -1;
break;
}
if (valbool == 1)
(void) strncpy(valstr, "yes", 4);
else
(void) strncpy(valstr, "no", 3);
break;
default:
ret = -1;
}
} else {
ret = -1;
}
} else {
ret = -1;
}
scf_value_destroy(value);
scf_property_destroy(prop);
return (ret);
}