changeset 3393:660717ce3a70

6493258 sharemgr: *sharectl* usage is confusing 6494273 sharemgr: sharectl unable to set/get properties commented out from /etc/default/nfs 6494277 sharemgr: *sharectl* returns 0 when setting/getting invalid property 6497688 sharemgr: *sharectl* fails to set some of nfs properties 6506328 sharemgr: sharectl should do additional value checking for min/max properties
author dougm
date Tue, 09 Jan 2007 09:13:45 -0800
parents 2c3a1c7448cc
children b937d1aa5870
files usr/src/cmd/dfs.cmds/sharectl/sharectl.c usr/src/cmd/dfs.cmds/sharemgr/plugins/libshare_nfs.c usr/src/lib/libshare/common/libshare.c
diffstat 3 files changed, 199 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/dfs.cmds/sharectl/sharectl.c	Mon Jan 08 23:36:56 2007 -0800
+++ b/usr/src/cmd/dfs.cmds/sharectl/sharectl.c	Tue Jan 09 09:13:45 2007 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -100,13 +100,13 @@
 
 	switch (index) {
 	case USAGE_CTL_GET:
-	    ret = gettext("get [-h] -p property ... proto");
+	    ret = gettext("get [-h | -p property ...] proto");
 	    break;
 	case USAGE_CTL_SET:
 	    ret = gettext("set [-h] -p property=value ... proto");
 	    break;
 	case USAGE_CTL_STATUS:
-	    ret = gettext("status -h | proto...");
+	    ret = gettext("status [-h | proto ...]");
 	    break;
 	}
 	return (ret);
@@ -191,6 +191,7 @@
 			} else {
 			    (void) printf(gettext("%s: not defined\n"),
 						opt->optname);
+			    ret = SA_NO_SUCH_PROP;
 			}
 		    }
 		}
@@ -249,6 +250,7 @@
 	    propset = sa_proto_get_properties(proto);
 	    if (propset != NULL) {
 		sa_property_t prop;
+		int err;
 
 		if (optlist == NULL) {
 		    (void) printf(gettext("usage: %s\n"),
@@ -261,15 +263,28 @@
 		    for (opt = optlist; opt != NULL; opt = opt->next) {
 			prop = sa_get_protocol_property(propset, opt->optname);
 			if (prop != NULL) {
-			    ret = sa_set_protocol_property(prop, opt->optvalue);
-			    if (ret != SA_OK) {
+				/*
+				 * "err" is used in order to prevent
+				 * setting ret to SA_OK if there has
+				 * been a real error. We want to be
+				 * able to return an error status on
+				 * exit in that case. Error messages
+				 * are printed for each error, so we
+				 * only care on exit that there was an
+				 * error and not the specific error
+				 * value.
+				 */
+			    err = sa_set_protocol_property(prop, opt->optvalue);
+			    if (err != SA_OK) {
 				(void) printf(gettext("Could not set property"
-						" %s: %s\n"),
-					opt->optname, sa_errorstr(ret));
+							" %s: %s\n"),
+					opt->optname, sa_errorstr(err));
+				ret = err;
 			    }
 			} else {
 			    (void) printf(gettext("%s: not defined\n"),
 						opt->optname);
+			    ret = SA_NO_SUCH_PROP;
 			}
 		    }
 		}
@@ -322,11 +337,11 @@
 	    case '?':
 	    case 'h':
 		(void) printf(gettext("usage: %s\n"),
-				sc_get_usage(USAGE_CTL_SET));
+				sc_get_usage(USAGE_CTL_STATUS));
 		return (SA_OK);
 	    default:
 		(void) printf(gettext("usage: %s\n"),
-				sc_get_usage(USAGE_CTL_SET));
+				sc_get_usage(USAGE_CTL_STATUS));
 		return (SA_SYNTAX_ERR);
 	    }
 	}
