Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 9 Mar 2018 23:37:19 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r330711 - head/sbin/sysctl
Message-ID:  <201803092337.w29NbJSX093826@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Fri Mar  9 23:37:19 2018
New Revision: 330711
URL: https://svnweb.freebsd.org/changeset/base/330711

Log:
  Permit sysctl(8) to set an array of numeric values for a single node.
  
  Most sysctl nodes only return a single value, but some nodes return an
  array of values (e.g. kern.cp_time).  sysctl(8) understand how to display
  the values of a node that returns multiple values (it prints out each
  numeric value separated by spaces).  However, until now sysctl(8) has
  only been able to set sysctl nodes to a single value.  This change
  allows sysctl to accept a new value for a numeric sysctl node that contains
  multiple values separated by either spaces or commas.  sysctl(8) parses
  this list into an array of values and passes the array as the "new" value
  to sysctl(2).
  
  Reviewed by:	rpokala
  MFC after:	1 week
  Sponsored by:	Chelsio Communications
  Differential Revision:	https://reviews.freebsd.org/D14569

Modified:
  head/sbin/sysctl/sysctl.8
  head/sbin/sysctl/sysctl.c

Modified: head/sbin/sysctl/sysctl.8
==============================================================================
--- head/sbin/sysctl/sysctl.8	Fri Mar  9 23:25:18 2018	(r330710)
+++ head/sbin/sysctl/sysctl.8	Fri Mar  9 23:37:19 2018	(r330711)
@@ -28,7 +28,7 @@
 .\"	From: @(#)sysctl.8	8.1 (Berkeley) 6/6/93
 .\" $FreeBSD$
 .\"
-.Dd December 10, 2015
+.Dd March 9, 2018
 .Dt SYSCTL 8
 .Os
 .Sh NAME
@@ -39,7 +39,7 @@
 .Op Fl bdehiNnoRTtqx
 .Op Fl B Ar bufsize
 .Op Fl f Ar filename
-.Ar name Ns Op = Ns Ar value
+.Ar name Ns Op = Ns Ar value Ns Op , Ns Ar value
 .Ar ...
 .Nm
 .Op Fl bdehNnoRTtqx

Modified: head/sbin/sysctl/sysctl.c
==============================================================================
--- head/sbin/sysctl/sysctl.c	Fri Mar  9 23:25:18 2018	(r330710)
+++ head/sbin/sysctl/sysctl.c	Fri Mar  9 23:37:19 2018	(r330711)
@@ -65,6 +65,7 @@ static const char rcsid[] =
 #include <errno.h>
 #include <inttypes.h>
 #include <locale.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -234,16 +235,17 @@ main(int argc, char **argv)
 }
 
 /*
- * Parse a name into a MIB entry.
- * Lookup and print out the MIB entry if it exists.
- * Set a new value if requested.
+ * Parse a single numeric value, append it to 'newbuf', and update
+ * 'newsize'.  Returns true if the value was parsed and false if the
+ * value was invalid.  Non-numeric types (strings) are handled
+ * directly in parse().
  */
