summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/kern/subr_sbuf.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2016-10-07 15:10:20 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2017-01-10 09:53:31 +0100
commitc40e45b75eb76d79a05c7fa85c1fa9b5c728a12f (patch)
treead4f2519067709f00ab98b3c591186c26dc3a21f /freebsd/sys/kern/subr_sbuf.c
parentuserspace-header-gen.py: Simplify program ports (diff)
downloadrtems-libbsd-c40e45b75eb76d79a05c7fa85c1fa9b5c728a12f.tar.bz2
Update to FreeBSD head 2016-08-23
Git mirror commit 9fe7c416e6abb28b1398fd3e5687099846800cfd.
Diffstat (limited to 'freebsd/sys/kern/subr_sbuf.c')
-rw-r--r--freebsd/sys/kern/subr_sbuf.c131
1 files changed, 88 insertions, 43 deletions
diff --git a/freebsd/sys/kern/subr_sbuf.c b/freebsd/sys/kern/subr_sbuf.c
index e61b0844..73a9b383 100644
--- a/freebsd/sys/kern/subr_sbuf.c
+++ b/freebsd/sys/kern/subr_sbuf.c
@@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$");
#include <sys/ctype.h>
#include <rtems/bsd/sys/errno.h>
#include <sys/kernel.h>
+#include <sys/limits.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <sys/uio.h>
@@ -44,6 +45,7 @@ __FBSDID("$FreeBSD$");
#else /* _KERNEL */
#include <ctype.h>
#include <errno.h>
+#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -54,11 +56,11 @@ __FBSDID("$FreeBSD$");
#ifdef _KERNEL
static MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers");
-#define SBMALLOC(size) malloc(size, M_SBUF, M_WAITOK)
+#define SBMALLOC(size) malloc(size, M_SBUF, M_WAITOK|M_ZERO)
#define SBFREE(buf) free(buf, M_SBUF)
#else /* _KERNEL */
#define KASSERT(e, m)
-#define SBMALLOC(size) malloc(size)
+#define SBMALLOC(size) calloc(1, size)
#define SBFREE(buf) free(buf)
#endif /* _KERNEL */
@@ -72,6 +74,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
@@ -79,6 +82,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
@@ -102,9 +106,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
@@ -187,8 +197,9 @@ sbuf_newbuf(struct sbuf *s, char *buf, int length, int flags)
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)
@@ -264,6 +275,28 @@ sbuf_uionew(struct sbuf *s, struct uio *uio, int *error)
}
#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.
*/
@@ -354,34 +387,51 @@ 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);
}
/*
@@ -390,19 +440,10 @@ sbuf_put_byte(struct sbuf *s, int c)
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);
}
@@ -456,18 +497,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);
}
@@ -590,6 +625,10 @@ sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap)
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)
@@ -699,11 +738,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);
@@ -745,6 +786,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);
}