--- a/usr/src/cmd/dfs.cmds/sharemgr/plugins/libshare_nfs.c	Mon Jan 08 23:36:56 2007 -0800
+++ b/usr/src/cmd/dfs.cmds/sharemgr/plugins/libshare_nfs.c	Tue Jan 09 09:13:45 2007 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -1852,8 +1852,13 @@
 /*
  * Protocol management functions
  *
- * properties defined in the default files are defined in
- * proto_option_defs for parsing and validation.
+ * Properties defined in the default files are defined in
+ * proto_option_defs for parsing and validation. If "other" and
+ * "compare" are set, then the value for this property should be
+ * compared against the property specified in "other" using the
+ * "compare" check (either <= or >=) in order to ensure that the
+ * values are in the correct range.  E.g. setting server_versmin
+ * higher than server_versmax should not be allowed.
  */
 
 struct proto_option_defs {
@@ -1869,6 +1874,10 @@
 	int32_t minval;
 	int32_t maxval;
 	char *file;
+	char *other;
+	int compare;
+#define	OPT_CMP_GE	0
+#define	OPT_CMP_LE	1
 	int (*check)(char *);
 } proto_options[] = {
 #define	PROTO_OPT_NFSD_SERVERS			0
@@ -1895,22 +1904,22 @@
 	{"nfs_server_versmin",
 	    "server_versmin", PROTO_OPT_NFS_SERVER_VERSMIN, OPT_TYPE_NUMBER,
 	    (int)NFS_VERSMIN_DEFAULT, SVC_NFSD|SVC_MOUNTD, NFS_VERSMIN,
-	    NFS_VERSMAX, NFSADMIN},
+	    NFS_VERSMAX, NFSADMIN, "server_versmax", OPT_CMP_LE},
 #define	PROTO_OPT_NFS_SERVER_VERSMAX		6
 	{"nfs_server_versmax",
 	    "server_versmax", PROTO_OPT_NFS_SERVER_VERSMAX, OPT_TYPE_NUMBER,
 	    (int)NFS_VERSMAX_DEFAULT, SVC_NFSD|SVC_MOUNTD, NFS_VERSMIN,
-	    NFS_VERSMAX, NFSADMIN},
+	    NFS_VERSMAX, NFSADMIN, "server_versmin", OPT_CMP_GE},
 #define	PROTO_OPT_NFS_CLIENT_VERSMIN		7
 	{"nfs_client_versmin",
 	    "client_versmin", PROTO_OPT_NFS_CLIENT_VERSMIN, OPT_TYPE_NUMBER,
 	    (int)NFS_VERSMIN_DEFAULT, NULL, NFS_VERSMIN, NFS_VERSMAX,
-	    NFSADMIN},
+	    NFSADMIN, "client_versmax", OPT_CMP_LE},
 #define	PROTO_OPT_NFS_CLIENT_VERSMAX		8
 	{"nfs_client_versmax",
 	    "client_versmax", PROTO_OPT_NFS_CLIENT_VERSMAX, OPT_TYPE_NUMBER,
 	    (int)NFS_VERSMAX_DEFAULT, NULL, NFS_VERSMIN, NFS_VERSMAX,
-	    NFSADMIN},
+	    NFSADMIN, "client_versmin", OPT_CMP_GE},
 #define	PROTO_OPT_NFS_SERVER_DELEGATION		9
 	{"nfs_server_delegation",
 	    "server_delegation", PROTO_OPT_NFS_SERVER_DELEGATION,
@@ -2046,7 +2055,8 @@
  * add_default()
  *
  * Add the default values for any property not defined in the parsing
- * of the default files.
+ * of the default files. Values are set according to their defined
+ * types.
  */
 
 static void
@@ -2066,11 +2076,23 @@
 				proto_options[i].defvalue.intval);
 		    prop = sa_create_property(proto_options[i].name, number);
 		    break;
+
 		case OPT_TYPE_BOOLEAN:
 		    prop = sa_create_property(proto_options[i].name,
 					proto_options[i].defvalue.intval ?
 					"true" : "false");
 		    break;
+
+		case OPT_TYPE_ONOFF:
+		    prop = sa_create_property(proto_options[i].name,
+					proto_options[i].defvalue.intval ?
+					"on" : "off");
+		    break;
+
+		default:
+		    /* treat as strings of zero length */
+		    prop = sa_create_property(proto_options[i].name, "");
+		    break;
 		}
 		if (prop != NULL)
 		    (void) sa_add_protocol_property(protoset, prop);