-static int
-parse(const char *string, int lineno)
+static bool
+parse_numeric(const char *newvalstr, const char *fmt, u_int kind,
+    void **newbufp, size_t *newsizep)
 {
-	int len, i, j;
+	void *newbuf;
 	const void *newval;
-	const char *newvalstr = NULL;
 	int8_t i8val;
 	uint8_t u8val;
 	int16_t i16val;
@@ -254,11 +256,111 @@ parse(const char *string, int lineno)
 	unsigned int uintval;
 	long longval;
 	unsigned long ulongval;
-	size_t newsize = Bflag;
 	int64_t i64val;
 	uint64_t u64val;
+	size_t valsize;
+	char *endptr = NULL;
+	
+	errno = 0;
+
+	switch (kind & CTLTYPE) {
+	case CTLTYPE_INT:
+		if (strncmp(fmt, "IK", 2) == 0)
+			intval = strIKtoi(newvalstr, &endptr, fmt);
+		else
+			intval = (int)strtol(newvalstr, &endptr, 0);
+		newval = &intval;
+		valsize = sizeof(intval);
+		break;
+	case CTLTYPE_UINT:
+		uintval = (int) strtoul(newvalstr, &endptr, 0);
+		newval = &uintval;
+		valsize = sizeof(uintval);
+		break;
+	case CTLTYPE_LONG:
+		longval = strtol(newvalstr, &endptr, 0);
+		newval = &longval;
+		valsize = sizeof(longval);
+		break;
+	case CTLTYPE_ULONG:
+		ulongval = strtoul(newvalstr, &endptr, 0);
+		newval = &ulongval;
+		valsize = sizeof(ulongval);
+		break;
+	case CTLTYPE_S8:
+		i8val = (int8_t)strtol(newvalstr, &endptr, 0);
+		newval = &i8val;
+		valsize = sizeof(i8val);
+		break;
+	case CTLTYPE_S16:
+		i16val = (int16_t)strtol(newvalstr, &endptr, 0);
+		newval = &i16val;
+		valsize = sizeof(i16val);
+		break;
+	case CTLTYPE_S32:
+		i32val = (int32_t)strtol(newvalstr, &endptr, 0);
+		newval = &i32val;
+		valsize = sizeof(i32val);
+		break;
+	case CTLTYPE_S64:
+		i64val = strtoimax(newvalstr, &endptr, 0);
+		newval = &i64val;
+		valsize = sizeof(i64val);
+		break;
+	case CTLTYPE_U8:
+		u8val = (uint8_t)strtoul(newvalstr, &endptr, 0);
+		newval = &u8val;
+		valsize = sizeof(u8val);
+		break;
+	case CTLTYPE_U16:
+		u16val = (uint16_t)strtoul(newvalstr, &endptr, 0);
+		newval = &u16val;
+		valsize = sizeof(u16val);
+		break;
+	case CTLTYPE_U32:
+		u32val = (uint32_t)strtoul(newvalstr, &endptr, 0);
+		newval = &u32val;
+		valsize = sizeof(u32val);
+		break;
+	case CTLTYPE_U64:
+		u64val = strtoumax(newvalstr, &endptr, 0);
+		newval = &u64val;
+		valsize = sizeof(u64val);
+		break;
+	default:
+		/* NOTREACHED */
+		abort();
+	}
+	
+	if (errno != 0 || endptr == newvalstr ||
+	    (endptr != NULL && *endptr != '\0'))
+		return (false);
+
+	newbuf = realloc(*newbufp, *newsizep + valsize);
+	if (newbuf == NULL)
+		err(1, "out of memory");
+	memcpy((char *)newbuf + *newsizep, newval, valsize);
+	*newbufp = newbuf;
+	*newsizep += valsize;
+	
+	return (true);
+}
+
+/*
+ * Parse a name into a MIB entry.
+ * Lookup and print out the MIB entry if it exists.
+ * Set a new value if requested.
+ */
+static int
+parse(const char *string, int lineno)
+{
+	int len, i, j;
+	const void *newval;
+	char *newvalstr = NULL;
+	void *newbuf;
+	size_t newsize = Bflag;
 	int mib[CTL_MAXNAME];
-	char *cp, *bufp, buf[BUFSIZ], *endptr = NULL, fmt[BUFSIZ], line[BUFSIZ];
+	char *cp, *bufp, buf[BUFSIZ], fmt[BUFSIZ], line[BUFSIZ];
 	u_int kind;
 
 	if (lineno)
@@ -377,94 +479,33 @@ parse(const char *string, int lineno)
 			return (1);
 		}
 
