svn commit: r321112 - in stable/10: share/man/man9 sys/kern sys/sys

Ngie Cooper ngie at FreeBSD.org
Tue Jul 18 08:15:04 UTC 2017


Author: ngie
Date: Tue Jul 18 08:15:02 2017
New Revision: 321112
URL: https://svnweb.freebsd.org/changeset/base/321112

Log:
  MFC r279992,r280149,r280193,r288223,r288484,r321109:
  
  r279992 (by ian):
  
  Add a new flag, SBUF_INCLUDENUL, and new get/set/clear functions for flags.
  
  The SBUF_INCLUDENUL flag causes the nulterm byte at the end of the string
  to be counted in the length of the data.  If copying the data using the
  sbuf_data() and sbuf_len() functions, or if writing it automatically with
  a drain function, the net effect is that the nulterm byte is copied along
  with the rest of the data.
  
  r280149 (by ian):
  
  Update an sbuf assertion to allow for the new SBUF_INCLUDENUL flag.  If
  INCLUDENUL is set and sbuf_finish() has been called, the length has been
  incremented to count the nulterm byte, and in that case current length is
  allowed to be equal to buffer size, otherwise it must be less than.
  
  Add a predicate macro to test for SBUF_INCLUDENUL, and use it in tests, to
  be consistant with the style in the rest of this file.
  
  r280193 (by ian):
  
  The minimum sbuf buffer size is 2 bytes (a byte plus a nulterm), assert that.
  
  Values smaller than two lead to strange asserts that have nothing to do
  with the actual problem (in the case of size=0), or to writing beyond the
  end of the allocated buffer in sbuf_finish() (in the case of size=1).
  
  r288223 (by cem):
  
  sbuf: Process more than one char at a time
  
  Revamp sbuf_put_byte() to sbuf_put_bytes() in the obvious fashion and
  fixup callers.
  
  Add a thin shim around sbuf_put_bytes() with the old ABI to avoid ugly
  changes to some callers.
  
  Obtained from:	Dan Sledz
  
  r288484 (by phk):
  
  Fail the sbuf if vsnprintf(3) fails.
  
  r321109:
  
  Fix whitespace regression accidentally checked in via ^/head at r280149

Modified:
  stable/10/share/man/man9/sbuf.9
  stable/10/sys/kern/subr_sbuf.c
  stable/10/sys/sys/sbuf.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/share/man/man9/sbuf.9
==============================================================================
--- stable/10/share/man/man9/sbuf.9	Tue Jul 18 07:41:38 2017	(r321111)
+++ stable/10/share/man/man9/sbuf.9	Tue Jul 18 08:15:02 2017	(r321112)
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd April 11, 2013
+.Dd March 14, 2015
 .Dt SBUF 9
 .Os
 .Sh NAME
@@ -34,6 +34,9 @@
 .Nm sbuf_new_auto ,
 .Nm sbuf_new_for_sysctl ,
 .Nm sbuf_clear ,
+.Nm sbuf_get_flags ,
+.Nm sbuf_set_flags ,
+.Nm sbuf_clear_flags ,
 .Nm sbuf_setpos ,
 .Nm sbuf_bcat ,
 .Nm sbuf_bcopyin ,
@@ -69,6 +72,12 @@
 .Ft void
 .Fn sbuf_clear "struct sbuf *s"
 .Ft int
+.Fn sbuf_get_flags "struct sbuf *s"
+.Ft void
+.Fn sbuf_set_flags "struct sbuf *s" "int flags"
+.Ft void
+.Fn sbuf_clear_flags "struct sbuf *s" "int flags"
+.Ft int
 .Fn sbuf_setpos "struct sbuf *s" "int pos"
 .Ft int
 .Fn sbuf_bcat "struct sbuf *s" "const void *buf" "size_t len"
@@ -171,6 +180,8 @@ Attempting to extend the sbuf beyond this size results
 .It Dv SBUF_AUTOEXTEND
 This indicates that the storage buffer may be extended as necessary, so long
 as resources allow, to hold additional data.
+.It Dv SBUF_INCLUDENUL
+This causes the final nulterm byte to be counted in the length of the data.
 .El
 .Pp
 Note that if
@@ -221,6 +232,18 @@ The
 function invalidates the contents of the
 .Fa sbuf
 and resets its position to zero.
+.Pp
+The
+.Fn sbuf_get_flags
+function returns the current user flags.
+The
+.Fn sbuf_set_flags
+and
+.Fn sbuf_get_flags
+functions set or clear one or more user flags, respectively.
+The user flags are described under the
+.Fn sbuf_new
+function.
 .Pp
 The
 .Fn sbuf_setpos

Modified: stable/10/sys/kern/subr_sbuf.c
==============================================================================
--- stable/10/sys/kern/subr_sbuf.c	Tue Jul 18 07:41:38 2017	(r321111)
+++ stable/10/sys/kern/subr_sbuf.c	Tue Jul 18 08:15:02 2017	(r321112)
@@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/ctype.h>
 #include <sys/errno.h>
 #include <sys/kernel.h>
