2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/*
2N/A * AUTOMOUNT specific functions
2N/A */
2N/A#include <stdio.h>
2N/A#include <string.h>
2N/A#include <ctype.h>
2N/A#include <stdlib.h>
2N/A#include <unistd.h>
2N/A#include <zone.h>
2N/A#include <errno.h>
2N/A#include <locale.h>
2N/A#include <fcntl.h>
2N/A#include <sys/types.h>
2N/A#include <sys/stat.h>
2N/A#include <syslog.h>
2N/A#include <pwd.h>
2N/A#include <limits.h>
2N/A#include <libscf.h>
2N/A#include <strings.h>
2N/A#include <libdlpi.h>
2N/A
2N/A#include <libshare.h>
2N/A#include <libshare_impl.h>
2N/A#include "smfcfg.h"
2N/A
2N/A/*
2N/A * protocol plugin op routines
2N/A */
2N/Astatic int sa_autofs_init(void);
2N/Astatic void sa_autofs_fini(void);
2N/A
2N/A/* protocol property op routines */
2N/Astatic int sa_autofs_proto_get_features(uint64_t *);
2N/Astatic int sa_autofs_proto_get_proplist(nvlist_t **);
2N/Astatic int sa_autofs_proto_get_status(char **);
2N/Astatic int sa_autofs_proto_get_property(const char *, const char *, char **);
2N/Astatic int sa_autofs_proto_set_property(const char *, const char *,
2N/A const char *);
2N/A
2N/A/* protocol property validator routines */
2N/Astatic int range_check_validator(int, char *);
2N/Astatic int true_false_validator(int, char *);
2N/Astatic int strlen_validator(int, char *);
2N/A
2N/Astatic void autofs_free_proto_proplist(void);
2N/A
2N/Asa_proto_ops_t sa_plugin_ops = {
2N/A .sap_hdr = {
2N/A .pi_ptype = SA_PLUGIN_PROTO,
2N/A .pi_type = SA_PROT_AUTOFS,
2N/A .pi_name = "autofs",
2N/A .pi_version = SA_LIBSHARE_VERSION,
2N/A .pi_flags = 0,
2N/A .pi_init = sa_autofs_init,
2N/A .pi_fini = sa_autofs_fini
2N/A },
2N/A .sap_share_parse = NULL,
2N/A .sap_share_merge = NULL,
2N/A .sap_share_set_def_proto = NULL,
2N/A .sap_share_validate_name = NULL,
2N/A .sap_share_validate = NULL,
2N/A .sap_share_publish = NULL,
2N/A .sap_share_unpublish = NULL,
2N/A .sap_share_unpublish_byname = NULL,
2N/A .sap_fs_publish = NULL,
2N/A .sap_fs_unpublish = NULL,
2N/A .sap_share_prop_format = NULL,
2N/A
2N/A .sap_proto_get_features = sa_autofs_proto_get_features,
2N/A .sap_proto_get_proplist = sa_autofs_proto_get_proplist,
2N/A .sap_proto_get_status = sa_autofs_proto_get_status,
2N/A .sap_proto_get_property = sa_autofs_proto_get_property,
2N/A .sap_proto_set_property = sa_autofs_proto_set_property,
2N/A .sap_proto_rem_section = NULL
2N/A};
2N/A
2N/A#define AUTOMOUNT_VERBOSE_DEFAULT 0
2N/A#define AUTOMOUNTD_VERBOSE_DEFAULT 0
2N/A#define AUTOMOUNT_NOBROWSE_DEFAULT 0
2N/A#define AUTOMOUNT_TIMEOUT_DEFAULT 600
2N/A#define AUTOMOUNT_TRACE_DEFAULT 0
2N/A
2N/A/*
2N/A * Protocol Management functions
2N/A */
2N/Astruct proto_option_defs {
2N/A char *tag;
2N/A char *name; /* display name -- remove protocol identifier */
2N/A int index;
2N/A scf_type_t type;
2N/A union {
2N/A int intval;
2N/A char *string;
2N/A } defvalue;
2N/A int32_t minval;
2N/A int32_t maxval;
2N/A int (*validator)(int, char *);
2N/A} autofs_proto_options[] = {
2N/A#define PROTO_OPT_AUTOMOUNT_TIMEOUT 0
2N/A { "timeout",
2N/A "timeout", PROTO_OPT_AUTOMOUNT_TIMEOUT,
2N/A SCF_TYPE_INTEGER, AUTOMOUNT_TIMEOUT_DEFAULT,
2N/A 1, INT32_MAX, range_check_validator},
2N/A#define PROTO_OPT_AUTOMOUNT_VERBOSE 1
2N/A { "automount_verbose",
2N/A "automount_verbose", PROTO_OPT_AUTOMOUNT_VERBOSE,
2N/A SCF_TYPE_BOOLEAN, AUTOMOUNT_VERBOSE_DEFAULT, 0, 1,
2N/A true_false_validator},
2N/A#define PROTO_OPT_AUTOMOUNTD_VERBOSE 2
2N/A { "automountd_verbose",
2N/A "automountd_verbose", PROTO_OPT_AUTOMOUNTD_VERBOSE,
2N/A SCF_TYPE_BOOLEAN, AUTOMOUNTD_VERBOSE_DEFAULT, 0, 1,
2N/A true_false_validator},
2N/A#define PROTO_OPT_AUTOMOUNTD_NOBROWSE 3
2N/A { "nobrowse",
2N/A "nobrowse", PROTO_OPT_AUTOMOUNTD_NOBROWSE, SCF_TYPE_BOOLEAN,
2N/A AUTOMOUNT_NOBROWSE_DEFAULT, 0, 1, true_false_validator},
2N/A#define PROTO_OPT_AUTOMOUNTD_TRACE 4
2N/A { "trace",
2N/A "trace", PROTO_OPT_AUTOMOUNTD_TRACE,
2N/A SCF_TYPE_INTEGER, AUTOMOUNT_TRACE_DEFAULT,
2N/A 0, 20, range_check_validator},
2N/A#define PROTO_OPT_AUTOMOUNTD_ENV 5
2N/A { "environment",
2N/A "environment", PROTO_OPT_AUTOMOUNTD_ENV, SCF_TYPE_ASTRING,
2N/A NULL, 0, 1024, strlen_validator},
2N/A {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
2N/A};
2N/A
2N/A#define AUTOFS_OPT_MAX PROTO_OPT_AUTOMOUNTD_ENV
2N/A
2N/Astatic nvlist_t *autofs_proto_proplist = NULL;
2N/A
2N/Astatic int
2N/Asa_autofs_init(void)
2N/A{
2N/A return (SA_OK);
2N/A}
2N/A
2N/Astatic void
2N/Asa_autofs_fini(void)
2N/A{
2N/A autofs_free_proto_proplist();
2N/A}
2N/A
2N/A/*
2N/A * service_in_state(service, chkstate)
2N/A *
2N/A * Want to know if the specified service is in the desired state
2N/A * (chkstate) or not. Return true (1) if it is and false (0) if it
2N/A * isn't.
2N/A */
2N/Astatic int
2N/Aservice_in_state(char *service, const char *chkstate)
2N/A{
2N/A char *state;
2N/A int ret = B_FALSE;
2N/A
2N/A state = smf_get_state(service);
2N/A if (state != NULL) {
2N/A /* got the state so get the equality for the return value */
2N/A ret = strcmp(state, chkstate) == 0 ? B_TRUE : B_FALSE;
2N/A free(state);
2N/A }
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * Only attempt to restart the service if it is
2N/A * currently running. In the future, it may be
2N/A * desirable to use smf_refresh_instance if the NFS
2N/A * services ever implement the refresh method.
2N/A */
2N/Astatic void
2N/Aautofs_restart_service(void)
2N/A{
2N/A char *service = AUTOFS_DEFAULT_FMRI;
2N/A int ret = -1;
2N/A
2N/A if (service_in_state(service, SCF_STATE_STRING_ONLINE)) {
2N/A ret = smf_restart_instance(service);
2N/A /*
2N/A * There are only a few SMF errors at this point, but
2N/A * it is also possible that a bad value may have put
2N/A * the service into maintenance if there wasn't an
2N/A * SMF level error.
2N/A */
2N/A if (ret != 0) {
2N/A (void) fprintf(stderr,
2N/A dgettext(TEXT_DOMAIN,
2N/A "%s failed to restart: %s\n"),
2N/A service, scf_strerror(scf_error()));
2N/A } else {
2N/A /*
2N/A * Check whether it has gone to "maintenance"
2N/A * mode or not. Maintenance implies something
2N/A * went wrong.
2N/A */
2N/A if (service_in_state(service, SCF_STATE_STRING_MAINT)) {
2N/A (void) fprintf(stderr,
2N/A dgettext(TEXT_DOMAIN,
2N/A "%s failed to restart\n"), service);
2N/A }
2N/A }
2N/A }
2N/A}
2N/A
2N/Astatic int
2N/Afindprotoopt(const char *propname)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; autofs_proto_options[i].tag != NULL; i++)
2N/A if (strcmp(autofs_proto_options[i].name, propname) == 0)
2N/A return (i);
2N/A return (-1);
2N/A}
2N/A
2N/Astatic int
2N/Ais_a_number(char *number)
2N/A{
2N/A int ret = 1;
2N/A int hex = 0;
2N/A
2N/A if (strncmp(number, "0x", 2) == 0) {
2N/A number += 2;
2N/A hex = 1;
2N/A } else if (*number == '-') {
2N/A number++; /* skip the minus */
2N/A }
2N/A
2N/A while (ret == 1 && *number != '\0') {
2N/A if (hex) {
2N/A ret = isxdigit(*number++);
2N/A } else {
2N/A ret = isdigit(*number++);
2N/A }
2N/A }
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/Astatic int
2N/Arange_check_validator(int index, char *value)
2N/A{
2N/A int ret = SA_OK;
2N/A if (!is_a_number(value)) {
2N/A ret = SA_INVALID_PROP_VAL;
2N/A } else {
2N/A int val;
2N/A val = strtoul(value, NULL, 0);
2N/A if (val < autofs_proto_options[index].minval ||
2N/A val > autofs_proto_options[index].maxval)
2N/A ret = SA_INVALID_PROP_VAL;
2N/A }
2N/A return (ret);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Atrue_false_validator(int index, char *value)
2N/A{
2N/A if ((strcasecmp(value, "true") == 0) ||
2N/A (strcasecmp(value, "false") == 0) ||
2N/A (strcmp(value, "1") == 0) ||
2N/A (strcmp(value, "0") == 0)) {
2N/A return (SA_OK);
2N/A }
2N/A return (SA_INVALID_PROP_VAL);
2N/A}
2N/A
2N/Astatic int
2N/Astrlen_validator(int index, char *value)
2N/A{
2N/A if (value == NULL) {
2N/A if (autofs_proto_options[index].minval == 0)
2N/A return (SA_OK);
2N/A else
2N/A return (SA_INVALID_PROP_VAL);
2N/A }
2N/A
2N/A if (strlen(value) > autofs_proto_options[index].maxval ||
2N/A strlen(value) < autofs_proto_options[index].minval)
2N/A return (SA_INVALID_PROP_VAL);
2N/A
2N/A return (SA_OK);
2N/A}
2N/A
2N/A/*
2N/A * autofs_validate_proto_prop(index, name, value)
2N/A *
2N/A * Verify that the property specifed by name can take the new
2N/A * value. This is a sanity check to prevent bad values getting into
2N/A * the default files.
2N/A */
2N/Astatic int
2N/Aautofs_validate_proto_prop(int index, const char *value)
2N/A{
2N/A if (index < 0 || index > AUTOFS_OPT_MAX)
2N/A return (SA_INVALID_PROP);
2N/A
2N/A if (autofs_proto_options[index].validator == NULL)
2N/A return (SA_OK);
2N/A
2N/A return (autofs_proto_options[index].validator(index, (char *)value));
2N/A}
2N/A
2N/Astatic void
2N/Aautofs_free_proto_proplist(void)
2N/A{
2N/A if (autofs_proto_proplist != NULL) {
2N/A nvlist_free(autofs_proto_proplist);
2N/A autofs_proto_proplist = NULL;
2N/A }
2N/A}
2N/A
2N/Astatic int
2N/Aautofs_add_default_value(int index)
2N/A{
2N/A char value[MAXDIGITS];
2N/A int ret;
2N/A
2N/A if (index < 0 || index > AUTOFS_OPT_MAX)
2N/A return (SA_INVALID_PROP);
2N/A
2N/A switch (autofs_proto_options[index].type) {
2N/A case SCF_TYPE_INTEGER:
2N/A (void) snprintf(value, sizeof (value), "%d",
2N/A autofs_proto_options[index].defvalue.intval);
2N/A break;
2N/A
2N/A case SCF_TYPE_BOOLEAN:
2N/A if (autofs_proto_options[index].defvalue.intval == 0)
2N/A (void) snprintf(value, sizeof (value), "false");
2N/A else
2N/A (void) snprintf(value, sizeof (value), "true");
2N/A break;
2N/A
2N/A case SCF_TYPE_ASTRING:
2N/A (void) snprintf(value, sizeof (value), "%s",
2N/A autofs_proto_options[index].defvalue.string != NULL ?
2N/A autofs_proto_options[index].defvalue.string : "");
2N/A break;
2N/A
2N/A default:
2N/A return (SA_INVALID_PROP);
2N/A }
2N/A
2N/A ret = nvlist_add_string(autofs_proto_proplist,
2N/A autofs_proto_options[index].name, value);
2N/A
2N/A return ((ret == 0) ? SA_OK : SA_NO_MEMORY);
2N/A}
2N/A
2N/Astatic int
2N/Aautofs_init_proto_proplist(void)
2N/A{
2N/A int i;
2N/A char name[PATH_MAX];
2N/A char value[PATH_MAX];
2N/A char *instance = NULL;
2N/A int bufsz = 0;
2N/A scf_type_t sctype;
2N/A int ret = SA_OK;
2N/A
2N/A autofs_free_proto_proplist();
2N/A
2N/A if (nvlist_alloc(&autofs_proto_proplist, NV_UNIQUE_NAME, 0) != 0)
2N/A return (SA_NO_MEMORY);
2N/A
2N/A for (i = 0; autofs_proto_options[i].tag != NULL; i++) {
2N/A bzero(value, PATH_MAX);
2N/A (void) strlcpy(name, autofs_proto_options[i].name, PATH_MAX);
2N/A sctype = autofs_proto_options[i].type;
2N/A bufsz = PATH_MAX;
2N/A ret = autofs_smf_get_prop(name, value, instance,
2N/A sctype, AUTOFS_FMRI, &bufsz);
2N/A if (ret == 0) {
2N/A /* add property to list */
2N/A ret = nvlist_add_string(autofs_proto_proplist,
2N/A name, value);
2N/A } else {
2N/A /* add default value to list */
2N/A ret = autofs_add_default_value(i);
2N/A }
2N/A
2N/A if (ret != 0) {
2N/A autofs_free_proto_proplist();
2N/A return (SA_NO_MEMORY);
2N/A }
2N/A }
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * sa_autofs_get_features
2N/A *
2N/A * return supported features
2N/A */
2N/Astatic int
2N/Asa_autofs_proto_get_features(uint64_t *features)
2N/A{
2N/A *features = SA_FEATURE_NONE;
2N/A return (SA_OK);
2N/A}
2N/A
2N/Astatic int
2N/Asa_autofs_proto_get_proplist(nvlist_t **proplist)
2N/A{
2N/A int ret;
2N/A
2N/A if (autofs_proto_proplist == NULL) {
2N/A if ((ret = autofs_init_proto_proplist()) != SA_OK) {
2N/A *proplist = NULL;
2N/A return (ret);
2N/A }
2N/A }
2N/A
2N/A if (nvlist_dup(autofs_proto_proplist, proplist, 0) == 0)
2N/A return (SA_OK);
2N/A else
2N/A return (SA_NO_MEMORY);
2N/A}
2N/A
2N/A/*
2N/A * sa_autofs_proto_get_status()
2N/A *
2N/A * What is the current status of the AUTOFS_DEFAULT_FMRI?
2N/A * We use the SMF state here.
2N/A * Caller must free the returned value.
2N/A */
2N/Astatic int
2N/Asa_autofs_proto_get_status(char **status_str)
2N/A{
2N/A *status_str = smf_get_state(AUTOFS_DEFAULT_FMRI);
2N/A if (*status_str == NULL &&
2N/A (*status_str = strdup("-")) == NULL)
2N/A return (SA_NO_MEMORY);
2N/A else
2N/A return (SA_OK);
2N/A}
2N/A
2N/A/*
2N/A * sa_autofs_proto_get_property
2N/A */
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Asa_autofs_proto_get_property(const char *sectname, const char *propname,
2N/A char **propval)
2N/A{
2N/A char *val;
2N/A
2N/A if (autofs_proto_proplist == NULL) {
2N/A if (autofs_init_proto_proplist() != SA_OK) {
2N/A *propval = NULL;
2N/A return (SA_NO_MEMORY);
2N/A }
2N/A }
2N/A
2N/A if (nvlist_lookup_string(autofs_proto_proplist, propname, &val) == 0) {
2N/A if ((*propval = strdup(val)) != NULL)
2N/A return (SA_OK);
2N/A else
2N/A return (SA_NO_MEMORY);
2N/A } else {
2N/A return (SA_NO_SUCH_PROP);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * sa_autofs_proto_set_property
2N/A */
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Asa_autofs_proto_set_property(const char *sectname, const char *propname,
2N/A const char *propval)
2N/A{
2N/A int index;
2N/A scf_type_t sctype;
2N/A int ret = SA_OK;
2N/A char *value = (char *)propval;
2N/A
2N/A if (propname == NULL)
2N/A return (SA_INVALID_PROP);
2N/A
2N/A if (propval == NULL)
2N/A return (SA_INVALID_PROP_VAL);
2N/A
2N/A if ((index = findprotoopt(propname)) < 0)
2N/A return (SA_INVALID_PROP);
2N/A
2N/A /* test for valid value */
2N/A ret = autofs_validate_proto_prop(index, propval);
2N/A if (ret == SA_OK) {
2N/A sctype = autofs_proto_options[index].type;
2N/A if (sctype == SCF_TYPE_BOOLEAN)
2N/A value = (string_to_boolean(propval)) ? "1" : "0";
2N/A ret = autofs_smf_set_prop((char *)propname, value, NULL, sctype,
2N/A AUTOFS_FMRI);
2N/A
2N/A if (ret == 0) {
2N/A autofs_restart_service();
2N/A (void) autofs_init_proto_proplist();
2N/A } else {
2N/A ret = SA_SCF_ERROR;
2N/A }
2N/A }
2N/A
2N/A return (ret);
2N/A}