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@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);
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-stable-10
To unsubscribe, send any mail to "[email protected]"

Reply via email to