169990Sdes/*-
2181462Sdes * Copyright (c) 2000-2008 Poul-Henning Kamp
3181462Sdes * Copyright (c) 2000-2008 Dag-Erling Co��dan Sm��rgrav
469990Sdes * All rights reserved.
569990Sdes *
669990Sdes * Redistribution and use in source and binary forms, with or without
769990Sdes * modification, are permitted provided that the following conditions
869990Sdes * are met:
969990Sdes * 1. Redistributions of source code must retain the above copyright
1069990Sdes *    notice, this list of conditions and the following disclaimer
1169990Sdes *    in this position and unchanged.
1269990Sdes * 2. Redistributions in binary form must reproduce the above copyright
1369990Sdes *    notice, this list of conditions and the following disclaimer in the
1469990Sdes *    documentation and/or other materials provided with the distribution.
1569990Sdes *
16181462Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17181462Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18181462Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19181462Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20181462Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21181462Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22181462Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23181462Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24181462Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25181462Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26181462Sdes * SUCH DAMAGE.
2769990Sdes */
2869990Sdes
29116182Sobrien#include <sys/cdefs.h>
30116182Sobrien__FBSDID("$FreeBSD: stable/11/sys/kern/subr_sbuf.c 369621 2021-04-16 19:42:36Z git2svn $");
31116182Sobrien
3269990Sdes#include <sys/param.h>
3374840Sken
3474840Sken#ifdef _KERNEL
3584097Sdes#include <sys/ctype.h>
36212367Smdf#include <sys/errno.h>
3769990Sdes#include <sys/kernel.h>
38288223Scem#include <sys/limits.h>
3969990Sdes#include <sys/malloc.h>
4069990Sdes#include <sys/systm.h>
4184097Sdes#include <sys/uio.h>
4269990Sdes#include <machine/stdarg.h>
4374840Sken#else /* _KERNEL */
4484097Sdes#include <ctype.h>
45212367Smdf#include <errno.h>
46288223Scem#include <limits.h>
4774840Sken#include <stdarg.h>
4888950Skbyanc#include <stdio.h>
4978340Sjlemon#include <stdlib.h>
5088950Skbyanc#include <string.h>
5174840Sken#endif /* _KERNEL */
5269990Sdes
5384097Sdes#include <sys/sbuf.h>
5484097Sdes
5574840Sken#ifdef _KERNEL
56141616Sphkstatic MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers");
57255805Sdes#define	SBMALLOC(size)		malloc(size, M_SBUF, M_WAITOK|M_ZERO)
5889121Skbyanc#define	SBFREE(buf)		free(buf, M_SBUF)
5974840Sken#else /* _KERNEL */
6089121Skbyanc#define	KASSERT(e, m)
61255805Sdes#define	SBMALLOC(size)		calloc(1, size)
6289121Skbyanc#define	SBFREE(buf)		free(buf)
6374840Sken#endif /* _KERNEL */
6469990Sdes
6571721Sdes/*
6671721Sdes * Predicates
6771721Sdes */
6889121Skbyanc#define	SBUF_ISDYNAMIC(s)	((s)->s_flags & SBUF_DYNAMIC)
6989121Skbyanc#define	SBUF_ISDYNSTRUCT(s)	((s)->s_flags & SBUF_DYNSTRUCT)
7089121Skbyanc#define	SBUF_ISFINISHED(s)	((s)->s_flags & SBUF_FINISHED)
7189121Skbyanc#define	SBUF_HASROOM(s)		((s)->s_len < (s)->s_size - 1)
72222004Sphk#define	SBUF_FREESPACE(s)	((s)->s_size - ((s)->s_len + 1))
7388950Skbyanc#define	SBUF_CANEXTEND(s)	((s)->s_flags & SBUF_AUTOEXTEND)
74249377Strociny#define	SBUF_ISSECTION(s)	((s)->s_flags & SBUF_INSECTION)
75280149Sian#define	SBUF_NULINCLUDED(s)	((s)->s_flags & SBUF_INCLUDENUL)
7671721Sdes
7771721Sdes/*
7871721Sdes * Set / clear flags
7971721Sdes */
8089121Skbyanc#define	SBUF_SETFLAG(s, f)	do { (s)->s_flags |= (f); } while (0)
8189121Skbyanc#define	SBUF_CLEARFLAG(s, f)	do { (s)->s_flags &= ~(f); } while (0)
8271721Sdes
83280193Sian#define	SBUF_MINSIZE		 2		/* Min is 1 byte + nulterm. */
8489121Skbyanc#define	SBUF_MINEXTENDSIZE	16		/* Should be power of 2. */
85222004Sphk
86222004Sphk#ifdef PAGE_SIZE
8789121Skbyanc#define	SBUF_MAXEXTENDSIZE	PAGE_SIZE
8889121Skbyanc#define	SBUF_MAXEXTENDINCR	PAGE_SIZE
89222004Sphk#else
90222004Sphk#define	SBUF_MAXEXTENDSIZE	4096
91222004Sphk#define	SBUF_MAXEXTENDINCR	4096
92222004Sphk#endif
9388950Skbyanc
9471721Sdes/*
9571721Sdes * Debugging support
9671721Sdes */
9774840Sken#if defined(_KERNEL) && defined(INVARIANTS)
98181462Sdes
9969990Sdesstatic void
10092664Speter_assert_sbuf_integrity(const char *fun, struct sbuf *s)
10169990Sdes{
102181462Sdes
10369990Sdes	KASSERT(s != NULL,
10473891Sdes	    ("%s called with a NULL sbuf pointer", fun));
10569990Sdes	KASSERT(s->s_buf != NULL,
10688950Skbyanc	    ("%s called with uninitialized or corrupt sbuf", fun));
107321110Sngie	if (SBUF_ISFINISHED(s) && SBUF_NULINCLUDED(s)) {
108280149Sian		KASSERT(s->s_len <= s->s_size,
109280149Sian		    ("wrote past end of sbuf (%jd >= %jd)",
110280149Sian		    (intmax_t)s->s_len, (intmax_t)s->s_size));
111280149Sian	} else {
112280149Sian		KASSERT(s->s_len < s->s_size,
113280149Sian		    ("wrote past end of sbuf (%jd >= %jd)",
114280149Sian		    (intmax_t)s->s_len, (intmax_t)s->s_size));
115280149Sian	}
11669990Sdes}
11769990Sdes
11869990Sdesstatic void
11992664Speter_assert_sbuf_state(const char *fun, struct sbuf *s, int state)
12069990Sdes{
121181462Sdes
12269990Sdes	KASSERT((s->s_flags & SBUF_FINISHED) == state,
12373891Sdes	    ("%s called with %sfinished or corrupt sbuf", fun,
12469990Sdes	    (state ? "un" : "")));
12569990Sdes}
126181462Sdes
12789121Skbyanc#define	assert_sbuf_integrity(s) _assert_sbuf_integrity(__func__, (s))
12889121Skbyanc#define	assert_sbuf_state(s, i)	 _assert_sbuf_state(__func__, (s), (i))
129181462Sdes
13074840Sken#else /* _KERNEL && INVARIANTS */
131181462Sdes
13289121Skbyanc#define	assert_sbuf_integrity(s) do { } while (0)
13389121Skbyanc#define	assert_sbuf_state(s, i)	 do { } while (0)
134181462Sdes
13574840Sken#endif /* _KERNEL && INVARIANTS */
13669990Sdes
137212184Smdf#ifdef CTASSERT
138212180SmdfCTASSERT(powerof2(SBUF_MAXEXTENDSIZE));
139212180SmdfCTASSERT(powerof2(SBUF_MAXEXTENDINCR));
140212182Smdf#endif
141212180Smdf
14288950Skbyancstatic int
14388950Skbyancsbuf_extendsize(int size)
14488950Skbyanc{
14588950Skbyanc	int newsize;
14688950Skbyanc
147212180Smdf	if (size < (int)SBUF_MAXEXTENDSIZE) {
148212180Smdf		newsize = SBUF_MINEXTENDSIZE;
149212180Smdf		while (newsize < size)
15088950Skbyanc			newsize *= 2;
151212180Smdf	} else {
152212180Smdf		newsize = roundup2(size, SBUF_MAXEXTENDINCR);
15388950Skbyanc	}
154212181Smdf	KASSERT(newsize >= size, ("%s: %d < %d\n", __func__, newsize, size));
15588950Skbyanc	return (newsize);
15688950Skbyanc}
15788950Skbyanc
15869990Sdes/*
15988950Skbyanc * Extend an sbuf.
16088950Skbyanc */
16188950Skbyancstatic int
16288950Skbyancsbuf_extend(struct sbuf *s, int addlen)
16388950Skbyanc{
16488950Skbyanc	char *newbuf;
165269179Sgahr	int newsize;
16688950Skbyanc
16788950Skbyanc	if (!SBUF_CANEXTEND(s))
16888950Skbyanc		return (-1);
16988950Skbyanc	newsize = sbuf_extendsize(s->s_size + addlen);
170181462Sdes	newbuf = SBMALLOC(newsize);
17188950Skbyanc	if (newbuf == NULL)
17288950Skbyanc		return (-1);
173222015Sphk	memcpy(newbuf, s->s_buf, s->s_size);
17488950Skbyanc	if (SBUF_ISDYNAMIC(s))
17588950Skbyanc		SBFREE(s->s_buf);
17688950Skbyanc	else
17788950Skbyanc		SBUF_SETFLAG(s, SBUF_DYNAMIC);
17888950Skbyanc	s->s_buf = newbuf;
17988950Skbyanc	s->s_size = newsize;
18088950Skbyanc	return (0);
18188950Skbyanc}
18288950Skbyanc
18388950Skbyanc/*
184222015Sphk * Initialize the internals of an sbuf.
185222015Sphk * If buf is non-NULL, it points to a static or already-allocated string
186222015Sphk * big enough to hold at least length characters.
187222015Sphk */
188222015Sphkstatic struct sbuf *
189269179Sgahrsbuf_newbuf(struct sbuf *s, char *buf, int length, int flags)
190222015Sphk{
191222015Sphk
192222015Sphk	memset(s, 0, sizeof(*s));
193222015Sphk	s->s_flags = flags;
194222015Sphk	s->s_size = length;
195222015Sphk	s->s_buf = buf;
196222015Sphk
197222015Sphk	if ((s->s_flags & SBUF_AUTOEXTEND) == 0) {
198280193Sian		KASSERT(s->s_size >= SBUF_MINSIZE,
199280193Sian		    ("attempt to create an sbuf smaller than %d bytes",
200280193Sian		    SBUF_MINSIZE));
201222015Sphk	}
202222015Sphk
203222015Sphk	if (s->s_buf != NULL)
204222015Sphk		return (s);
205222015Sphk
206222015Sphk	if ((flags & SBUF_AUTOEXTEND) != 0)
207222015Sphk		s->s_size = sbuf_extendsize(s->s_size);
208222015Sphk
209222015Sphk	s->s_buf = SBMALLOC(s->s_size);
210222015Sphk	if (s->s_buf == NULL)
211222015Sphk		return (NULL);
212222015Sphk	SBUF_SETFLAG(s, SBUF_DYNAMIC);
213222015Sphk	return (s);
214222015Sphk}
215222015Sphk
216222015Sphk/*
21769990Sdes * Initialize an sbuf.
21869990Sdes * If buf is non-NULL, it points to a static or already-allocated string
21969990Sdes * big enough to hold at least length characters.
22069990Sdes */
22177989Sdesstruct sbuf *
22271721Sdessbuf_new(struct sbuf *s, char *buf, int length, int flags)
22369990Sdes{
224181462Sdes
22571721Sdes	KASSERT(length >= 0,
22671721Sdes	    ("attempt to create an sbuf of negative length (%d)", length));
22788950Skbyanc	KASSERT((flags & ~SBUF_USRFLAGMSK) == 0,
22888950Skbyanc	    ("%s called with invalid flags", __func__));
22969990Sdes
23088950Skbyanc	flags &= SBUF_USRFLAGMSK;
231222015Sphk	if (s != NULL)
232222015Sphk		return (sbuf_newbuf(s, buf, length, flags));
233222015Sphk
234222015Sphk	s = SBMALLOC(sizeof(*s));
235222015Sphk	if (s == NULL)
23677989Sdes		return (NULL);
237222015Sphk	if (sbuf_newbuf(s, buf, length, flags) == NULL) {
238222015Sphk		SBFREE(s);
239222015Sphk		return (NULL);
24077989Sdes	}
241222015Sphk	SBUF_SETFLAG(s, SBUF_DYNSTRUCT);
24277989Sdes	return (s);
24369990Sdes}
24469990Sdes
24584097Sdes#ifdef _KERNEL
24669990Sdes/*
24784097Sdes * Create an sbuf with uio data
24884097Sdes */
24984097Sdesstruct sbuf *
25084097Sdessbuf_uionew(struct sbuf *s, struct uio *uio, int *error)
25184097Sdes{
252181462Sdes
25384097Sdes	KASSERT(uio != NULL,
25487594Sobrien	    ("%s called with NULL uio pointer", __func__));
25584097Sdes	KASSERT(error != NULL,
25687594Sobrien	    ("%s called with NULL error pointer", __func__));
25784097Sdes
25884097Sdes	s = sbuf_new(s, NULL, uio->uio_resid + 1, 0);
25984097Sdes	if (s == NULL) {
26084097Sdes		*error = ENOMEM;
26184097Sdes		return (NULL);
26284097Sdes	}
26384097Sdes	*error = uiomove(s->s_buf, uio->uio_resid, uio);
26484097Sdes	if (*error != 0) {
26584097Sdes		sbuf_delete(s);
26684097Sdes		return (NULL);
26784097Sdes	}
26884097Sdes	s->s_len = s->s_size - 1;
269249377Strociny	if (SBUF_ISSECTION(s))
270249377Strociny		s->s_sect_len = s->s_size - 1;
27184097Sdes	*error = 0;
27284097Sdes	return (s);
27384097Sdes}
27484097Sdes#endif
27584097Sdes
276279992Sianint
277279992Siansbuf_get_flags(struct sbuf *s)
278279992Sian{
279279992Sian
280279992Sian	return (s->s_flags & SBUF_USRFLAGMSK);
281279992Sian}
282279992Sian
283279992Sianvoid
284279992Siansbuf_clear_flags(struct sbuf *s, int flags)
285279992Sian{
286279992Sian
287279992Sian	s->s_flags &= ~(flags & SBUF_USRFLAGMSK);
288279992Sian}
289279992Sian
290279992Sianvoid
291279992Siansbuf_set_flags(struct sbuf *s, int flags)
292279992Sian{
293279992Sian
294279992Sian
295279992Sian	s->s_flags |= (flags & SBUF_USRFLAGMSK);
296279992Sian}
297279992Sian
29884097Sdes/*
29988950Skbyanc * Clear an sbuf and reset its position.
30071721Sdes */
30171721Sdesvoid
30271721Sdessbuf_clear(struct sbuf *s)
30371721Sdes{
304181462Sdes
30571721Sdes	assert_sbuf_integrity(s);
30671724Sdes	/* don't care if it's finished or not */
30771721Sdes
30871721Sdes	SBUF_CLEARFLAG(s, SBUF_FINISHED);
309212367Smdf	s->s_error = 0;
31071721Sdes	s->s_len = 0;
311249377Strociny	s->s_sect_len = 0;
31271721Sdes}
31371721Sdes
31471721Sdes/*
31588950Skbyanc * Set the sbuf's end position to an arbitrary value.
31688950Skbyanc * Effectively truncates the sbuf at the new position.
31769990Sdes */
31869990Sdesint
319269179Sgahrsbuf_setpos(struct sbuf *s, ssize_t pos)
32069990Sdes{
321181462Sdes
32269990Sdes	assert_sbuf_integrity(s);
32369990Sdes	assert_sbuf_state(s, 0);
324125937Sdes
325269179Sgahr	KASSERT(pos >= 0,
326269179Sgahr	    ("attempt to seek to a negative position (%jd)", (intmax_t)pos));
32769990Sdes	KASSERT(pos < s->s_size,
328221993Sphk	    ("attempt to seek past end of sbuf (%jd >= %jd)",
329221993Sphk	    (intmax_t)pos, (intmax_t)s->s_size));
330249377Strociny	KASSERT(!SBUF_ISSECTION(s),
331249377Strociny	    ("attempt to seek when in a section"));
332125937Sdes
333269179Sgahr	if (pos < 0 || pos > s->s_len)
33469990Sdes		return (-1);
33569990Sdes	s->s_len = pos;
33669990Sdes	return (0);
33769990Sdes}
33869990Sdes
33969990Sdes/*
340212367Smdf * Set up a drain function and argument on an sbuf to flush data to
341212367Smdf * when the sbuf buffer overflows.
342212367Smdf */
343212367Smdfvoid
344212367Smdfsbuf_set_drain(struct sbuf *s, sbuf_drain_func *func, void *ctx)
345212367Smdf{
346212367Smdf
347212367Smdf	assert_sbuf_state(s, 0);
348212367Smdf	assert_sbuf_integrity(s);
349212367Smdf	KASSERT(func == s->s_drain_func || s->s_len == 0,
350212367Smdf	    ("Cannot change drain to %p on non-empty sbuf %p", func, s));
351212367Smdf	s->s_drain_func = func;
352212367Smdf	s->s_drain_arg = ctx;
353212367Smdf}
354212367Smdf
355212367Smdf/*
356212367Smdf * Call the drain and process the return.
357212367Smdf */
358369620Srscheffint
359212367Smdfsbuf_drain(struct sbuf *s)
360212367Smdf{
361212367Smdf	int len;
362212367Smdf
363369621Sgit2svn	/*
364369621Sgit2svn	 * Immediately return when no work to do,
365369621Sgit2svn	 * or an error has already been accumulated.
366369621Sgit2svn	 */
367369621Sgit2svn	if ((s->s_len == 0) || (s->s_error != 0))
368369621Sgit2svn		return(s->s_error);
369369621Sgit2svn
370212367Smdf	len = s->s_drain_func(s->s_drain_arg, s->s_buf, s->s_len);
371212367Smdf	if (len < 0) {
372212367Smdf		s->s_error = -len;
373212367Smdf		return (s->s_error);
374212367Smdf	}
375212750Smdf	KASSERT(len > 0 && len <= s->s_len,
376212750Smdf	    ("Bad drain amount %d for sbuf %p", len, s));
377212367Smdf	s->s_len -= len;
378212367Smdf	/*
379212367Smdf	 * Fast path for the expected case where all the data was
380212367Smdf	 * drained.
381212367Smdf	 */
382212367Smdf	if (s->s_len == 0)
383212367Smdf		return (0);
384212367Smdf	/*
385212367Smdf	 * Move the remaining characters to the beginning of the
386212367Smdf	 * string.
387212367Smdf	 */
388212367Smdf	memmove(s->s_buf, s->s_buf + len, s->s_len);
389212367Smdf	return (0);
390212367Smdf}
391212367Smdf
392212367Smdf/*
393288223Scem * Append bytes to an sbuf.  This is the core function for appending
394212365Smdf * to an sbuf and is the main place that deals with extending the
395212365Smdf * buffer and marking overflow.
396212365Smdf */
397212365Smdfstatic void
398288223Scemsbuf_put_bytes(struct sbuf *s, const char *buf, size_t len)
399212365Smdf{
400288223Scem	size_t n;
401212365Smdf
402212365Smdf	assert_sbuf_integrity(s);
403212365Smdf	assert_sbuf_state(s, 0);
404212365Smdf
405212425Smdf	if (s->s_error != 0)
406212365Smdf		return;
407288223Scem	while (len > 0) {
408288223Scem		if (SBUF_FREESPACE(s) <= 0) {
409288223Scem			/*
410288223Scem			 * If there is a drain, use it, otherwise extend the
411288223Scem			 * buffer.
412288223Scem			 */
413288223Scem			if (s->s_drain_func != NULL)
414288223Scem				(void)sbuf_drain(s);
415288223Scem			else if (sbuf_extend(s, len > INT_MAX ? INT_MAX : len)
416288223Scem			    < 0)
417288223Scem				s->s_error = ENOMEM;
418288223Scem			if (s->s_error != 0)
419288223Scem				return;
420288223Scem		}
421288223Scem		n = SBUF_FREESPACE(s);
422288223Scem		if (len < n)
423288223Scem			n = len;
424288223Scem		memcpy(&s->s_buf[s->s_len], buf, n);
425288223Scem		s->s_len += n;
426288223Scem		if (SBUF_ISSECTION(s))
427288223Scem			s->s_sect_len += n;
428288223Scem		len -= n;
429288223Scem		buf += n;
430212365Smdf	}
431212365Smdf}
432212365Smdf
433288223Scemstatic void
434288223Scemsbuf_put_byte(struct sbuf *s, char c)
435288223Scem{
436288223Scem
437288223Scem	sbuf_put_bytes(s, &c, 1);
438288223Scem}
439288223Scem
440212365Smdf/*
44178077Sdes * Append a byte string to an sbuf.
44278077Sdes */
44378077Sdesint
444131869Sdessbuf_bcat(struct sbuf *s, const void *buf, size_t len)
44578077Sdes{
446131868Sdes
447288223Scem	sbuf_put_bytes(s, buf, len);
448212425Smdf	if (s->s_error != 0)
44978077Sdes		return (-1);
45078077Sdes	return (0);
45178077Sdes}
45278077Sdes
45378077Sdes#ifdef _KERNEL
45478077Sdes/*
45578077Sdes * Copy a byte string from userland into an sbuf.
45678077Sdes */
45778077Sdesint
45878077Sdessbuf_bcopyin(struct sbuf *s, const void *uaddr, size_t len)
45978077Sdes{
460181462Sdes
46178077Sdes	assert_sbuf_integrity(s);
46278077Sdes	assert_sbuf_state(s, 0);
463212367Smdf	KASSERT(s->s_drain_func == NULL,
464212367Smdf	    ("Nonsensical copyin to sbuf %p with a drain", s));
46578077Sdes
466212425Smdf	if (s->s_error != 0)
46778077Sdes		return (-1);
46878077Sdes	if (len == 0)
46978077Sdes		return (0);
47088950Skbyanc	if (len > SBUF_FREESPACE(s)) {
47188950Skbyanc		sbuf_extend(s, len - SBUF_FREESPACE(s));
472212183Smdf		if (SBUF_FREESPACE(s) < len)
473212183Smdf			len = SBUF_FREESPACE(s);
47488950Skbyanc	}
47578092Sdes	if (copyin(uaddr, s->s_buf + s->s_len, len) != 0)
47678092Sdes		return (-1);
47778095Sdes	s->s_len += len;
478125937Sdes
47978077Sdes	return (0);
48078077Sdes}
48178077Sdes#endif
48278077Sdes
48378077Sdes/*
48478077Sdes * Copy a byte string into an sbuf.
48578077Sdes */
48678077Sdesint
487131869Sdessbuf_bcpy(struct sbuf *s, const void *buf, size_t len)
48878077Sdes{
489181462Sdes
49078077Sdes	assert_sbuf_integrity(s);
49178077Sdes	assert_sbuf_state(s, 0);
492125937Sdes
49378077Sdes	sbuf_clear(s);
494131869Sdes	return (sbuf_bcat(s, buf, len));
49578077Sdes}
49678077Sdes
49778077Sdes/*
49869990Sdes * Append a string to an sbuf.
49969990Sdes */
50069990Sdesint
50174840Skensbuf_cat(struct sbuf *s, const char *str)
50269990Sdes{
503288223Scem	size_t n;
504181462Sdes
505288223Scem	n = strlen(str);
506288223Scem	sbuf_put_bytes(s, str, n);
507212425Smdf	if (s->s_error != 0)
50869990Sdes		return (-1);
50969990Sdes	return (0);
51069990Sdes}
51169990Sdes
51278077Sdes#ifdef _KERNEL
51369990Sdes/*
51488950Skbyanc * Append a string from userland to an sbuf.
51578077Sdes */
51678077Sdesint
51778077Sdessbuf_copyin(struct sbuf *s, const void *uaddr, size_t len)
51878077Sdes{
51978077Sdes	size_t done;
520125937Sdes
52178077Sdes	assert_sbuf_integrity(s);
52278077Sdes	assert_sbuf_state(s, 0);
523212367Smdf	KASSERT(s->s_drain_func == NULL,
524212367Smdf	    ("Nonsensical copyin to sbuf %p with a drain", s));
52578077Sdes
526212425Smdf	if (s->s_error != 0)
52778077Sdes		return (-1);
52878077Sdes
52988950Skbyanc	if (len == 0)
53088950Skbyanc		len = SBUF_FREESPACE(s);	/* XXX return 0? */
53188950Skbyanc	if (len > SBUF_FREESPACE(s)) {
53288950Skbyanc		sbuf_extend(s, len);
533212183Smdf		if (SBUF_FREESPACE(s) < len)
534212183Smdf			len = SBUF_FREESPACE(s);
53588950Skbyanc	}
53678077Sdes	switch (copyinstr(uaddr, s->s_buf + s->s_len, len + 1, &done)) {
53778077Sdes	case ENAMETOOLONG:
538212425Smdf		s->s_error = ENOMEM;
53978077Sdes		/* fall through */
54078077Sdes	case 0:
54178077Sdes		s->s_len += done - 1;
542249377Strociny		if (SBUF_ISSECTION(s))
543249377Strociny			s->s_sect_len += done - 1;
54478077Sdes		break;
54578077Sdes	default:
54678077Sdes		return (-1);	/* XXX */
54778077Sdes	}
548125937Sdes
549153678Sphk	return (done);
55078077Sdes}
55178077Sdes#endif
55278077Sdes
55378077Sdes/*
55469990Sdes * Copy a string into an sbuf.
55569990Sdes */
55669990Sdesint
55774840Skensbuf_cpy(struct sbuf *s, const char *str)
55869990Sdes{
559181462Sdes
56069990Sdes	assert_sbuf_integrity(s);
56169990Sdes	assert_sbuf_state(s, 0);
562125937Sdes
56371721Sdes	sbuf_clear(s);
56469990Sdes	return (sbuf_cat(s, str));
56569990Sdes}
56669990Sdes
56769990Sdes/*
56888950Skbyanc * Format the given argument list and append the resulting string to an sbuf.
56969990Sdes */
570212365Smdf#ifdef _KERNEL
571222004Sphk
572222004Sphk/*
573222004Sphk * Append a non-NUL character to an sbuf.  This prototype signature is
574222004Sphk * suitable for use with kvprintf(9).
575222004Sphk */
576222004Sphkstatic void
577222004Sphksbuf_putc_func(int c, void *arg)
578222004Sphk{
579222004Sphk
580222004Sphk	if (c != '\0')
581222004Sphk		sbuf_put_byte(arg, c);
582222004Sphk}
583222004Sphk
58469990Sdesint
58588950Skbyancsbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap)
58669990Sdes{
587212365Smdf
588212365Smdf	assert_sbuf_integrity(s);
589212365Smdf	assert_sbuf_state(s, 0);
590212365Smdf
591212365Smdf	KASSERT(fmt != NULL,
592212365Smdf	    ("%s called with a NULL format string", __func__));
593212365Smdf
594212365Smdf	(void)kvprintf(fmt, sbuf_putc_func, s, 10, ap);
595212425Smdf	if (s->s_error != 0)
596212365Smdf		return (-1);
597212365Smdf	return (0);
598212365Smdf}
599212365Smdf#else /* !_KERNEL */
600212365Smdfint
601212365Smdfsbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap)
602212365Smdf{
603115311Speter	va_list ap_copy;
604269179Sgahr	int error, len;
60569990Sdes
60669990Sdes	assert_sbuf_integrity(s);
60769990Sdes	assert_sbuf_state(s, 0);
60888950Skbyanc
60969990Sdes	KASSERT(fmt != NULL,
61087594Sobrien	    ("%s called with a NULL format string", __func__));
61188950Skbyanc
612212425Smdf	if (s->s_error != 0)
61369990Sdes		return (-1);
61469990Sdes
615212365Smdf	/*
616212365Smdf	 * For the moment, there is no way to get vsnprintf(3) to hand
617212365Smdf	 * back a character at a time, to push everything into
618212365Smdf	 * sbuf_putc_func() as was done for the kernel.
619212367Smdf	 *
620212367Smdf	 * In userspace, while drains are useful, there's generally
621212367Smdf	 * not a problem attempting to malloc(3) on out of space.  So
622212367Smdf	 * expand a userland sbuf if there is not enough room for the
623212367Smdf	 * data produced by sbuf_[v]printf(3).
624212365Smdf	 */
625212365Smdf
626212367Smdf	error = 0;
62788950Skbyanc	do {
628115311Speter		va_copy(ap_copy, ap);
62988950Skbyanc		len = vsnprintf(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1,
630115311Speter		    fmt, ap_copy);
631288484Sphk		if (len < 0) {
632288484Sphk			s->s_error = errno;
633288484Sphk			return (-1);
634288484Sphk		}
635115311Speter		va_end(ap_copy);
63669990Sdes
637212367Smdf		if (SBUF_FREESPACE(s) >= len)
638212367Smdf			break;
639212367Smdf		/* Cannot print with the current available space. */
640212367Smdf		if (s->s_drain_func != NULL && s->s_len > 0)
641212367Smdf			error = sbuf_drain(s);
642212367Smdf		else
643212367Smdf			error = sbuf_extend(s, len - SBUF_FREESPACE(s));
644212367Smdf	} while (error == 0);
645212367Smdf
64674840Sken	/*
64774840Sken	 * s->s_len is the length of the string, without the terminating nul.
64874840Sken	 * When updating s->s_len, we must subtract 1 from the length that
64974840Sken	 * we passed into vsnprintf() because that length includes the
65074840Sken	 * terminating nul.
65174840Sken	 *
65274840Sken	 * vsnprintf() returns the amount that would have been copied,
653212183Smdf	 * given sufficient space, so don't over-increment s_len.
65474840Sken	 */
655212183Smdf	if (SBUF_FREESPACE(s) < len)
656212183Smdf		len = SBUF_FREESPACE(s);
657212183Smdf	s->s_len += len;
658249377Strociny	if (SBUF_ISSECTION(s))
659249377Strociny		s->s_sect_len += len;
66089646Sphk	if (!SBUF_HASROOM(s) && !SBUF_CANEXTEND(s))
661212425Smdf		s->s_error = ENOMEM;
66274840Sken
66369990Sdes	KASSERT(s->s_len < s->s_size,
66469990Sdes	    ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size));
66569990Sdes
666212425Smdf	if (s->s_error != 0)
66769990Sdes		return (-1);
66869990Sdes	return (0);
66969990Sdes}
670212365Smdf#endif /* _KERNEL */
67169990Sdes
67269990Sdes/*
67388950Skbyanc * Format the given arguments and append the resulting string to an sbuf.
67488950Skbyanc */
67588950Skbyancint
67688950Skbyancsbuf_printf(struct sbuf *s, const char *fmt, ...)
67788950Skbyanc{
67888950Skbyanc	va_list ap;
67988950Skbyanc	int result;
68088950Skbyanc
68188950Skbyanc	va_start(ap, fmt);
68288950Skbyanc	result = sbuf_vprintf(s, fmt, ap);
68388950Skbyanc	va_end(ap);
684181462Sdes	return (result);
68588950Skbyanc}
68688950Skbyanc
68788950Skbyanc/*
68869990Sdes * Append a character to an sbuf.
68969990Sdes */
69069990Sdesint
69169990Sdessbuf_putc(struct sbuf *s, int c)
69269990Sdes{
693181462Sdes
694222004Sphk	sbuf_put_byte(s, c);
695212425Smdf	if (s->s_error != 0)
69669990Sdes		return (-1);
69769990Sdes	return (0);
69869990Sdes}
69969990Sdes
70069990Sdes/*
70188950Skbyanc * Trim whitespace characters from end of an sbuf.
70284097Sdes */
70384097Sdesint
70484097Sdessbuf_trim(struct sbuf *s)
70584097Sdes{
706181462Sdes
70784097Sdes	assert_sbuf_integrity(s);
70884097Sdes	assert_sbuf_state(s, 0);
709212367Smdf	KASSERT(s->s_drain_func == NULL,
710212367Smdf	    ("%s makes no sense on sbuf %p with drain", __func__, s));
711125937Sdes
712212425Smdf	if (s->s_error != 0)
71384097Sdes		return (-1);
714125937Sdes
715249377Strociny	while (s->s_len > 0 && isspace(s->s_buf[s->s_len-1])) {
71684097Sdes		--s->s_len;
717249377Strociny		if (SBUF_ISSECTION(s))
718249377Strociny			s->s_sect_len--;
719249377Strociny	}
72084097Sdes
72184097Sdes	return (0);
72284097Sdes}
72384097Sdes
72484097Sdes/*
725212425Smdf * Check if an sbuf has an error.
72671721Sdes */
72771721Sdesint
728221993Sphksbuf_error(const struct sbuf *s)
72971721Sdes{
730181462Sdes
731212425Smdf	return (s->s_error);
73271721Sdes}
73371721Sdes
73471721Sdes/*
73569990Sdes * Finish off an sbuf.
73669990Sdes */
737212367Smdfint
73869990Sdessbuf_finish(struct sbuf *s)
73969990Sdes{
740181462Sdes
74169990Sdes	assert_sbuf_integrity(s);
74269990Sdes	assert_sbuf_state(s, 0);
743125937Sdes
744279992Sian	s->s_buf[s->s_len] = '\0';
745280149Sian	if (SBUF_NULINCLUDED(s))
746279992Sian		s->s_len++;
747212367Smdf	if (s->s_drain_func != NULL) {
748222004Sphk		while (s->s_len > 0 && s->s_error == 0)
749222004Sphk			s->s_error = sbuf_drain(s);
750212425Smdf	}
75169990Sdes	SBUF_SETFLAG(s, SBUF_FINISHED);
752212367Smdf#ifdef _KERNEL
753222004Sphk	return (s->s_error);
754212367Smdf#else
755250706Sjh	if (s->s_error != 0) {
756250706Sjh		errno = s->s_error;
757222004Sphk		return (-1);
758250706Sjh	}
759222004Sphk	return (0);
760212367Smdf#endif
76169990Sdes}
76269990Sdes
76369990Sdes/*
76469990Sdes * Return a pointer to the sbuf data.
76569990Sdes */
76669990Sdeschar *
76769990Sdessbuf_data(struct sbuf *s)
76869990Sdes{
769181462Sdes
77069990Sdes	assert_sbuf_integrity(s);
77169990Sdes	assert_sbuf_state(s, SBUF_FINISHED);
772212367Smdf	KASSERT(s->s_drain_func == NULL,
773212367Smdf	    ("%s makes no sense on sbuf %p with drain", __func__, s));
774125937Sdes
775181462Sdes	return (s->s_buf);
77669990Sdes}
77769990Sdes
77869990Sdes/*
77969990Sdes * Return the length of the sbuf data.
78069990Sdes */
781221993Sphkssize_t
78269990Sdessbuf_len(struct sbuf *s)
78369990Sdes{
784181462Sdes
78569990Sdes	assert_sbuf_integrity(s);
78671724Sdes	/* don't care if it's finished or not */
787212367Smdf	KASSERT(s->s_drain_func == NULL,
788212367Smdf	    ("%s makes no sense on sbuf %p with drain", __func__, s));
789125937Sdes
790212425Smdf	if (s->s_error != 0)
79171721Sdes		return (-1);
792279992Sian
793279992Sian	/* If finished, nulterm is already in len, else add one. */
794280149Sian	if (SBUF_NULINCLUDED(s) && !SBUF_ISFINISHED(s))
795279992Sian		return (s->s_len + 1);
796181462Sdes	return (s->s_len);
79769990Sdes}
79869990Sdes
79969990Sdes/*
80069990Sdes * Clear an sbuf, free its buffer if necessary.
80169990Sdes */
80269990Sdesvoid
80369990Sdessbuf_delete(struct sbuf *s)
80469990Sdes{
80588219Sdillon	int isdyn;
80688219Sdillon
80769990Sdes	assert_sbuf_integrity(s);
80869990Sdes	/* don't care if it's finished or not */
809125937Sdes
81069990Sdes	if (SBUF_ISDYNAMIC(s))
81174840Sken		SBFREE(s->s_buf);
81288219Sdillon	isdyn = SBUF_ISDYNSTRUCT(s);
813222015Sphk	memset(s, 0, sizeof(*s));
81488219Sdillon	if (isdyn)
81577989Sdes		SBFREE(s);
81669990Sdes}
817104449Sphk
818104449Sphk/*
819104449Sphk * Check if an sbuf has been finished.
820104449Sphk */
821104449Sphkint
822221993Sphksbuf_done(const struct sbuf *s)
823104449Sphk{
824104449Sphk
825181462Sdes	return (SBUF_ISFINISHED(s));
826104449Sphk}
827249377Strociny
828249377Strociny/*
829249377Strociny * Start a section.
830249377Strociny */
831249377Strocinyvoid
832249377Strocinysbuf_start_section(struct sbuf *s, ssize_t *old_lenp)
833249377Strociny{
834249377Strociny
835249377Strociny	assert_sbuf_integrity(s);
836249377Strociny	assert_sbuf_state(s, 0);
837249377Strociny
838249377Strociny	if (!SBUF_ISSECTION(s)) {
839249377Strociny		KASSERT(s->s_sect_len == 0,
840249377Strociny		    ("s_sect_len != 0 when starting a section"));
841249377Strociny		if (old_lenp != NULL)
842249377Strociny			*old_lenp = -1;
843249377Strociny		SBUF_SETFLAG(s, SBUF_INSECTION);
844249377Strociny	} else {
845249377Strociny		KASSERT(old_lenp != NULL,
846249377Strociny		    ("s_sect_len should be saved when starting a subsection"));
847249377Strociny		*old_lenp = s->s_sect_len;
848249377Strociny		s->s_sect_len = 0;
849249377Strociny	}
850249377Strociny}
851249377Strociny
852249377Strociny/*
853249377Strociny * End the section padding to the specified length with the specified
854249377Strociny * character.
855249377Strociny */
856249377Strocinyssize_t
857249377Strocinysbuf_end_section(struct sbuf *s, ssize_t old_len, size_t pad, int c)
858249377Strociny{
859249377Strociny	ssize_t len;
860249377Strociny
861249377Strociny	assert_sbuf_integrity(s);
862249377Strociny	assert_sbuf_state(s, 0);
863249377Strociny	KASSERT(SBUF_ISSECTION(s),
864249377Strociny	    ("attempt to end a section when not in a section"));
865249377Strociny
866249377Strociny	if (pad > 1) {
867249377Strociny		len = roundup(s->s_sect_len, pad) - s->s_sect_len;
868249377Strociny		for (; s->s_error == 0 && len > 0; len--)
869249377Strociny			sbuf_put_byte(s, c);
870249377Strociny	}
871249377Strociny	len = s->s_sect_len;
872249377Strociny	if (old_len == -1) {
873249377Strociny		s->s_sect_len = 0;
874249377Strociny		SBUF_CLEARFLAG(s, SBUF_INSECTION);
875249377Strociny	} else {
876249377Strociny		s->s_sect_len += old_len;
877249377Strociny	}
878249377Strociny	if (s->s_error != 0)
879249377Strociny		return (-1);
880249377Strociny	return (len);
881249377Strociny}
882