-		errno = 0;
+		newbuf = NULL;
 
 		switch (kind & CTLTYPE) {
-			case CTLTYPE_INT:
-				if (strncmp(fmt, "IK", 2) == 0)
-					intval = strIKtoi(newvalstr, &endptr, fmt);
-				else
-					intval = (int)strtol(newvalstr, &endptr,
-					    0);
-				newval = &intval;
-				newsize = sizeof(intval);
-				break;
-			case CTLTYPE_UINT:
-				uintval = (int) strtoul(newvalstr, &endptr, 0);
-				newval = &uintval;
-				newsize = sizeof(uintval);
-				break;
-			case CTLTYPE_LONG:
-				longval = strtol(newvalstr, &endptr, 0);
-				newval = &longval;
-				newsize = sizeof(longval);
-				break;
-			case CTLTYPE_ULONG:
-				ulongval = strtoul(newvalstr, &endptr, 0);
-				newval = &ulongval;
-				newsize = sizeof(ulongval);
-				break;
-			case CTLTYPE_STRING:
-				newval = newvalstr;
-				break;
-			case CTLTYPE_S8:
-				i8val = (int8_t)strtol(newvalstr, &endptr, 0);
-				newval = &i8val;
-				newsize = sizeof(i8val);
-				break;
-			case CTLTYPE_S16:
-				i16val = (int16_t)strtol(newvalstr, &endptr,
-				    0);
-				newval = &i16val;
-				newsize = sizeof(i16val);
-				break;
-			case CTLTYPE_S32:
-				i32val = (int32_t)strtol(newvalstr, &endptr,
-				    0);
-				newval = &i32val;
-				newsize = sizeof(i32val);
-				break;
-			case CTLTYPE_S64:
-				i64val = strtoimax(newvalstr, &endptr, 0);
-				newval = &i64val;
-				newsize = sizeof(i64val);
-				break;
-			case CTLTYPE_U8:
-				u8val = (uint8_t)strtoul(newvalstr, &endptr, 0);
-				newval = &u8val;
-				newsize = sizeof(u8val);
-				break;
-			case CTLTYPE_U16:
-				u16val = (uint16_t)strtoul(newvalstr, &endptr,
-				    0);
-				newval = &u16val;
-				newsize = sizeof(u16val);
-				break;
-			case CTLTYPE_U32:
-				u32val = (uint32_t)strtoul(newvalstr, &endptr,
-				    0);
-				newval = &u32val;
-				newsize = sizeof(u32val);
-				break;
-			case CTLTYPE_U64:
-				u64val = strtoumax(newvalstr, &endptr, 0);
-				newval = &u64val;
-				newsize = sizeof(u64val);
-				break;
-			default:
-				/* NOTREACHED */
-				abort();
+		case CTLTYPE_STRING:
+			newval = newvalstr;
+			break;
+		default:
+			newsize = 0;
+			while ((cp = strsep(&newvalstr, " ,")) != NULL) {
+				if (*cp == '\0')
+					continue;
+				if (!parse_numeric(cp, fmt, kind, &newbuf,
+				    &newsize)) {
+					warnx("invalid %s '%s'%s",
+					    ctl_typename[kind & CTLTYPE],
+					    cp, line);
+					free(newbuf);
+					return (1);
+				}
+			}
+			newval = newbuf;
+			break;
 		}
 
-		if (errno != 0 || endptr == newvalstr ||
-		    (endptr != NULL && *endptr != '\0')) {
-			warnx("invalid %s '%s'%s", ctl_typename[kind & CTLTYPE],
-			    newvalstr, line);
-			return (1);
-		}
-
 		i = show_var(mib, len);
 		if (sysctl(mib, len, 0, 0, newval, newsize) == -1) {
+			free(newbuf);
 			if (!i && !bflag)
 				putchar('\n');
 			switch (errno) {
@@ -485,6 +526,7 @@ parse(const char *string, int lineno)
 				return (1);
 			}
 		}
+		free(newbuf);
 		if (!bflag)
 			printf(" -> ");
 		i = nflag;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201803092337.w29NbJSX093826>