@@ -2312,54 +2334,163 @@
 }
 
 /*
+ * service_in_state(service, chkstate)
+ *
+ * Want to know if the specified service is in the desired state
+ * (chkstate) or not. Return true (1) if it is and false (0) if it
+ * isn't.
+ */
+static int
+service_in_state(char *service, const char *chkstate)
+{
+	char *state;
+	int ret = B_FALSE;
+
+	state = smf_get_state(service);
+	if (state != NULL) {
+	    /* got the state so get the equality for the return value */
+	    ret = strcmp(state, chkstate) == 0 ? B_TRUE : B_FALSE;
+	    free(state);
+	}
+	return (ret);
+}
+
+/*
  * restart_service(svcs)
  *
  * Walk through the bit mask of services that need to be restarted in
  * order to use the new property values. Some properties affect
- * multiple daemons.
+ * multiple daemons. Should only restart a service if it is currently
+ * enabled (online).
  */
 
 static void
 restart_service(uint32_t svcs)
 {
 	uint32_t mask;
+	int ret;
+	char *service;
+
 	for (mask = 1; svcs != 0; mask <<= 1) {
 	    switch (svcs & mask) {
 	    case SVC_LOCKD:
-		(void) smf_restart_instance(LOCKD);
+		service = LOCKD;
 		break;
 	    case SVC_STATD:
-		(void) smf_restart_instance(STATD);
+		service = STATD;
 		break;
 	    case SVC_NFSD:
-		(void) smf_restart_instance(NFSD);
+		service = NFSD;
 		break;
 	    case SVC_MOUNTD:
-		(void) smf_restart_instance(MOUNTD);
+		service = MOUNTD;
 		break;
 	    case SVC_NFS4CBD:
-		(void) smf_restart_instance(NFS4CBD);
+		service = NFS4CBD;
 		break;
 	    case SVC_NFSMAPID:
-		(void) smf_restart_instance(NFSMAPID);
+		service = NFSMAPID;
 		break;
 	    case SVC_RQUOTAD:
-		(void) smf_restart_instance(RQUOTAD);
+		service = RQUOTAD;
 		break;
 	    case SVC_NFSLOGD:
-		(void) smf_restart_instance(NFSLOGD);
+		service = NFSLOGD;
 		break;
+	    default:
+		continue;
+	    }
+
+		/*
+		 * Only attempt to restart the service if it is
+		 * currently running. In the future, it may be
+		 * desirable to use smf_refresh_instance if the NFS
+		 * services ever implement the refresh method.
+		 */
+	    if (service_in_state(service, SCF_STATE_STRING_ONLINE)) {
+		ret = smf_restart_instance(service);
+		/*
+		 * There are only a few SMF errors at this point, but
+		 * it is also possible that a bad value may have put
+		 * the service into maintenance if there wasn't an
+		 * SMF level error.
+		 */
+		if (ret != 0) {
+		    (void) fprintf(stderr,
+				gettext("%s failed to restart: %s\n"),
+				scf_strerror(scf_error()));
+		} else {
+			/*
+			 * Check whether it has gone to "maintenance"
+			 * mode or not. Maintenance implies something
+			 * went wrong.
+			 */
+		    if (service_in_state(service, SCF_STATE_STRING_MAINT)) {
+			(void) fprintf(stderr,
+					gettext("%s failed to restart\n"),
+					service);
+		    }
+		}
 	    }
 	    svcs &= ~mask;
 	}
 }
 
 /*
+ * nfs_minmax_check(name, value)
+ *
+ * Verify that the value for the property specified by index is valid
+ * relative to the opposite value in the case of a min/max variable.
+ * Currently, server_minvers/server_maxvers and
+ * client_minvers/client_maxvers are the only ones to check.
+ */
+
+static int
+nfs_minmax_check(int index, int value)
+{
+	int val;
+	char *pval;
+	sa_property_t prop;
+	sa_optionset_t opts;
+	int ret = B_TRUE;
+
+	if (proto_options[index].other != NULL) {
+	    /* have a property to compare against */
+	    opts = nfs_get_proto_set();
+	    prop = sa_get_property(opts, proto_options[index].other);
+		/*
+		 * If we don't find the property, assume default
+		 * values which will work since the max will be at the
+		 * max and the min at the min.
+		 */
+	    if (prop != NULL) {
+		pval = sa_get_property_attr(prop, "value");
+		if (pval != NULL) {
+		    val = strtoul(pval, NULL, 0);
+		    if (proto_options[index].compare == OPT_CMP_LE) {
+			ret = value <= val ? B_TRUE : B_FALSE;
+		    } else if (proto_options[index].compare == OPT_CMP_GE) {
+			ret = value >= val ? B_TRUE : B_FALSE;
+		    }
+		}
+	    }
+	}
+	return (ret);
+}
+
+/*
  * nfs_validate_proto_prop(index, name, value)
  *
  * Verify that the property specifed by name can take the new
  * value. This is a sanity check to prevent bad values getting into
- * the default files.
+ * the default files. All values need to be checked against what is
+ * allowed by their defined type. If a type isn't explicitly defined
+ * here, it is treated as a string.
+ *
+ * Note that OPT_TYPE_NUMBER will additionally check that the value is
+ * within the range specified and potentially against another property
+ * value as well as specified in the proto_options members other and
+ * compare.
  */
 
 static int
