#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <zone.h>
#include <errno.h>
#include <locale.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <syslog.h>
#include "libshare.h"
#include "libshare_impl.h"
#include <pwd.h>
#include <limits.h>
#include <libscf.h>
#include <strings.h>
#include <libdlpi.h>
#include "smfcfg.h"
static int autofs_init();
static void autofs_fini();
static int autofs_validate_property(sa_handle_t, sa_property_t, sa_optionset_t);
static int autofs_set_proto_prop(sa_property_t);
static sa_protocol_properties_t autofs_get_proto_set();
static char *autofs_get_status();
static uint64_t autofs_features();
static int initautofsprotofromsmf();
static int true_false_validator(int index, char *value);
static int strlen_validator(int index, char *value);
static int range_check_validator(int index, char *value);
struct sa_plugin_ops sa_plugin_ops = {
SA_PLUGIN_VERSION,
"autofs",
autofs_init,
autofs_fini,
NULL,
NULL,
autofs_validate_property,
NULL,
NULL,
NULL,
NULL,
autofs_set_proto_prop,
autofs_get_proto_set,
autofs_get_status,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
autofs_features,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
};
static sa_protocol_properties_t protoset;
#define AUTOMOUNT_VERBOSE_DEFAULT 0
#define AUTOMOUNTD_VERBOSE_DEFAULT 0
#define AUTOMOUNT_NOBROWSE_DEFAULT 0
#define AUTOMOUNT_TIMEOUT_DEFAULT 600
#define AUTOMOUNT_TRACE_DEFAULT 0
struct proto_option_defs {
char *tag;
char *name;
int index;
scf_type_t type;
union {
int intval;
char *string;
} defvalue;
int32_t minval;
int32_t maxval;
int (*check)(int, char *);
} proto_options[] = {
#define PROTO_OPT_AUTOMOUNT_TIMEOUT 0
{ "timeout",
"timeout", PROTO_OPT_AUTOMOUNT_TIMEOUT,
SCF_TYPE_INTEGER, AUTOMOUNT_TIMEOUT_DEFAULT,
1, INT32_MAX, range_check_validator},
#define PROTO_OPT_AUTOMOUNT_VERBOSE 1
{ "automount_verbose",
"automount_verbose", PROTO_OPT_AUTOMOUNT_VERBOSE,
SCF_TYPE_BOOLEAN, AUTOMOUNT_VERBOSE_DEFAULT, 0, 1,
true_false_validator},
#define PROTO_OPT_AUTOMOUNTD_VERBOSE 2
{ "automountd_verbose",
"automountd_verbose", PROTO_OPT_AUTOMOUNTD_VERBOSE,
SCF_TYPE_BOOLEAN, AUTOMOUNTD_VERBOSE_DEFAULT, 0, 1,
true_false_validator},
#define PROTO_OPT_AUTOMOUNTD_NOBROWSE 3
{ "nobrowse",
"nobrowse", PROTO_OPT_AUTOMOUNTD_NOBROWSE, SCF_TYPE_BOOLEAN,
AUTOMOUNT_NOBROWSE_DEFAULT, 0, 1, true_false_validator},
#define PROTO_OPT_AUTOMOUNTD_TRACE 4
{ "trace",
"trace", PROTO_OPT_AUTOMOUNTD_TRACE,
SCF_TYPE_INTEGER, AUTOMOUNT_TRACE_DEFAULT,
0, 20, range_check_validator},
#define PROTO_OPT_AUTOMOUNTD_ENV 5
{ "environment",
"environment", PROTO_OPT_AUTOMOUNTD_ENV, SCF_TYPE_ASTRING,
0, 0, 1024, strlen_validator},
{NULL, NULL, 0, 0, 0, 0, 0, NULL}
};
#define AUTOFS_PROP_MAX (sizeof (proto_options) / sizeof (proto_options[0]))
static void
add_defaults()
{
int i;
char number[MAXDIGITS];
for (i = 0; proto_options[i].tag != NULL; i++) {
sa_property_t prop;
prop = sa_get_protocol_property(protoset,
proto_options[i].name);
if (prop == NULL) {
switch (proto_options[i].type) {
case SCF_TYPE_INTEGER:
(void) snprintf(number, sizeof (number), "%d",
proto_options[i].defvalue.intval);
prop = sa_create_property(proto_options[i].name,
number);
break;
case SCF_TYPE_BOOLEAN:
prop = sa_create_property(proto_options[i].name,
proto_options[i].defvalue.intval ?
"true" : "false");
break;
default:
prop = sa_create_property(proto_options[i].name,
"");
break;
}
if (prop != NULL)
(void) sa_add_protocol_property(protoset, prop);
}
}
}
static int
autofs_init()
{
int ret = SA_OK;
if (sa_plugin_ops.sa_init != autofs_init) {
(void) printf(dgettext(TEXT_DOMAIN,
"AUTOFS plugin not installed properly\n"));
return (SA_CONFIG_ERR);
}
ret = initautofsprotofromsmf();
if (ret != SA_OK) {
(void) printf(dgettext(TEXT_DOMAIN,
"AUTOFS plugin problem with SMF properties: %s\n"),
sa_errorstr(ret));
ret = SA_OK;
}
add_defaults();
return (ret);
}
static void
free_protoprops()
{
if (protoset != NULL) {
xmlFreeNode(protoset);
protoset = NULL;
}
}
static void
autofs_fini()
{
free_protoprops();
}
static int
findprotoopt(char *propname)
{
int i;
for (i = 0; proto_options[i].tag != NULL; i++)
if (strcmp(proto_options[i].name, propname) == 0)
return (i);
return (-1);
}
static int
autofs_validate_property(sa_handle_t handle, sa_property_t property,
sa_optionset_t parent)
{
int ret = SA_OK;
char *propname;
int optionindex;
char *value;
#ifdef lint
handle = handle;
parent = parent;
#endif
propname = sa_get_property(property, "type");
if (propname == NULL)
return (SA_NO_SUCH_PROP);
if ((optionindex = findprotoopt(propname)) < 0)
ret = SA_NO_SUCH_PROP;
if (ret != SA_OK) {
if (propname != NULL)
sa_free_attr_string(propname);
return (ret);
}
value = sa_get_property_attr(property, "value");
if (value != NULL) {
switch (proto_options[optionindex].type) {
case SCF_TYPE_INTEGER:
case SCF_TYPE_BOOLEAN:
case SCF_TYPE_ASTRING:
ret = proto_options[optionindex].check(optionindex,
value);
break;
default:
break;
}
}
if (value != NULL)
sa_free_attr_string(value);
if (propname != NULL)
sa_free_attr_string(propname);
return (ret);
}
static int
service_in_state(char *service, const char *chkstate)
{
char *state;
int ret = B_FALSE;
state = smf_get_state(service);
if (state != NULL) {
ret = strcmp(state, chkstate) == 0 ? B_TRUE : B_FALSE;
free(state);
}
return (ret);
}
static void
restart_service(char *service)
{
int ret = -1;
if (service_in_state(service, SCF_STATE_STRING_ONLINE)) {
ret = smf_restart_instance(service);
if (ret != 0) {
(void) fprintf(stderr,
dgettext(TEXT_DOMAIN,
"%s failed to restart: %s\n"),
scf_strerror(scf_error()));
} else {
if (service_in_state(service,
SCF_STATE_STRING_MAINT)) {
(void) fprintf(stderr,
dgettext(TEXT_DOMAIN,
"%s failed to restart\n"),
service);
}
}
}
}
static int
is_a_number(char *number)
{
int ret = 1;
int hex = 0;
if (strncmp(number, "0x", 2) == 0) {
number += 2;
hex = 1;
} else if (*number == '-') {
number++;
}
while (ret == 1 && *number != '\0') {
if (hex) {
ret = isxdigit(*number++);
} else {
ret = isdigit(*number++);
}
}
return (ret);
}
static void
fixcaselower(char *str)
{
while (*str) {
*str = tolower(*str);
str++;
}
}
static char *
skipwhitespace(char *str)
{
while (*str && isspace(*str))
str++;
return (str);
}
static int
extractprop(char *name, char *value)
{
sa_property_t prop;
int index;
int ret = SA_OK;
name = skipwhitespace(name);
index = findprotoopt(name);
if (index >= 0) {
fixcaselower(name);
prop = sa_create_property(proto_options[index].name, value);
if (prop != NULL)
ret = sa_add_protocol_property(protoset, prop);
else
ret = SA_NO_MEMORY;
}
return (ret);
}
static int
initautofsprotofromsmf(void)
{
char name[PATH_MAX];
char value[PATH_MAX];
int ret = SA_OK, bufsz = 0, i;
char *instance = NULL;
scf_type_t sctype;
protoset = sa_create_protocol_properties("autofs");
if (protoset != NULL) {
for (i = 0; proto_options[i].tag != NULL; i++) {
bzero(value, PATH_MAX);
(void) strncpy(name, proto_options[i].name, PATH_MAX);
sctype = proto_options[i].type;
bufsz = PATH_MAX;
ret = autofs_smf_get_prop(name, value,
instance, sctype, AUTOFS_FMRI, &bufsz);
if (ret == SA_OK) {
ret = extractprop(name, value);
}
}
} else {
ret = SA_NO_MEMORY;
}
return (ret);
}
static int
range_check_validator(int index, char *value)
{
int ret = SA_OK;
if (!is_a_number(value)) {
ret = SA_BAD_VALUE;
} else {
int val;
errno = 0;
val = strtoul(value, NULL, 0);
if (errno != 0)
return (SA_BAD_VALUE);
if (val < proto_options[index].minval ||
val > proto_options[index].maxval)
ret = SA_BAD_VALUE;
}
return (ret);
}
static int
true_false_validator(int index, char *value)
{
#ifdef lint
index = index;
#endif
if ((strcasecmp(value, "true") == 0) ||
(strcasecmp(value, "on") == 0) ||
(strcasecmp(value, "yes") == 0) ||
(strcmp(value, "1") == 0) ||
(strcasecmp(value, "false") == 0) ||
(strcasecmp(value, "off") == 0) ||
(strcasecmp(value, "no") == 0) ||
(strcmp(value, "0") == 0)) {
return (SA_OK);
}
return (SA_BAD_VALUE);
}
static int
strlen_validator(int index, char *value)
{
int ret = SA_OK;
if (value == NULL) {
if (proto_options[index].minval == 0) {
return (ret);
} else {
return (SA_BAD_VALUE);
}
}
if (strlen(value) > proto_options[index].maxval ||
strlen(value) < proto_options[index].minval)
ret = SA_BAD_VALUE;
return (ret);
}
static int
autofs_validate_proto_prop(int index, char *name, char *value)
{
#ifdef lint
name = name;
#endif
return (proto_options[index].check(index, value));
}
static int
autofs_set_proto_prop(sa_property_t prop)
{
int ret = SA_OK;
char *name;
char *value, *instance = NULL;
scf_type_t sctype;
name = sa_get_property_attr(prop, "type");
value = sa_get_property_attr(prop, "value");
if (name != NULL && value != NULL) {
int index = findprotoopt(name);
if (index >= 0) {
ret = autofs_validate_proto_prop(index, name, value);
if (ret == SA_OK) {
sctype = proto_options[index].type;
if (sctype == SCF_TYPE_BOOLEAN) {
if (value != NULL)
sa_free_attr_string(value);
if (string_to_boolean(value) == 0)
value = strdup("0");
else
value = strdup("1");
}
ret = autofs_smf_set_prop(name, value,
instance, sctype, AUTOFS_FMRI);
if (ret == SA_OK)
restart_service(AUTOFS_DEFAULT_FMRI);
}
} else {
ret = SA_NO_SUCH_PROP;
}
} else {
ret = SA_CONFIG_ERR;
}
if (name != NULL)
sa_free_attr_string(name);
if (value != NULL)
sa_free_attr_string(value);
return (ret);
}
static sa_protocol_properties_t
autofs_get_proto_set(void)
{
return (protoset);
}
static uint64_t
autofs_features(void)
{
return (0);
}
static char *
autofs_get_status(void)
{
return (smf_get_state(AUTOFS_DEFAULT_FMRI));
}