#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <stdarg.h>
#include <nfs/nfs.h>
#include <rpcsvc/daemon_utils.h>
#include <sys/sysmacros.h>
#include "smfcfg.h"
static struct str_val {
const char *str;
uint32_t val;
} nfs_versions[] = {
{ "2", NFS_VERS_2 },
{ "3", NFS_VERS_3 },
{ "4", NFS_VERS_4 },
{ "4.0", NFS_VERS_4 },
{ "4.1", NFS_VERS_4_1 },
{ "4.2", NFS_VERS_4_2 }
};
uint32_t
nfs_convert_version_str(const char *version)
{
uint32_t v = 0;
for (size_t i = 0; i < ARRAY_SIZE(nfs_versions); i++) {
if (strcmp(version, nfs_versions[i].str) == 0) {
v = nfs_versions[i].val;
break;
}
}
return (v);
}
fs_smfhandle_t *
fs_smf_init(const char *fmri, const char *instance)
{
fs_smfhandle_t *handle = NULL;
char *svcname, srv[MAXPATHLEN];
(void) snprintf(srv, MAXPATHLEN, "%s", fmri + strlen("svc:/"));
svcname = strrchr(srv, ':');
if (svcname != NULL)
*svcname = '\0';
svcname = srv;
handle = calloc(1, sizeof (fs_smfhandle_t));
if (handle != NULL) {
handle->fs_handle = scf_handle_create(SCF_VERSION);
if (handle->fs_handle == NULL)
goto out;
if (scf_handle_bind(handle->fs_handle) != 0)
goto out;
handle->fs_service =
scf_service_create(handle->fs_handle);
handle->fs_scope =
scf_scope_create(handle->fs_handle);
if (scf_handle_get_local_scope(handle->fs_handle,
handle->fs_scope) != 0)
goto out;
if (scf_scope_get_service(handle->fs_scope,
svcname, handle->fs_service) != SCF_SUCCESS) {
goto out;
}
handle->fs_pg =
scf_pg_create(handle->fs_handle);
handle->fs_instance =
scf_instance_create(handle->fs_handle);
handle->fs_property =
scf_property_create(handle->fs_handle);
handle->fs_value =
scf_value_create(handle->fs_handle);
} else {
fprintf(stderr,
gettext("Cannot access SMF repository: %s\n"), fmri);
}
return (handle);
out:
fs_smf_fini(handle);
if (scf_error() != SCF_ERROR_NOT_FOUND) {
fprintf(stderr,
gettext("SMF Initialization problem(%s): %s\n"),
fmri, scf_strerror(scf_error()));
}
return (NULL);
}
void
fs_smf_fini(fs_smfhandle_t *handle)
{
if (handle != NULL) {
scf_scope_destroy(handle->fs_scope);
scf_instance_destroy(handle->fs_instance);
scf_service_destroy(handle->fs_service);
scf_pg_destroy(handle->fs_pg);
scf_property_destroy(handle->fs_property);
scf_value_destroy(handle->fs_value);
if (handle->fs_handle != NULL) {
(void) scf_handle_unbind(handle->fs_handle);
scf_handle_destroy(handle->fs_handle);
}
free(handle);
}
}
int
fs_smf_set_prop(smf_fstype_t fstype, char *prop_name, char *valbuf,
char *instance, scf_type_t sctype, char *fmri)
{
fs_smfhandle_t *phandle = NULL;
scf_handle_t *handle;
scf_propertygroup_t *pg;
scf_property_t *prop;
scf_transaction_t *tran = NULL;
scf_transaction_entry_t *entry = NULL;
scf_instance_t *inst;
scf_value_t *val;
int valint;
int ret = 0;
char *p = NULL;
char *svcname, srv[MAXPATHLEN];
const char *pgname;
(void) snprintf(srv, MAXPATHLEN, "%s", fmri);
p = strstr(fmri, ":default");
if (p == NULL) {
(void) strcat(srv, ":");
if (instance == NULL)
instance = "default";
if (strlen(srv) + strlen(instance) > MAXPATHLEN)
goto out;
(void) strncat(srv, instance, strlen(instance));
}
svcname = srv;
phandle = fs_smf_init(fmri, instance);
if (phandle == NULL) {
return (SMF_SYSTEM_ERR);
}
handle = phandle->fs_handle;
pg = phandle->fs_pg;
prop = phandle->fs_property;
inst = phandle->fs_instance;
val = phandle->fs_value;
tran = scf_transaction_create(handle);
entry = scf_entry_create(handle);
if (handle == NULL || pg == NULL || prop == NULL ||
val == NULL|| tran == NULL || entry == NULL || inst == NULL) {
ret = SMF_SYSTEM_ERR;
goto out;
}
if (scf_handle_decode_fmri(handle, svcname, phandle->fs_scope,
phandle->fs_service, inst, NULL, NULL, 0) != 0) {
ret = scf_error();
goto out;
}
if (fstype == AUTOFS_SMF)
pgname = AUTOFS_PROPS_PGNAME;
else
pgname = NFS_PROPS_PGNAME;
if (scf_instance_get_pg(inst, pgname,
pg) != -1) {
uint8_t vint;
if (scf_transaction_start(tran, pg) == -1) {
ret = scf_error();
goto out;
}
switch (sctype) {
case SCF_TYPE_INTEGER:
errno = 0;
valint = strtoul(valbuf, NULL, 0);
if (errno != 0) {
ret = SMF_SYSTEM_ERR;
goto out;
}
if (scf_transaction_property_change(tran,
entry, prop_name, SCF_TYPE_INTEGER) == 0) {
scf_value_set_integer(val, valint);
if (scf_entry_add_value(entry, val) < 0) {
ret = scf_error();
goto out;
}
}
break;
case SCF_TYPE_ASTRING:
if (scf_transaction_property_change(tran, entry,
prop_name, SCF_TYPE_ASTRING) == 0) {
if (scf_value_set_astring(val,
valbuf) == 0) {
if (scf_entry_add_value(entry,
val) != 0) {
ret = scf_error();
goto out;
}
} else
ret = SMF_SYSTEM_ERR;
} else
ret = SMF_SYSTEM_ERR;
break;
case SCF_TYPE_BOOLEAN:
if (strcmp(valbuf, "1") == 0) {
vint = 1;
} else if (strcmp(valbuf, "0") == 0) {
vint = 0;
} else {
ret = SMF_SYSTEM_ERR;
break;
}
if (scf_transaction_property_change(tran, entry,
prop_name, SCF_TYPE_BOOLEAN) == 0) {
scf_value_set_boolean(val, (uint8_t)vint);
if (scf_entry_add_value(entry, val) != 0) {
ret = scf_error();
goto out;
}
} else {
ret = SMF_SYSTEM_ERR;
}
break;
default:
break;
}
if (ret != SMF_SYSTEM_ERR)
(void) scf_transaction_commit(tran);
}
out:
if (tran != NULL)
scf_transaction_destroy(tran);
if (entry != NULL)
scf_entry_destroy(entry);
fs_smf_fini(phandle);
return (ret);
}
int
fs_smf_get_prop(smf_fstype_t fstype, char *prop_name, char *cbuf,
char *instance, scf_type_t sctype, char *fmri, int *bufsz)
{
fs_smfhandle_t *phandle = NULL;
scf_handle_t *handle;
scf_propertygroup_t *pg;
scf_property_t *prop;
scf_value_t *val;
scf_instance_t *inst;
int ret = 0, len = 0, length;
int64_t valint = 0;
char srv[MAXPATHLEN], *p, *svcname;
const char *pgname;
uint8_t bval;
(void) snprintf(srv, MAXPATHLEN, "%s", fmri);
p = strstr(fmri, ":default");
if (p == NULL) {
(void) strcat(srv, ":");
if (instance == NULL)
instance = "default";
if (strlen(srv) + strlen(instance) > MAXPATHLEN)
goto out;
(void) strncat(srv, instance, strlen(instance));
}
svcname = srv;
phandle = fs_smf_init(fmri, instance);
if (phandle == NULL)
return (SMF_SYSTEM_ERR);
handle = phandle->fs_handle;
pg = phandle->fs_pg;
inst = phandle->fs_instance;
prop = phandle->fs_property;
val = phandle->fs_value;
if (handle == NULL || pg == NULL || prop == NULL || val == NULL ||
inst == NULL) {
return (SMF_SYSTEM_ERR);
}
if (scf_handle_decode_fmri(handle, svcname, phandle->fs_scope,
phandle->fs_service, inst, NULL, NULL, 0) != 0) {
ret = scf_error();
goto out;
}
if (fstype == AUTOFS_SMF)
pgname = AUTOFS_PROPS_PGNAME;
else
pgname = NFS_PROPS_PGNAME;
if (scf_instance_get_pg(inst, pgname, pg) != -1) {
if (scf_pg_get_property(pg, prop_name,
prop) != SCF_SUCCESS) {
ret = scf_error();
goto out;
}
if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
ret = scf_error();
goto out;
}
switch (sctype) {
case SCF_TYPE_ASTRING:
len = scf_value_get_astring(val, cbuf, *bufsz);
if (len < 0 || len > *bufsz) {
ret = scf_error();
goto out;
}
ret = 0;
*bufsz = len;
break;
case SCF_TYPE_INTEGER:
if (scf_value_get_integer(val, &valint) != 0) {
ret = scf_error();
goto out;
}
length = snprintf(cbuf, *bufsz, "%lld", valint);
if (length < 0 || length > *bufsz) {
ret = SA_BAD_VALUE;
goto out;
}
ret = 0;
break;
case SCF_TYPE_BOOLEAN:
if (scf_value_get_boolean(val, &bval) != 0) {
ret = scf_error();
goto out;
}
if (bval == 1) {
length = snprintf(cbuf, *bufsz, "%s", "true");
} else {
length = snprintf(cbuf, *bufsz, "%s", "false");
}
if (length < 0 || length > *bufsz) {
ret = SA_BAD_VALUE;
goto out;
}
break;
default:
break;
}
} else {
ret = scf_error();
}
if ((ret != 0) && scf_error() != SCF_ERROR_NONE)
fprintf(stdout, gettext("%s\n"), scf_strerror(ret));
out:
fs_smf_fini(phandle);
return (ret);
}
int
nfs_smf_get_prop(char *prop_name, char *propbuf, char *instance,
scf_type_t sctype, char *svc_name, int *bufsz)
{
return (fs_smf_get_prop(NFS_SMF, prop_name, propbuf,
instance, sctype, svc_name, bufsz));
}
int
nfs_smf_get_iprop(char *prop_name, int *rvp, char *instance,
scf_type_t sctype, char *svc_name)
{
char propbuf[32];
int bufsz, rc, val;
bufsz = sizeof (propbuf);
rc = fs_smf_get_prop(NFS_SMF, prop_name, propbuf,
instance, sctype, svc_name, &bufsz);
if (rc != SA_OK)
return (rc);
errno = 0;
val = strtol(propbuf, NULL, 10);
if (errno != 0)
return (SA_BAD_VALUE);
*rvp = val;
return (SA_OK);
}
int
nfs_smf_set_prop(char *prop_name, char *value, char *instance,
scf_type_t type, char *svc_name)
{
return (fs_smf_set_prop(NFS_SMF, prop_name, value, instance,
type, svc_name));
}
int
autofs_smf_set_prop(char *prop_name, char *value, char *instance,
scf_type_t type, char *svc_name)
{
return (fs_smf_set_prop(AUTOFS_SMF, prop_name, value, instance,
type, svc_name));
}
int
autofs_smf_get_prop(char *prop_name, char *propbuf, char *instance,
scf_type_t sctype, char *svc_name, int *bufsz)
{
return (fs_smf_get_prop(AUTOFS_SMF, prop_name, propbuf,
instance, sctype, svc_name, bufsz));
}
boolean_t
string_to_boolean(const char *str)
{
if (strcasecmp(str, "true") == 0 || atoi(str) == 1 ||
strcasecmp(str, "on") == 0 || strcasecmp(str, "yes") == 0) {
return (B_TRUE);
} else
return (B_FALSE);
}
static void
nfs_upgrade_server_vers(const char *fmri)
{
fs_smfhandle_t *phandle;
scf_handle_t *handle;
scf_propertygroup_t *pg;
scf_instance_t *inst;
scf_value_t *vmin = NULL, *vmax = NULL;
scf_transaction_t *tran = NULL;
scf_transaction_entry_t *emin = NULL, *emax = NULL;
char versmax[32];
char versmin[32];
int bufsz;
bufsz = sizeof (versmax);
if (nfs_smf_get_prop("server_versmax", versmax, DEFAULT_INSTANCE,
SCF_TYPE_INTEGER, (char *)fmri, &bufsz) != SA_OK) {
return;
}
bufsz = sizeof (versmin);
if (nfs_smf_get_prop("server_versmin", versmin, DEFAULT_INSTANCE,
SCF_TYPE_INTEGER, (char *)fmri, &bufsz) != SA_OK) {
return;
}
phandle = fs_smf_init(fmri, NULL);
if (phandle == NULL)
return;
handle = phandle->fs_handle;
if (handle == NULL)
goto done;
pg = phandle->fs_pg;
inst = phandle->fs_instance;
tran = scf_transaction_create(handle);
vmin = scf_value_create(handle);
vmax = scf_value_create(handle);
emin = scf_entry_create(handle);
emax = scf_entry_create(handle);
if (pg == NULL || inst == NULL || tran == NULL ||
emin == NULL || emax == NULL || vmin == NULL || vmax == NULL) {
goto done;
}
if (scf_handle_decode_fmri(handle, (char *)fmri,
phandle->fs_scope, phandle->fs_service, inst, NULL, NULL, 0) != 0) {
goto done;
}
if (scf_instance_get_pg(inst, NFS_PROPS_PGNAME, pg) == -1)
goto done;
if (scf_pg_update(pg) == -1)
goto done;
if (scf_transaction_start(tran, pg) == -1)
goto done;
if (scf_transaction_property_change_type(tran, emax,
"server_versmax", SCF_TYPE_ASTRING) != 0) {
goto done;
}
if (scf_value_set_astring(vmax, versmax) == 0) {
if (scf_entry_add_value(emax, vmax) != 0)
goto done;
} else {
goto done;
}
if (scf_transaction_property_change_type(tran, emin,
"server_versmin", SCF_TYPE_ASTRING) != 0) {
goto done;
}
if (scf_value_set_astring(vmin, versmin) == 0) {
if (scf_entry_add_value(emin, vmin) != 0)
goto done;
} else {
goto done;
}
(void) scf_transaction_commit(tran);
done:
if (tran != NULL)
scf_transaction_destroy(tran);
if (emin != NULL)
scf_entry_destroy(emin);
if (emax != NULL)
scf_entry_destroy(emax);
if (vmin != NULL)
scf_value_destroy(vmin);
if (vmax != NULL)
scf_value_destroy(vmax);
fs_smf_fini(phandle);
}
void
nfs_config_upgrade(const char *svc_name)
{
if (strcmp(svc_name, NFSD) == 0) {
nfs_upgrade_server_vers(svc_name);
}
}