2N/A/*
2N/A * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A/*
2N/A * BSD 3 Clause License
2N/A *
2N/A * Copyright (c) 2007, The Storage Networking Industry Association.
2N/A *
2N/A * Redistribution and use in source and binary forms, with or without
2N/A * modification, are permitted provided that the following conditions
2N/A * are met:
2N/A * - Redistributions of source code must retain the above copyright
2N/A * notice, this list of conditions and the following disclaimer.
2N/A *
2N/A * - Redistributions in binary form must reproduce the above copyright
2N/A * notice, this list of conditions and the following disclaimer in
2N/A * the documentation and/or other materials provided with the
2N/A * distribution.
2N/A *
2N/A * - Neither the name of The Storage Networking Industry Association (SNIA)
2N/A * nor the names of its contributors may be used to endorse or promote
2N/A * products derived from this software without specific prior written
2N/A * permission.
2N/A *
2N/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2N/A * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2N/A * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2N/A * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2N/A * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2N/A * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2N/A * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2N/A * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2N/A * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2N/A * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2N/A * POSSIBILITY OF SUCH DAMAGE.
2N/A */
2N/A
2N/A/*
2N/A * NDMP configuration management
2N/A */
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <synch.h>
2N/A#include <libintl.h>
2N/A#include <strings.h>
2N/A#include <sys/stat.h>
2N/A#include <libndmp.h>
2N/A#include <ctype.h>
2N/A
2N/A/* NDMP properties configuration */
2N/A#define NDMP_GROUP_FMRI_PREFIX "system/ndmpd"
2N/A#define NDMP_INST "svc:/system/ndmpd:default"
2N/A#define NDMP_PROP_LEN 600
2N/Astatic char *ndmp_pg[] = {
2N/A "ndmpd",
2N/A "read"
2N/A};
2N/A#define NPG (sizeof (ndmp_pg) / sizeof (ndmp_pg[0]))
2N/A
2N/A/* Handle Init states */
2N/A#define NDMP_SCH_STATE_UNINIT 0
2N/A#define NDMP_SCH_STATE_INITIALIZING 1
2N/A#define NDMP_SCH_STATE_INIT 2
2N/A
2N/A/* NDMP scf handle structure */
2N/Atypedef struct ndmp_scfhandle {
2N/A scf_handle_t *scf_handle;
2N/A int scf_state;
2N/A scf_service_t *scf_service;
2N/A scf_scope_t *scf_scope;
2N/A scf_transaction_t *scf_trans;
2N/A scf_propertygroup_t *scf_pg;
2N/A} ndmp_scfhandle_t;
2N/A
2N/Atypedef enum {
2N/A NDMP_PROP_BOOL,
2N/A NDMP_PROP_PATH,
2N/A NDMP_PROP_PATH_LIST,
2N/A NDMP_PROP_DTYPE,
2N/A NDMP_PROP_NUMERIC,
2N/A NDMP_PROP_BACKUP_TYPE,
2N/A NDMP_PROP_ZFS_FORCE_OVERRIDE
2N/A} ndmp_prop_type_t;
2N/A
2N/Atypedef struct ndmp_prop {
2N/A char *prop_name;
2N/A ndmp_prop_type_t prop_type;
2N/A} ndmp_prop_t;
2N/A
2N/Astatic ndmp_prop_t prop_table[] = {
2N/A { "debug-path", NDMP_PROP_PATH },
2N/A { "dump-pathnode", NDMP_PROP_BOOL },
2N/A { "tar-pathnode", NDMP_PROP_BOOL },
2N/A { "ignore-ctime", NDMP_PROP_BOOL },
2N/A { "zfs-token-support", NDMP_PROP_BOOL },
2N/A { "token-maxseq", NDMP_PROP_NUMERIC },
2N/A { "version", NDMP_PROP_NUMERIC },
2N/A { "dar-support", NDMP_PROP_BOOL },
2N/A { "tcp-port", NDMP_PROP_NUMERIC },
2N/A { "backup-quarantine", NDMP_PROP_BOOL },
2N/A { "restore-quarantine", NDMP_PROP_BOOL },
2N/A { "overwrite-quarantine", NDMP_PROP_BOOL },
2N/A { "zfs-force-override", NDMP_PROP_ZFS_FORCE_OVERRIDE },
2N/A { "drive-type", NDMP_PROP_DTYPE },
2N/A { "type-override", NDMP_PROP_BACKUP_TYPE },
2N/A { "cpu-binding", NDMP_PROP_BOOL },
2N/A { "fs-export", NDMP_PROP_PATH_LIST }
2N/A};
2N/A
2N/A#define NDMPADM_NPROP (sizeof (prop_table) / sizeof (prop_table[0]))
2N/A
2N/Astatic char *ndmp_bool_vals[] = {
2N/A "yes",
2N/A "no"
2N/A};
2N/A
2N/A#define NBOOLS (sizeof (ndmp_bool_vals) / sizeof (ndmp_bool_vals[0]))
2N/A
2N/Astatic char *ndmp_dtypes[] = {
2N/A "sysv",
2N/A "bsd"
2N/A};
2N/A
2N/A#define NDTYPES (sizeof (ndmp_dtypes) / sizeof (ndmp_dtypes[0]))
2N/A
2N/Astatic char *ndmp_backuptypes[] = {
2N/A "off",
2N/A "zfs"
2N/A};
2N/A
2N/A#define NBTYPES (sizeof (ndmp_backuptypes) / sizeof (ndmp_backuptypes[0]))
2N/A
2N/Astatic char *zfs_force_override_vals[] = {
2N/A "yes",
2N/A "no",
2N/A "off"
2N/A};
2N/A
2N/A#define NZFS_FORCE_OVERRIDE_VALS \
2N/A (sizeof (zfs_force_override_vals) /\
2N/A sizeof (zfs_force_override_vals[0]))
2N/A
2N/Astatic const struct {
2N/A char *prop;
2N/A int lo;
2N/A int hi;
2N/A} ndmp_proplims[] = {
2N/A { "token-maxseq", 0, 64 },
2N/A { "version", 2, 4 },
2N/A { "tcp-port", 1, 65535 }
2N/A};
2N/A
2N/A#define NDMP_NPROPLIM (sizeof (ndmp_proplims) / sizeof (ndmp_proplims[0]))
2N/A
2N/Astatic int ndmp_validate_propval(char *, char *);
2N/Astatic int ndmp_isvalid_numeric(char *, char *);
2N/Astatic int ndmp_config_saveenv(ndmp_scfhandle_t *);
2N/Astatic ndmp_scfhandle_t *ndmp_smf_scf_init(char *);
2N/Astatic void ndmp_smf_scf_fini(ndmp_scfhandle_t *);
2N/Astatic int ndmp_smf_start_transaction(ndmp_scfhandle_t *);
2N/Astatic int ndmp_smf_end_transaction(ndmp_scfhandle_t *);
2N/Astatic int ndmp_smf_set_property(ndmp_scfhandle_t *, char *, char *);
2N/Astatic int ndmp_smf_get_property(ndmp_scfhandle_t *, char *, char *, size_t);
2N/Astatic int ndmp_smf_create_service_pgroup(ndmp_scfhandle_t *, char *);
2N/Astatic int ndmp_smf_delete_property(ndmp_scfhandle_t *, char *);
2N/Astatic int ndmp_smf_get_pg_name(ndmp_scfhandle_t *, char *, char **);
2N/A
2N/A/*
2N/A * This routine send a refresh signal to ndmpd service which cause ndmpd
2N/A * property table to be refeshed with current ndmpd properties value from SMF.
2N/A */
2N/Aint
2N/Andmp_service_refresh(void)
2N/A{
2N/A if ((smf_get_state(NDMP_INST)) != NULL)
2N/A return (smf_refresh_instance(NDMP_INST));
2N/A
2N/A ndmp_errno = ENDMP_SMF_INTERNAL;
2N/A return (-1);
2N/A}
2N/A
2N/A/*
2N/A * Scan list of current supported values.
2N/A */
2N/Aint
2N/Andmp_isvalid_entry(char *propval, char **typelist, int ntypes)
2N/A{
2N/A int ret = 0;
2N/A int i;
2N/A
2N/A for (i = 0; i < ntypes; i++) {
2N/A if (strcasecmp(propval, typelist[i]) == 0)
2N/A break;
2N/A }
2N/A if (i == ntypes) {
2N/A ret = -1;
2N/A }
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * Given a property and an associated value, verify whether
2N/A * or not a.) it's a valid property and b.) if so, whether or not
2N/A * the respective value passed in is valid.
2N/A */
2N/Astatic int
2N/Andmp_validate_propval(char *prop, char *propval)
2N/A{
2N/A int ret = 0;
2N/A int i, status;
2N/A ndmp_prop_t *cur_prop;
2N/A struct stat st;
2N/A char *p, *s, *psave;
2N/A
2N/A
2N/A /*
2N/A * Check to see if we are enabling authorization
2N/A * or cleartext
2N/A */
2N/A if ((strcasecmp(prop, "cram-md5-username") == 0) ||
2N/A (strcasecmp(prop, "cram-md5-password") == 0) ||
2N/A (strcasecmp(prop, "cleartext-username") == 0) ||
2N/A (strcasecmp(prop, "cleartext-password") == 0)) {
2N/A if (propval) {
2N/A return (ret);
2N/A } else {
2N/A ndmp_errno = ENDMP_INVALID_PROPVAL;
2N/A return (-1);
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * Scan the table for a matching ndmp property
2N/A */
2N/A for (i = 0; i < NDMPADM_NPROP; i++) {
2N/A if (strcasecmp(prop, prop_table[i].prop_name) == 0)
2N/A break;
2N/A }
2N/A if (i == NDMPADM_NPROP) {
2N/A /*
2N/A * The given property is not a valid ndmp property
2N/A */
2N/A ndmp_errno = ENDMP_INVALID_ARG;
2N/A ret = -1;
2N/A } else {
2N/A cur_prop = &prop_table[i];
2N/A if (cur_prop->prop_type == NDMP_PROP_BOOL) {
2N/A if (ndmp_isvalid_entry(propval, ndmp_bool_vals,
2N/A NBOOLS) != 0) {
2N/A /*
2N/A * Invalid BOOL property value
2N/A */
2N/A ndmp_errno = ENDMP_INVALID_PROPVAL;
2N/A ret = -1;
2N/A }
2N/A } else if (cur_prop->prop_type == NDMP_PROP_PATH) {
2N/A status = stat(propval, &st);
2N/A if (status != 0) {
2N/A /*
2N/A * The path given does not exist
2N/A */
2N/A ndmp_errno = ENDMP_ENOENT;
2N/A ret = -1;
2N/A }
2N/A } else if (cur_prop->prop_type == NDMP_PROP_PATH_LIST) {
2N/A p = psave = strdup(propval);
2N/A while (p) {
2N/A if ((s = strpbrk(p, " ,\t")) != NULL)
2N/A for (*s++ = 0; *s && IS_DELIM(*s); s++)
2N/A ;
2N/A if (*p && stat(p, &st) != 0) {
2N/A ndmp_errno = ENDMP_ENOENT;
2N/A ret = -1;
2N/A break;
2N/A }
2N/A
2N/A p = s;
2N/A }
2N/A free(psave);
2N/A } else if (cur_prop->prop_type == NDMP_PROP_DTYPE) {
2N/A if (ndmp_isvalid_entry(propval, ndmp_dtypes,
2N/A NDTYPES) != 0) {
2N/A /*
2N/A * Invalid drive type
2N/A */
2N/A ndmp_errno = ENDMP_INVALID_DTYPE;
2N/A ret = -1;
2N/A }
2N/A } else if (cur_prop->prop_type == NDMP_PROP_NUMERIC) {
2N/A if (ndmp_isvalid_numeric(prop, propval) != 0) {
2N/A /*
2N/A * Invalid numeric value
2N/A */
2N/A ndmp_errno = ENDMP_INVALID_PROPVAL;
2N/A ret = -1;
2N/A }
2N/A } else if (cur_prop->prop_type == NDMP_PROP_BACKUP_TYPE) {
2N/A if (ndmp_isvalid_entry(propval, ndmp_backuptypes,
2N/A NBTYPES) != 0) {
2N/A /*
2N/A * Invalid backup type specified. Default
2N/A * course of action is to set backup type
2N/A * to "off"
2N/A */
2N/A ndmp_errno = ENDMP_INVALID_PROPVAL;
2N/A (void) strncpy(propval, "off", 4);
2N/A }
2N/A } else if (cur_prop->prop_type ==
2N/A NDMP_PROP_ZFS_FORCE_OVERRIDE) {
2N/A if (ndmp_isvalid_entry(propval,
2N/A zfs_force_override_vals,
2N/A NZFS_FORCE_OVERRIDE_VALS) != 0) {
2N/A ndmp_errno = ENDMP_INVALID_PROPVAL;
2N/A ret = -1;
2N/A }
2N/A }
2N/A }
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * For property values that are numeric do a little more fine grained
2N/A * validation to make sure that the number is within range.
2N/A */
2N/Astatic int
2N/Andmp_isvalid_numeric(char *prop, char *propval)
2N/A{
2N/A int i;
2N/A int ret = 0;
2N/A long max_int = 0x7fffffff;
2N/A long pval = 0;
2N/A
2N/A /*
2N/A * Scan the string for any non-numeric chars
2N/A */
2N/A for (i = 0; i < strlen(propval); i++) {
2N/A if (!isdigit(propval[i])) {
2N/A return (-1);
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * Check for integer overflow
2N/A */
2N/A pval = strtol(propval, (char **)NULL, 10);
2N/A if (pval >= max_int) {
2N/A return (-1);
2N/A }
2N/A
2N/A /*
2N/A * Scan our prop limit table for the property we passed in. Once
2N/A * we find it, check to make sure it's within an acceptable range.
2N/A * If we don't find the property here in this table, it means that we
2N/A * are not imposing any range restrictions and will return success.
2N/A */
2N/A for (i = 0; i < NDMP_NPROPLIM; i++) {
2N/A if (strcasecmp(ndmp_proplims[i].prop, prop) == 0) {
2N/A if ((pval > ndmp_proplims[i].hi) ||
2N/A (pval < ndmp_proplims[i].lo)) {
2N/A ret = -1;
2N/A }
2N/A break;
2N/A }
2N/A }
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * Returns value of the specified variable/property. The return value is a
2N/A * string pointer to the locally allocated memory if the config param is
2N/A * defined otherwise it would be NULL.
2N/A */
2N/Aint
2N/Andmp_get_prop(char *prop, char **value)
2N/A{
2N/A ndmp_scfhandle_t *handle = NULL;
2N/A char *lval = (char *)malloc(NDMP_PROP_LEN);
2N/A char *pgname;
2N/A
2N/A if (!lval) {
2N/A ndmp_errno = ENDMP_MEM_ALLOC;
2N/A return (-1);
2N/A }
2N/A if ((handle = ndmp_smf_scf_init(NDMP_GROUP_FMRI_PREFIX)) == NULL) {
2N/A free(lval);
2N/A return (-1);
2N/A }
2N/A if (ndmp_smf_get_pg_name(handle, prop, &pgname)) {
2N/A free(lval);
2N/A ndmp_errno = ENDMP_SMF_PROP_GRP;
2N/A return (-1);
2N/A }
2N/A if (ndmp_smf_create_service_pgroup(handle, pgname)) {
2N/A ndmp_smf_scf_fini(handle);
2N/A free(lval);
2N/A return (-1);
2N/A }
2N/A if (ndmp_smf_get_property(handle, prop, lval, NDMP_PROP_LEN) != 0) {
2N/A ndmp_smf_scf_fini(handle);
2N/A free(lval);
2N/A ndmp_errno = ENDMP_SMF_PROP;
2N/A return (-1);
2N/A }
2N/A *value = lval;
2N/A ndmp_smf_scf_fini(handle);
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Andmp_set_prop(char *env, char *env_val)
2N/A{
2N/A ndmp_scfhandle_t *handle = NULL;
2N/A char lval[NDMP_PROP_LEN];
2N/A char *pgname;
2N/A
2N/A (void) strncpy(lval, env_val, NDMP_PROP_LEN);
2N/A
2N/A if ((handle = ndmp_smf_scf_init(NDMP_GROUP_FMRI_PREFIX)) == NULL)
2N/A return (-1);
2N/A
2N/A if (ndmp_smf_get_pg_name(handle, env, &pgname)) {
2N/A ndmp_errno = ENDMP_SMF_PROP_GRP;
2N/A return (-1);
2N/A }
2N/A
2N/A if (ndmp_smf_create_service_pgroup(handle, pgname))
2N/A return (-1);
2N/A
2N/A if (ndmp_smf_start_transaction(handle))
2N/A return (-1);
2N/A
2N/A if (env_val) {
2N/A /*
2N/A * Validate property values here. If either the property
2N/A * or the value itself is invalid, then return.
2N/A */
2N/A if (ndmp_validate_propval(env, lval) != 0) {
2N/A return (-1);
2N/A }
2N/A if (ndmp_smf_set_property(handle, env, lval)) {
2N/A return (-1);
2N/A }
2N/A } else {
2N/A if (ndmp_smf_delete_property(handle, env))
2N/A return (-1);
2N/A }
2N/A
2N/A if (ndmp_config_saveenv(handle) != 0)
2N/A return (-1);
2N/A
2N/A if (ndmp_errno != 0) {
2N/A return (-1);
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Andmp_smf_get_pg_name(ndmp_scfhandle_t *h, char *pname, char **pgname)
2N/A{
2N/A scf_value_t *value;
2N/A scf_property_t *prop;
2N/A int i;
2N/A
2N/A for (i = 0; i < NPG; i++) {
2N/A if (scf_service_get_pg(h->scf_service, ndmp_pg[i],
2N/A h->scf_pg) != 0)
2N/A return (-1);
2N/A
2N/A if ((value = scf_value_create(h->scf_handle)) == NULL)
2N/A return (-1);
2N/A
2N/A if ((prop = scf_property_create(h->scf_handle)) == NULL) {
2N/A scf_value_destroy(value);
2N/A return (-1);
2N/A }
2N/A /*
2N/A * This will fail if property does not exist in the property
2N/A * group. Check the next property group in case of failure.
2N/A */
2N/A if ((scf_pg_get_property(h->scf_pg, pname, prop)) != 0) {
2N/A scf_value_destroy(value);
2N/A scf_property_destroy(prop);
2N/A continue;
2N/A }
2N/A
2N/A *pgname = ndmp_pg[i];
2N/A scf_value_destroy(value);
2N/A scf_property_destroy(prop);
2N/A return (0);
2N/A }
2N/A return (-1);
2N/A}
2N/A
2N/A/*
2N/A * Basically commit the transaction.
2N/A */
2N/Astatic int
2N/Andmp_config_saveenv(ndmp_scfhandle_t *handle)
2N/A{
2N/A int ret = 0;
2N/A
2N/A ret = ndmp_smf_end_transaction(handle);
2N/A
2N/A ndmp_smf_scf_fini(handle);
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * Must be called when done. Called with the handle allocated in
2N/A * ndmp_smf_scf_init(), it cleans up the state and frees any SCF resources
2N/A * still in use.
2N/A */
2N/Astatic void
2N/Andmp_smf_scf_fini(ndmp_scfhandle_t *handle)
2N/A{
2N/A if (handle != NULL) {
2N/A scf_scope_destroy(handle->scf_scope);
2N/A scf_service_destroy(handle->scf_service);
2N/A scf_pg_destroy(handle->scf_pg);
2N/A handle->scf_state = NDMP_SCH_STATE_UNINIT;
2N/A (void) scf_handle_unbind(handle->scf_handle);
2N/A scf_handle_destroy(handle->scf_handle);
2N/A free(handle);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Must be called before using any of the SCF functions. Returns
2N/A * ndmp_scfhandle_t pointer if success.
2N/A */
2N/Astatic ndmp_scfhandle_t *
2N/Andmp_smf_scf_init(char *svc_name)
2N/A{
2N/A ndmp_scfhandle_t *handle;
2N/A
2N/A handle = (ndmp_scfhandle_t *)calloc(1, sizeof (ndmp_scfhandle_t));
2N/A if (handle != NULL) {
2N/A handle->scf_state = NDMP_SCH_STATE_INITIALIZING;
2N/A if (((handle->scf_handle =
2N/A scf_handle_create(SCF_VERSION)) != NULL) &&
2N/A (scf_handle_bind(handle->scf_handle) == 0)) {
2N/A if ((handle->scf_scope =
2N/A scf_scope_create(handle->scf_handle)) == NULL)
2N/A goto err;
2N/A
2N/A if (scf_handle_get_local_scope(handle->scf_handle,
2N/A handle->scf_scope) != 0)
2N/A goto err;
2N/A
2N/A if ((handle->scf_service =
2N/A scf_service_create(handle->scf_handle)) == NULL)
2N/A goto err;
2N/A
2N/A if (scf_scope_get_service(handle->scf_scope, svc_name,
2N/A handle->scf_service) != SCF_SUCCESS)
2N/A goto err;
2N/A
2N/A if ((handle->scf_pg =
2N/A scf_pg_create(handle->scf_handle)) == NULL)
2N/A goto err;
2N/A
2N/A handle->scf_state = NDMP_SCH_STATE_INIT;
2N/A } else {
2N/A goto err;
2N/A }
2N/A } else {
2N/A ndmp_errno = ENDMP_MEM_ALLOC;
2N/A handle = NULL;
2N/A }
2N/A return (handle);
2N/A
2N/A /* Error handling/unwinding */
2N/Aerr:
2N/A (void) ndmp_smf_scf_fini(handle);
2N/A ndmp_errno = ENDMP_SMF_INTERNAL;
2N/A return (NULL);
2N/A}
2N/A
2N/A/*
2N/A * Create a new property group at service level.
2N/A */
2N/Astatic int
2N/Andmp_smf_create_service_pgroup(ndmp_scfhandle_t *handle, char *pgroup)
2N/A{
2N/A int err;
2N/A
2N/A /*
2N/A * Only create a handle if it doesn't exist. It is ok to exist since
2N/A * the pg handle will be set as a side effect.
2N/A */
2N/A if (handle->scf_pg == NULL) {
2N/A if ((handle->scf_pg =
2N/A scf_pg_create(handle->scf_handle)) == NULL)
2N/A ndmp_errno = ENDMP_SMF_INTERNAL;
2N/A return (-1);
2N/A }
2N/A
2N/A /*
2N/A * If the pgroup exists, we are done. If it doesn't, then we need to
2N/A * actually add one to the service instance.
2N/A */
2N/A if (scf_service_get_pg(handle->scf_service,
2N/A pgroup, handle->scf_pg) != 0) {
2N/A /* Doesn't exist so create one */
2N/A if (scf_service_add_pg(handle->scf_service, pgroup,
2N/A SCF_GROUP_FRAMEWORK, 0, handle->scf_pg) != 0) {
2N/A err = scf_error();
2N/A switch (err) {
2N/A case SCF_ERROR_PERMISSION_DENIED:
2N/A ndmp_errno = ENDMP_SMF_PERM;
2N/A return (-1);
2N/A /* NOTREACHED */
2N/A break;
2N/A default:
2N/A ndmp_errno = ENDMP_SMF_INTERNAL;
2N/A return (-1);
2N/A /* NOTREACHED */
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Start transaction on current pg in handle. The pg could be service or
2N/A * instance level. Must be called after pg handle is obtained from create or
2N/A * get.
2N/A */
2N/Astatic int
2N/Andmp_smf_start_transaction(ndmp_scfhandle_t *handle)
2N/A{
2N/A /*
2N/A * Lookup the property group and create it if it doesn't already
2N/A * exist.
2N/A */
2N/A if (handle->scf_state == NDMP_SCH_STATE_INIT) {
2N/A if ((handle->scf_trans =
2N/A scf_transaction_create(handle->scf_handle)) != NULL) {
2N/A if (scf_transaction_start(handle->scf_trans,
2N/A handle->scf_pg) != 0) {
2N/A scf_transaction_destroy(handle->scf_trans);
2N/A handle->scf_trans = NULL;
2N/A ndmp_errno = ENDMP_SMF_INTERNAL;
2N/A return (-1);
2N/A }
2N/A } else {
2N/A ndmp_errno = ENDMP_SMF_INTERNAL;
2N/A return (-1);
2N/A }
2N/A }
2N/A if (scf_error() == SCF_ERROR_PERMISSION_DENIED) {
2N/A ndmp_errno = ENDMP_SMF_PERM;
2N/A return (-1);
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Commit the changes that were added to the transaction in the handle. Do all
2N/A * necessary cleanup.
2N/A */
2N/Astatic int
2N/Andmp_smf_end_transaction(ndmp_scfhandle_t *handle)
2N/A{
2N/A if (scf_transaction_commit(handle->scf_trans) < 0) {
2N/A ndmp_errno = ENDMP_SMF_INTERNAL;
2N/A return (-1);
2N/A }
2N/A
2N/A scf_transaction_destroy_children(handle->scf_trans);
2N/A scf_transaction_destroy(handle->scf_trans);
2N/A handle->scf_trans = NULL;
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Deletes property in current pg
2N/A */
2N/Astatic int
2N/Andmp_smf_delete_property(ndmp_scfhandle_t *handle, char *propname)
2N/A{
2N/A scf_transaction_entry_t *entry = NULL;
2N/A
2N/A /*
2N/A * Properties must be set in transactions and don't take effect until
2N/A * the transaction has been ended/committed.
2N/A */
2N/A if ((entry = scf_entry_create(handle->scf_handle)) != NULL) {
2N/A if (scf_transaction_property_delete(handle->scf_trans, entry,
2N/A propname) != 0) {
2N/A scf_entry_destroy(entry);
2N/A ndmp_errno = ENDMP_SMF_INTERNAL;
2N/A return (-1);
2N/A }
2N/A } else {
2N/A ndmp_errno = ENDMP_SMF_INTERNAL;
2N/A return (-1);
2N/A }
2N/A if ((scf_error()) == SCF_ERROR_PERMISSION_DENIED) {
2N/A ndmp_errno = ENDMP_SMF_PERM;
2N/A scf_entry_destroy(entry);
2N/A return (-1);
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Sets property in current pg
2N/A */
2N/Astatic int
2N/Andmp_smf_set_property(ndmp_scfhandle_t *handle,
2N/A char *propname, char *valstr)
2N/A{
2N/A int ret = 0;
2N/A scf_value_t *value = NULL;
2N/A scf_transaction_entry_t *entry = NULL;
2N/A scf_property_t *prop;
2N/A scf_type_t type;
2N/A int64_t valint;
2N/A uint8_t valbool;
2N/A
2N/A /*
2N/A * Properties must be set in transactions and don't take effect until
2N/A * the transaction has been ended/committed.
2N/A */
2N/A if (((value = scf_value_create(handle->scf_handle)) != NULL) &&
2N/A (entry = scf_entry_create(handle->scf_handle)) != NULL) {
2N/A if (((prop =
2N/A scf_property_create(handle->scf_handle)) != NULL) &&
2N/A ((scf_pg_get_property(handle->scf_pg, propname,
2N/A prop)) == 0)) {
2N/A if (scf_property_get_value(prop, value) == 0) {
2N/A type = scf_value_type(value);
2N/A if ((scf_transaction_property_change(
2N/A handle->scf_trans, entry, propname,
2N/A type) == 0) ||
2N/A (scf_transaction_property_new(
2N/A handle->scf_trans, entry, propname,
2N/A type) == 0)) {
2N/A switch (type) {
2N/A case SCF_TYPE_ASTRING:
2N/A if ((scf_value_set_astring(
2N/A value,
2N/A valstr)) != SCF_SUCCESS)
2N/A ret = -1;
2N/A break;
2N/A case SCF_TYPE_INTEGER:
2N/A valint = strtoll(valstr, 0, 0);
2N/A scf_value_set_integer(value,
2N/A valint);
2N/A break;
2N/A case SCF_TYPE_BOOLEAN:
2N/A if (strncmp(valstr, "yes", 3))
2N/A valbool = 0;
2N/A else
2N/A valbool = 1;
2N/A scf_value_set_boolean(value,
2N/A valbool);
2N/A break;
2N/A default:
2N/A ret = -1;
2N/A }
2N/A if (scf_entry_add_value(entry,
2N/A value) != 0) {
2N/A ret = -1;
2N/A scf_value_destroy(value);
2N/A }
2N/A /* The value is in the transaction */
2N/A value = NULL;
2N/A }
2N/A /* The entry is in the transaction */
2N/A entry = NULL;
2N/A } else {
2N/A ret = -1;
2N/A }
2N/A } else {
2N/A ret = -1;
2N/A }
2N/A } else {
2N/A ret = -1;
2N/A }
2N/A if (ret == -1) {
2N/A if ((scf_error() == SCF_ERROR_PERMISSION_DENIED))
2N/A ndmp_errno = ENDMP_SMF_PERM;
2N/A else
2N/A ndmp_errno = ENDMP_SMF_INTERNAL;
2N/A }
2N/A scf_value_destroy(value);
2N/A scf_entry_destroy(entry);
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * Gets a property value.upto sz size. Caller is responsible to have enough
2N/A * memory allocated.
2N/A */
2N/Astatic int
2N/Andmp_smf_get_property(ndmp_scfhandle_t *handle, char *propname,
2N/A char *valstr, size_t sz)
2N/A{
2N/A int ret = 0;
2N/A scf_value_t *value;
2N/A scf_property_t *prop;
2N/A scf_type_t type;
2N/A int64_t valint;
2N/A uint8_t valbool;
2N/A char valstrbuf[NDMP_PROP_LEN];
2N/A
2N/A if (((value = scf_value_create(handle->scf_handle)) != NULL) &&
2N/A ((prop = scf_property_create(handle->scf_handle)) != NULL) &&
2N/A (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
2N/A if (scf_property_get_value(prop, value) == 0) {
2N/A type = scf_value_type(value);
2N/A switch (type) {
2N/A case SCF_TYPE_ASTRING:
2N/A if (scf_value_get_astring(value, valstr,
2N/A sz) < 0) {
2N/A ret = -1;
2N/A }
2N/A break;
2N/A case SCF_TYPE_INTEGER:
2N/A if (scf_value_get_integer(value,
2N/A &valint) != 0) {
2N/A ret = -1;
2N/A break;
2N/A }
2N/A valstrbuf[NDMP_PROP_LEN - 1] = '\0';
2N/A (void) strncpy(valstr, lltostr(valint,
2N/A &valstrbuf[NDMP_PROP_LEN - 1]),
2N/A NDMP_PROP_LEN);
2N/A break;
2N/A case SCF_TYPE_BOOLEAN:
2N/A if (scf_value_get_boolean(value,
2N/A &valbool) != 0) {
2N/A ret = -1;
2N/A break;
2N/A }
2N/A if (valbool == 1)
2N/A (void) strncpy(valstr, "yes", 4);
2N/A else
2N/A (void) strncpy(valstr, "no", 3);
2N/A break;
2N/A default:
2N/A ret = -1;
2N/A }
2N/A } else {
2N/A ret = -1;
2N/A }
2N/A } else {
2N/A ret = -1;
2N/A }
2N/A scf_value_destroy(value);
2N/A scf_property_destroy(prop);
2N/A return (ret);
2N/A}