+#include <sys/limits.h>
 #include <sys/malloc.h>
 #include <sys/systm.h>
 #include <sys/uio.h>
@@ -42,6 +43,7 @@ __FBSDID("$FreeBSD$");
 #else /* _KERNEL */
 #include <ctype.h>
 #include <errno.h>
+#include <limits.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -70,6 +72,7 @@ static MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers")
 #define	SBUF_FREESPACE(s)	((s)->s_size - ((s)->s_len + 1))
 #define	SBUF_CANEXTEND(s)	((s)->s_flags & SBUF_AUTOEXTEND)
 #define	SBUF_ISSECTION(s)	((s)->s_flags & SBUF_INSECTION)
+#define	SBUF_NULINCLUDED(s)	((s)->s_flags & SBUF_INCLUDENUL)
 
 /*
  * Set / clear flags
@@ -77,6 +80,7 @@ static MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers")
 #define	SBUF_SETFLAG(s, f)	do { (s)->s_flags |= (f); } while (0)
 #define	SBUF_CLEARFLAG(s, f)	do { (s)->s_flags &= ~(f); } while (0)
 
+#define	SBUF_MINSIZE		 2		/* Min is 1 byte + nulterm. */
 #define	SBUF_MINEXTENDSIZE	16		/* Should be power of 2. */
 
 #ifdef PAGE_SIZE
@@ -100,9 +104,15 @@ _assert_sbuf_integrity(const char *fun, struct sbuf *s
 	    ("%s called with a NULL sbuf pointer", fun));
 	KASSERT(s->s_buf != NULL,
 	    ("%s called with uninitialized or corrupt sbuf", fun));
-	KASSERT(s->s_len < s->s_size,
-	    ("wrote past end of sbuf (%jd >= %jd)",
-	    (intmax_t)s->s_len, (intmax_t)s->s_size));
+	if (SBUF_ISFINISHED(s) && SBUF_NULINCLUDED(s)) {
+		KASSERT(s->s_len <= s->s_size,
+		    ("wrote past end of sbuf (%jd >= %jd)",
+		    (intmax_t)s->s_len, (intmax_t)s->s_size));
+	} else {
+		KASSERT(s->s_len < s->s_size,
+		    ("wrote past end of sbuf (%jd >= %jd)",
+		    (intmax_t)s->s_len, (intmax_t)s->s_size));
+	}
 }
 
 static void
@@ -185,8 +195,9 @@ sbuf_newbuf(struct sbuf *s, char *buf, int length, int
 	s->s_buf = buf;
 
 	if ((s->s_flags & SBUF_AUTOEXTEND) == 0) {
-		KASSERT(s->s_size >= 0,
-		    ("attempt to create a too small sbuf"));
+		KASSERT(s->s_size >= SBUF_MINSIZE,
+		    ("attempt to create an sbuf smaller than %d bytes",
+		    SBUF_MINSIZE));
 	}
 
 	if (s->s_buf != NULL)
@@ -262,6 +273,28 @@ sbuf_uionew(struct sbuf *s, struct uio *uio, int *erro
 }
 #endif
 
+int
+sbuf_get_flags(struct sbuf *s)
+{
+
+	return (s->s_flags & SBUF_USRFLAGMSK);
+}
+
+void
+sbuf_clear_flags(struct sbuf *s, int flags)
+{
+
+	s->s_flags &= ~(flags & SBUF_USRFLAGMSK);
+}
+
+void
+sbuf_set_flags(struct sbuf *s, int flags)
+{
+
+
+	s->s_flags |= (flags & SBUF_USRFLAGMSK);
+}
+
 /*
  * Clear an sbuf and reset its position.
  */
@@ -352,55 +385,63 @@ sbuf_drain(struct sbuf *s)
 }
 
 /*
- * Append a byte to an sbuf.  This is the core function for appending
+ * Append bytes to an sbuf.  This is the core function for appending
  * to an sbuf and is the main place that deals with extending the
  * buffer and marking overflow.
  */
 static void