@@ -2381,17 +2512,32 @@
 		if (val < proto_options[index].minval ||
 		    val > proto_options[index].maxval)
 		    ret = SA_BAD_VALUE;
+		/*
+		 * For server_versmin/server_versmax and
+		 * client_versmin/client_versmax, the value of the
+		 * min(max) should be checked to be correct relative
+		 * to the current max(min).
+		 */
+		if (!nfs_minmax_check(index, val)) {
+		    ret = SA_BAD_VALUE;
+		}
 	    }
 	    break;
+
 	case OPT_TYPE_DOMAIN:
 		/*
-		 * needs to be a qualified domain so will have at least
-		 * one period and other characters on either side of it.
+		 * needs to be a qualified domain so will have at
+		 * least one period and other characters on either
+		 * side of it.  A zero length string is also allowed
+		 * and is the way to turn off the override.
 		 */
+	    if (strlen(value) == 0)
+		break;
 	    cp = strchr(value, '.');
-	    if (cp == NULL || cp == value ||strchr(value, '@') != NULL)
+	    if (cp == NULL || cp == value || strchr(value, '@') != NULL)
 		ret = SA_BAD_VALUE;
 	    break;
+
 	case OPT_TYPE_BOOLEAN:
 	    if (strlen(value) == 0 ||
 		strcasecmp(value, "true") == 0 ||
@@ -2403,17 +2549,24 @@
 		ret = SA_BAD_VALUE;
 	    }
 	    break;
+
 	case OPT_TYPE_ONOFF:
 	    if (strcasecmp(value, "on") != 0 &&
 		strcasecmp(value, "off") != 0) {
 		ret = SA_BAD_VALUE;
 	    }
 	    break;
+
 	case OPT_TYPE_PROTOCOL:
 	    if (strcasecmp(value, "all") != 0 &&
 		strcasecmp(value, "tcp") != 0 &&
 		strcasecmp(value, "udp") != 0)
 		ret = SA_BAD_VALUE;
+	    break;
+
+	default:
+	    /* treat as a string */
+	    break;
 	}
 	return (ret);
 }
--- a/usr/src/lib/libshare/common/libshare.c	Mon Jan 08 23:36:56 2007 -0800
+++ b/usr/src/lib/libshare/common/libshare.c	Tue Jan 09 09:13:45 2007 -0800
@@ -2656,7 +2656,7 @@
 	    if (proto != NULL) {
 		set_node_attr((xmlNodePtr)prop, "value", value);
 		ret = sa_proto_set_property(proto, prop);
-		sa_free_attr_string(prop);
+		sa_free_attr_string(proto);
 	    }
 	}
 	return (ret);