/*
*/
/*
* BSD 3 Clause License
*
* Copyright (c) 2007, The Storage Networking Industry Association.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* distribution.
*
* - Neither the name of The Storage Networking Industry Association (SNIA)
* nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* NDMP configuration management
*/
#include <stdio.h>
#include <stdlib.h>
#include <synch.h>
#include <libintl.h>
#include <strings.h>
#include <libndmp.h>
#include <ctype.h>
/* NDMP properties configuration */
static char *ndmp_pg[] = {
"ndmpd",
"read"
};
/* Handle Init states */
#define NDMP_SCH_STATE_UNINIT 0
/* NDMP scf handle structure */
typedef struct ndmp_scfhandle {
int scf_state;
typedef enum {
typedef struct ndmp_prop {
char *prop_name;
} ndmp_prop_t;
{ "debug-path", NDMP_PROP_PATH },
{ "dump-pathnode", NDMP_PROP_BOOL },
{ "tar-pathnode", NDMP_PROP_BOOL },
{ "ignore-ctime", NDMP_PROP_BOOL },
{ "zfs-token-support", NDMP_PROP_BOOL },
{ "token-maxseq", NDMP_PROP_NUMERIC },
{ "version", NDMP_PROP_NUMERIC },
{ "dar-support", NDMP_PROP_BOOL },
{ "tcp-port", NDMP_PROP_NUMERIC },
{ "backup-quarantine", NDMP_PROP_BOOL },
{ "restore-quarantine", NDMP_PROP_BOOL },
{ "overwrite-quarantine", NDMP_PROP_BOOL },
{ "zfs-force-override", NDMP_PROP_ZFS_FORCE_OVERRIDE },
{ "drive-type", NDMP_PROP_DTYPE },
{ "type-override", NDMP_PROP_BACKUP_TYPE },
{ "cpu-binding", NDMP_PROP_BOOL },
{ "fs-export", NDMP_PROP_PATH_LIST }
};
static char *ndmp_bool_vals[] = {
"yes",
"no"
};
static char *ndmp_dtypes[] = {
"sysv",
"bsd"
};
static char *ndmp_backuptypes[] = {
"off",
"zfs"
};
static char *zfs_force_override_vals[] = {
"yes",
"no",
"off"
};
#define NZFS_FORCE_OVERRIDE_VALS \
(sizeof (zfs_force_override_vals) /\
sizeof (zfs_force_override_vals[0]))
static const struct {
char *prop;
int lo;
int hi;
} ndmp_proplims[] = {
{ "token-maxseq", 0, 64 },
{ "version", 2, 4 },
{ "tcp-port", 1, 65535 }
};
static int ndmp_validate_propval(char *, char *);
static int ndmp_isvalid_numeric(char *, char *);
static int ndmp_config_saveenv(ndmp_scfhandle_t *);
static ndmp_scfhandle_t *ndmp_smf_scf_init(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 *);
static int ndmp_smf_set_property(ndmp_scfhandle_t *, char *, char *);
static int ndmp_smf_create_service_pgroup(ndmp_scfhandle_t *, char *);
static int ndmp_smf_delete_property(ndmp_scfhandle_t *, char *);
static int ndmp_smf_get_pg_name(ndmp_scfhandle_t *, char *, char **);
/*
* This routine send a refresh signal to ndmpd service which cause ndmpd
* property table to be refeshed with current ndmpd properties value from SMF.
*/
int
ndmp_service_refresh(void)
{
return (smf_refresh_instance(NDMP_INST));
return (-1);
}
/*
* Scan list of current supported values.
*/
int
{
int ret = 0;
int i;
for (i = 0; i < ntypes; i++) {
break;
}
if (i == ntypes) {
ret = -1;
}
return (ret);
}
/*
* Given a property and an associated value, verify whether
* or not a.) it's a valid property and b.) if so, whether or not
* the respective value passed in is valid.
*/
static int
{
int ret = 0;
int i, status;
char *p, *s, *psave;
/*
* Check to see if we are enabling authorization
* or cleartext
*/
if (propval) {
return (ret);
} else {
return (-1);
}
}
/*
* Scan the table for a matching ndmp property
*/
for (i = 0; i < NDMPADM_NPROP; i++) {
break;
}
if (i == NDMPADM_NPROP) {
/*
* The given property is not a valid ndmp property
*/
ret = -1;
} else {
cur_prop = &prop_table[i];
NBOOLS) != 0) {
/*
* Invalid BOOL property value
*/
ret = -1;
}
if (status != 0) {
/*
* The path given does not exist
*/
ret = -1;
}
while (p) {
for (*s++ = 0; *s && IS_DELIM(*s); s++)
;
ret = -1;
break;
}
p = s;
}
NDTYPES) != 0) {
/*
* Invalid drive type
*/
ret = -1;
}
/*
* Invalid numeric value
*/
ret = -1;
}
NBTYPES) != 0) {
/*
* Invalid backup type specified. Default
* course of action is to set backup type
* to "off"
*/
}
NZFS_FORCE_OVERRIDE_VALS) != 0) {
ret = -1;
}
}
}
return (ret);
}
/*
* For property values that are numeric do a little more fine grained
* validation to make sure that the number is within range.
*/
static int
{
int i;
int ret = 0;
long pval = 0;
/*
* Scan the string for any non-numeric chars
*/
return (-1);
}
}
/*
* Check for integer overflow
*/
return (-1);
}
/*
* Scan our prop limit table for the property we passed in. Once
* we find it, check to make sure it's within an acceptable range.
* If we don't find the property here in this table, it means that we
* are not imposing any range restrictions and will return success.
*/
for (i = 0; i < NDMP_NPROPLIM; i++) {
ret = -1;
}
break;
}
}
return (ret);
}
/*
* string pointer to the locally allocated memory if the config param is
* defined otherwise it would be NULL.
*/
int
{
char *pgname;
if (!lval) {
return (-1);
}
return (-1);
}
return (-1);
}
return (-1);
}
return (-1);
}
return (0);
}
int
{
char *pgname;
return (-1);
return (-1);
}
return (-1);
return (-1);
if (env_val) {
/*
* Validate property values here. If either the property
* or the value itself is invalid, then return.
*/
return (-1);
}
return (-1);
}
} else {
return (-1);
}
if (ndmp_config_saveenv(handle) != 0)
return (-1);
if (ndmp_errno != 0) {
return (-1);
}
return (0);
}
static int
{
int i;
for (i = 0; i < NPG; i++) {
h->scf_pg) != 0)
return (-1);
return (-1);
return (-1);
}
/*
* This will fail if property does not exist in the property
* group. Check the next property group in case of failure.
*/
continue;
}
return (0);
}
return (-1);
}
/*
* Basically commit the transaction.
*/
static int
{
int ret = 0;
return (ret);
}
/*
* Must be called when done. Called with the handle allocated in
* ndmp_smf_scf_init(), it cleans up the state and frees any SCF resources
* still in use.
*/
static void
{
}
}
/*
* Must be called before using any of the SCF functions. Returns
* ndmp_scfhandle_t pointer if success.
*/
static ndmp_scfhandle_t *
{
if (((handle->scf_handle =
goto err;
goto err;
if ((handle->scf_service =
goto err;
goto err;
goto err;
} else {
goto err;
}
} else {
}
return (handle);
err:
(void) ndmp_smf_scf_fini(handle);
return (NULL);
}
/*
* Create a new property group at service level.
*/
static int
{
int err;
/*
* Only create a handle if it doesn't exist. It is ok to exist since
* the pg handle will be set as a side effect.
*/
return (-1);
}
/*
* If the pgroup exists, we are done. If it doesn't, then we need to
* actually add one to the service instance.
*/
/* Doesn't exist so create one */
switch (err) {
return (-1);
/* NOTREACHED */
break;
default:
return (-1);
/* NOTREACHED */
break;
}
}
}
return (0);
}
/*
* Start transaction on current pg in handle. The pg could be service or
* instance level. Must be called after pg handle is obtained from create or
* get.
*/
static int
{
/*
* Lookup the property group and create it if it doesn't already
* exist.
*/
return (-1);
}
} else {
return (-1);
}
}
if (scf_error() == SCF_ERROR_PERMISSION_DENIED) {
return (-1);
}
return (0);
}
/*
* Commit the changes that were added to the transaction in the handle. Do all
* necessary cleanup.
*/
static int
{
return (-1);
}
return (0);
}
/*
* Deletes property in current pg
*/
static int
{
/*
* Properties must be set in transactions and don't take effect until
*/
propname) != 0) {
return (-1);
}
} else {
return (-1);
}
if ((scf_error()) == SCF_ERROR_PERMISSION_DENIED) {
return (-1);
}
return (0);
}
/*
* Sets property in current pg
*/
static int
{
int ret = 0;
/*
* Properties must be set in transactions and don't take effect until
*/
if (((prop =
prop)) == 0)) {
type) == 0) ||
type) == 0)) {
switch (type) {
case SCF_TYPE_ASTRING:
if ((scf_value_set_astring(
valstr)) != SCF_SUCCESS)
ret = -1;
break;
case SCF_TYPE_INTEGER:
valint);
break;
case SCF_TYPE_BOOLEAN:
valbool = 0;
else
valbool = 1;
valbool);
break;
default:
ret = -1;
}
if (scf_entry_add_value(entry,
value) != 0) {
ret = -1;
}
/* The value is in the transaction */
}
/* The entry is in the transaction */
} else {
ret = -1;
}
} else {
ret = -1;
}
} else {
ret = -1;
}
if (ret == -1) {
if ((scf_error() == SCF_ERROR_PERMISSION_DENIED))
else
}
return (ret);
}
/*
* Gets a property value.upto sz size. Caller is responsible to have enough
* memory allocated.
*/
static int
{
int ret = 0;
switch (type) {
case SCF_TYPE_ASTRING:
sz) < 0) {
ret = -1;
}
break;
case SCF_TYPE_INTEGER:
&valint) != 0) {
ret = -1;
break;
}
break;
case SCF_TYPE_BOOLEAN:
&valbool) != 0) {
ret = -1;
break;
}
if (valbool == 1)
else
break;
default:
ret = -1;
}
} else {
ret = -1;
}
} else {
ret = -1;
}
return (ret);
}