-sbuf_put_byte(struct sbuf *s, int c)
+sbuf_put_bytes(struct sbuf *s, const char *buf, size_t len)
 {
+	size_t n;
 
 	assert_sbuf_integrity(s);
 	assert_sbuf_state(s, 0);
 
 	if (s->s_error != 0)
 		return;
-	if (SBUF_FREESPACE(s) <= 0) {
-		/*
-		 * If there is a drain, use it, otherwise extend the
-		 * buffer.
-		 */
-		if (s->s_drain_func != NULL)
-			(void)sbuf_drain(s);
-		else if (sbuf_extend(s, 1) < 0)
-			s->s_error = ENOMEM;
-		if (s->s_error != 0)
-			return;
+	while (len > 0) {
+		if (SBUF_FREESPACE(s) <= 0) {
+			/*
+			 * If there is a drain, use it, otherwise extend the
+			 * buffer.
+			 */
+			if (s->s_drain_func != NULL)
+				(void)sbuf_drain(s);
+			else if (sbuf_extend(s, len > INT_MAX ? INT_MAX : len)
+			    < 0)
+				s->s_error = ENOMEM;
+			if (s->s_error != 0)
+				return;
+		}
+		n = SBUF_FREESPACE(s);
+		if (len < n)
+			n = len;
+		memcpy(&s->s_buf[s->s_len], buf, n);
+		s->s_len += n;
+		if (SBUF_ISSECTION(s))
+			s->s_sect_len += n;
+		len -= n;
+		buf += n;
 	}
-	s->s_buf[s->s_len++] = c;
-	if (SBUF_ISSECTION(s))
-		s->s_sect_len++;
 }
 
+static void
+sbuf_put_byte(struct sbuf *s, char c)
+{
+
+	sbuf_put_bytes(s, &c, 1);
+}
+
 /*
  * Append a byte string to an sbuf.
  */
 int
 sbuf_bcat(struct sbuf *s, const void *buf, size_t len)
 {
-	const char *str = buf;
-	const char *end = str + len;
 
-	assert_sbuf_integrity(s);
-	assert_sbuf_state(s, 0);
-
+	sbuf_put_bytes(s, buf, len);
 	if (s->s_error != 0)
 		return (-1);
-	for (; str < end; str++) {
-		sbuf_put_byte(s, *str);
-		if (s->s_error != 0)
-			return (-1);
-	}
 	return (0);
 }
 
@@ -454,18 +495,12 @@ sbuf_bcpy(struct sbuf *s, const void *buf, size_t len)
 int
 sbuf_cat(struct sbuf *s, const char *str)
 {
+	size_t n;
 
-	assert_sbuf_integrity(s);
-	assert_sbuf_state(s, 0);
-
+	n = strlen(str);
+	sbuf_put_bytes(s, str, n);
 	if (s->s_error != 0)
 		return (-1);
-
-	while (*str != '\0') {
-		sbuf_put_byte(s, *str++);
-		if (s->s_error != 0)
-			return (-1);
-	}
 	return (0);
 }
 
@@ -588,6 +623,10 @@ sbuf_vprintf(struct sbuf *s, const char *fmt, va_list 
 		va_copy(ap_copy, ap);
 		len = vsnprintf(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1,
 		    fmt, ap_copy);
+		if (len < 0) {
+			s->s_error = errno;
+			return (-1);
+		}
 		va_end(ap_copy);
 
 		if (SBUF_FREESPACE(s) >= len)
@@ -697,11 +736,13 @@ sbuf_finish(struct sbuf *s)
 	assert_sbuf_integrity(s);
 	assert_sbuf_state(s, 0);
 
+	s->s_buf[s->s_len] = '\0';
+	if (SBUF_NULINCLUDED(s))
+		s->s_len++;
 	if (s->s_drain_func != NULL) {
 		while (s->s_len > 0 && s->s_error == 0)
 			s->s_error = sbuf_drain(s);
 	}
-	s->s_buf[s->s_len] = '\0';
 	SBUF_SETFLAG(s, SBUF_FINISHED);
 #ifdef _KERNEL
 	return (s->s_error);
@@ -743,6 +784,10 @@ sbuf_len(struct sbuf *s)
 
 	if (s->s_error != 0)
 		return (-1);
+
+	/* If finished, nulterm is already in len, else add one. */
+	if (SBUF_NULINCLUDED(s) && !SBUF_ISFINISHED(s))
+		return (s->s_len + 1);
 	return (s->s_len);
 }
 

Modified: stable/10/sys/sys/sbuf.h
==============================================================================
--- stable/10/sys/sys/sbuf.h	Tue Jul 18 07:41:38 2017	(r321111)
+++ stable/10/sys/sys/sbuf.h	Tue Jul 18 08:15:02 2017	(r321112)
@@ -48,6 +48,7 @@ struct sbuf {
 	ssize_t		 s_len;		/* current length of string */
 #define	SBUF_FIXEDLEN	0x00000000	/* fixed length buffer (default) */
 #define	SBUF_AUTOEXTEND	0x00000001	/* automatically extend buffer */
+#define	SBUF_INCLUDENUL	0x00000002	/* nulterm byte is counted in len */
 #define	SBUF_USRFLAGMSK	0x0000ffff	/* mask of flags the user may specify */
 #define	SBUF_DYNAMIC	0x00010000	/* s_buf must be freed */
 #define	SBUF_FINISHED	0x00020000	/* set by sbuf_finish() */
@@ -72,6 +73,9 @@ __BEGIN_DECLS
 struct sbuf	*sbuf_new(struct sbuf *, char *, int, int);
 #define		 sbuf_new_auto()				\
 	sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND)
+int		 sbuf_get_flags(struct sbuf *);
+void		 sbuf_clear_flags(struct sbuf *, int);
+void		 sbuf_set_flags(struct sbuf *, int);
 void		 sbuf_clear(struct sbuf *);
 int		 sbuf_setpos(struct sbuf *, ssize_t);
 int		 sbuf_bcat(struct sbuf *, const void *, size_t);


More information about the svn-src-stable mailing list