1/*-
2 * Copyright (c) 2000-2008 Poul-Henning Kamp
3 * Copyright (c) 2000-2008 Dag-Erling Co��dan Sm��rgrav
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer
11 *    in this position and unchanged.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: stable/11/sys/kern/subr_sbuf.c 369621 2021-04-16 19:42:36Z git2svn $");
31
32#include <sys/param.h>
33
34#ifdef _KERNEL
35#include <sys/ctype.h>
36#include <sys/errno.h>
37#include <sys/kernel.h>
38#include <sys/limits.h>
39#include <sys/malloc.h>
40#include <sys/systm.h>
41#include <sys/uio.h>
42#include <machine/stdarg.h>
43#else /* _KERNEL */
44#include <ctype.h>
45#include <errno.h>
46#include <limits.h>
47#include <stdarg.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51#endif /* _KERNEL */
52
53#include <sys/sbuf.h>
54
55#ifdef _KERNEL
56static MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers");
57#define	SBMALLOC(size)		malloc(size, M_SBUF, M_WAITOK|M_ZERO)
58#define	SBFREE(buf)		free(buf, M_SBUF)
59#else /* _KERNEL */
60#define	KASSERT(e, m)
61#define	SBMALLOC(size)		calloc(1, size)
62#define	SBFREE(buf)		free(buf)
63#endif /* _KERNEL */
64
65/*
66 * Predicates
67 */
68#define	SBUF_ISDYNAMIC(s)	((s)->s_flags & SBUF_DYNAMIC)
69#define	SBUF_ISDYNSTRUCT(s)	((s)->s_flags & SBUF_DYNSTRUCT)
70#define	SBUF_ISFINISHED(s)	((s)->s_flags & SBUF_FINISHED)
71#define	SBUF_HASROOM(s)		((s)->s_len < (s)->s_size - 1)
72#define	SBUF_FREESPACE(s)	((s)->s_size - ((s)->s_len + 1))
73#define	SBUF_CANEXTEND(s)	((s)->s_flags & SBUF_AUTOEXTEND)
74#define	SBUF_ISSECTION(s)	((s)->s_flags & SBUF_INSECTION)
75#define	SBUF_NULINCLUDED(s)	((s)->s_flags & SBUF_INCLUDENUL)
76
77/*
78 * Set / clear flags
79 */
80#define	SBUF_SETFLAG(s, f)	do { (s)->s_flags |= (f); } while (0)
81#define	SBUF_CLEARFLAG(s, f)	do { (s)->s_flags &= ~(f); } while (0)
82
83#define	SBUF_MINSIZE		 2		/* Min is 1 byte + nulterm. */
84#define	SBUF_MINEXTENDSIZE	16		/* Should be power of 2. */
85
86#ifdef PAGE_SIZE
87#define	SBUF_MAXEXTENDSIZE	PAGE_SIZE
88#define	SBUF_MAXEXTENDINCR	PAGE_SIZE
89#else
90#define	SBUF_MAXEXTENDSIZE	4096
91#define	SBUF_MAXEXTENDINCR	4096
92#endif
93
94/*
95 * Debugging support
96 */
97#if defined(_KERNEL) && defined(INVARIANTS)
98
99static void
100_assert_sbuf_integrity(const char *fun, struct sbuf *s)
101{
102
103	KASSERT(s != NULL,
104	    ("%s called with a NULL sbuf pointer", fun));
105	KASSERT(s->s_buf != NULL,
106	    ("%s called with uninitialized or corrupt sbuf", fun));
107	if (SBUF_ISFINISHED(s) && SBUF_NULINCLUDED(s)) {
108		KASSERT(s->s_len <= s->s_size,
109		    ("wrote past end of sbuf (%jd >= %jd)",
110		    (intmax_t)s->s_len, (intmax_t)s->s_size));
111	} else {
112		KASSERT(s->s_len < s->s_size,
113		    ("wrote past end of sbuf (%jd >= %jd)",
114		    (intmax_t)s->s_len, (intmax_t)s->s_size));
115	}
116}
117
118static void
119_assert_sbuf_state(const char *fun, struct sbuf *s, int state)
120{
121
122	KASSERT((s->s_flags & SBUF_FINISHED) == state,
123	    ("%s called with %sfinished or corrupt sbuf", fun,
124	    (state ? "un" : "")));
125}
126
127#define	assert_sbuf_integrity(s) _assert_sbuf_integrity(__func__, (s))
128#define	assert_sbuf_state(s, i)	 _assert_sbuf_state(__func__, (s), (i))
129
130#else /* _KERNEL && INVARIANTS */
131
132#define	assert_sbuf_integrity(s) do { } while (0)
133#define	assert_sbuf_state(s, i)	 do { } while (0)
134
135#endif /* _KERNEL && INVARIANTS */
136
137#ifdef CTASSERT
138CTASSERT(powerof2(SBUF_MAXEXTENDSIZE));
139CTASSERT(powerof2(SBUF_MAXEXTENDINCR));
140#endif
141
142static int
143sbuf_extendsize(int size)
144{
145	int newsize;
146
147	if (size < (int)SBUF_MAXEXTENDSIZE) {
148		newsize = SBUF_MINEXTENDSIZE;
149		while (newsize < size)
150			newsize *= 2;
151	} else {
152		newsize = roundup2(size, SBUF_MAXEXTENDINCR);
153	}
154	KASSERT(newsize >= size, ("%s: %d < %d\n", __func__, newsize, size));
155	return (newsize);
156}
157
158/*
159 * Extend an sbuf.
160 */
161static int
162sbuf_extend(struct sbuf *s, int addlen)
163{
164	char *newbuf;
165	int newsize;
166
167	if (!SBUF_CANEXTEND(s))
168		return (-1);
169	newsize = sbuf_extendsize(s->s_size + addlen);
170	newbuf = SBMALLOC(newsize);
171	if (newbuf == NULL)
172		return (-1);
173	memcpy(newbuf, s->s_buf, s->s_size);
174	if (SBUF_ISDYNAMIC(s))
175		SBFREE(s->s_buf);
176	else
177		SBUF_SETFLAG(s, SBUF_DYNAMIC);
178	s->s_buf = newbuf;
179	s->s_size = newsize;
180	return (0);
181}
182
183/*
184 * Initialize the internals of an sbuf.
185 * If buf is non-NULL, it points to a static or already-allocated string
186 * big enough to hold at least length characters.
187 */
188static struct sbuf *
189sbuf_newbuf(struct sbuf *s, char *buf, int length, int flags)
190{
191
192	memset(s, 0, sizeof(*s));
193	s->s_flags = flags;
194	s->s_size = length;
195	s->s_buf = buf;
196
197	if ((s->s_flags & SBUF_AUTOEXTEND) == 0) {
198		KASSERT(s->s_size >= SBUF_MINSIZE,
199		    ("attempt to create an sbuf smaller than %d bytes",
200		    SBUF_MINSIZE));
201	}
202
203	if (s->s_buf != NULL)
204		return (s);
205
206	if ((flags & SBUF_AUTOEXTEND) != 0)
207		s->s_size = sbuf_extendsize(s->s_size);
208
209	s->s_buf = SBMALLOC(s->s_size);
210	if (s->s_buf == NULL)
211		return (NULL);
212	SBUF_SETFLAG(s, SBUF_DYNAMIC);
213	return (s);
214}
215
216/*
217 * Initialize an sbuf.
218 * If buf is non-NULL, it points to a static or already-allocated string
219 * big enough to hold at least length characters.
220 */
221struct sbuf *
222sbuf_new(struct sbuf *s, char *buf, int length, int flags)
223{
224
225	KASSERT(length >= 0,
226	    ("attempt to create an sbuf of negative length (%d)", length));
227	KASSERT((flags & ~SBUF_USRFLAGMSK) == 0,
228	    ("%s called with invalid flags", __func__));
229
230	flags &= SBUF_USRFLAGMSK;
231	if (s != NULL)
232		return (sbuf_newbuf(s, buf, length, flags));
233
234	s = SBMALLOC(sizeof(*s));
235	if (s == NULL)
236		return (NULL);
237	if (sbuf_newbuf(s, buf, length, flags) == NULL) {
238		SBFREE(s);
239		return (NULL);
240	}
241	SBUF_SETFLAG(s, SBUF_DYNSTRUCT);
242	return (s);
243}
244
245#ifdef _KERNEL
246/*
247 * Create an sbuf with uio data
248 */
249struct sbuf *
250sbuf_uionew(struct sbuf *s, struct uio *uio, int *error)
251{
252
253	KASSERT(uio != NULL,
254	    ("%s called with NULL uio pointer", __func__));
255	KASSERT(error != NULL,
256	    ("%s called with NULL error pointer", __func__));
257
258	s = sbuf_new(s, NULL, uio->uio_resid + 1, 0);
259	if (s == NULL) {
260		*error = ENOMEM;
261		return (NULL);
262	}
263	*error = uiomove(s->s_buf, uio->uio_resid, uio);
264	if (*error != 0) {
265		sbuf_delete(s);
266		return (NULL);
267	}
268	s->s_len = s->s_size - 1;
269	if (SBUF_ISSECTION(s))
270		s->s_sect_len = s->s_size - 1;
271	*error = 0;
272	return (s);
273}
274#endif
275
276int
277sbuf_get_flags(struct sbuf *s)
278{
279
280	return (s->s_flags & SBUF_USRFLAGMSK);
281}
282
283void
284sbuf_clear_flags(struct sbuf *s, int flags)
285{
286
287	s->s_flags &= ~(flags & SBUF_USRFLAGMSK);
288}
289
290void
291sbuf_set_flags(struct sbuf *s, int flags)
292{
293
294
295	s->s_flags |= (flags & SBUF_USRFLAGMSK);
296}
297
298/*
299 * Clear an sbuf and reset its position.
300 */
301void
302sbuf_clear(struct sbuf *s)
303{
304
305	assert_sbuf_integrity(s);
306	/* don't care if it's finished or not */
307
308	SBUF_CLEARFLAG(s, SBUF_FINISHED);
309	s->s_error = 0;
310	s->s_len = 0;
311	s->s_sect_len = 0;
312}
313
314/*
315 * Set the sbuf's end position to an arbitrary value.
316 * Effectively truncates the sbuf at the new position.
317 */
318int
319sbuf_setpos(struct sbuf *s, ssize_t pos)
320{
321
322	assert_sbuf_integrity(s);
323	assert_sbuf_state(s, 0);
324
325	KASSERT(pos >= 0,
326	    ("attempt to seek to a negative position (%jd)", (intmax_t)pos));
327	KASSERT(pos < s->s_size,
328	    ("attempt to seek past end of sbuf (%jd >= %jd)",
329	    (intmax_t)pos, (intmax_t)s->s_size));
330	KASSERT(!SBUF_ISSECTION(s),
331	    ("attempt to seek when in a section"));
332
333	if (pos < 0 || pos > s->s_len)
334		return (-1);
335	s->s_len = pos;
336	return (0);
337}
338
339/*
340 * Set up a drain function and argument on an sbuf to flush data to
341 * when the sbuf buffer overflows.
342 */
343void
344sbuf_set_drain(struct sbuf *s, sbuf_drain_func *func, void *ctx)
345{
346
347	assert_sbuf_state(s, 0);
348	assert_sbuf_integrity(s);
349	KASSERT(func == s->s_drain_func || s->s_len == 0,
350	    ("Cannot change drain to %p on non-empty sbuf %p", func, s));
351	s->s_drain_func = func;
352	s->s_drain_arg = ctx;
353}
354
355/*
356 * Call the drain and process the return.
357 */
358int
359sbuf_drain(struct sbuf *s)
360{
361	int len;
362
363	/*
364	 * Immediately return when no work to do,
365	 * or an error has already been accumulated.
366	 */
367	if ((s->s_len == 0) || (s->s_error != 0))
368		return(s->s_error);
369
370	len = s->s_drain_func(s->s_drain_arg, s->s_buf, s->s_len);
371	if (len < 0) {
372		s->s_error = -len;
373		return (s->s_error);
374	}
375	KASSERT(len > 0 && len <= s->s_len,
376	    ("Bad drain amount %d for sbuf %p", len, s));
377	s->s_len -= len;
378	/*
379	 * Fast path for the expected case where all the data was
380	 * drained.
381	 */
382	if (s->s_len == 0)
383		return (0);
384	/*
385	 * Move the remaining characters to the beginning of the
386	 * string.
387	 */
388	memmove(s->s_buf, s->s_buf + len, s->s_len);
389	return (0);
390}
391
392/*
393 * Append bytes to an sbuf.  This is the core function for appending
394 * to an sbuf and is the main place that deals with extending the
395 * buffer and marking overflow.
396 */
397static void
398sbuf_put_bytes(struct sbuf *s, const char *buf, size_t len)
399{
400	size_t n;
401
402	assert_sbuf_integrity(s);
403	assert_sbuf_state(s, 0);
404
405	if (s->s_error != 0)
406		return;
407	while (len > 0) {
408		if (SBUF_FREESPACE(s) <= 0) {
409			/*
410			 * If there is a drain, use it, otherwise extend the
411			 * buffer.
412			 */
413			if (s->s_drain_func != NULL)
414				(void)sbuf_drain(s);
415			else if (sbuf_extend(s, len > INT_MAX ? INT_MAX : len)
416			    < 0)
417				s->s_error = ENOMEM;
418			if (s->s_error != 0)
419				return;
420		}
421		n = SBUF_FREESPACE(s);
422		if (len < n)
423			n = len;
424		memcpy(&s->s_buf[s->s_len], buf, n);
425		s->s_len += n;
426		if (SBUF_ISSECTION(s))
427			s->s_sect_len += n;
428		len -= n;
429		buf += n;
430	}
431}
432
433static void
434sbuf_put_byte(struct sbuf *s, char c)
435{
436
437	sbuf_put_bytes(s, &c, 1);
438}
439
440/*
441 * Append a byte string to an sbuf.
442 */
443int
444sbuf_bcat(struct sbuf *s, const void *buf, size_t len)
445{
446
447	sbuf_put_bytes(s, buf, len);
448	if (s->s_error != 0)
449		return (-1);
450	return (0);
451}
452
453#ifdef _KERNEL
454/*
455 * Copy a byte string from userland into an sbuf.
456 */
457int
458sbuf_bcopyin(struct sbuf *s, const void *uaddr, size_t len)
459{
460
461	assert_sbuf_integrity(s);
462	assert_sbuf_state(s, 0);
463	KASSERT(s->s_drain_func == NULL,
464	    ("Nonsensical copyin to sbuf %p with a drain", s));
465
466	if (s->s_error != 0)
467		return (-1);
468	if (len == 0)
469		return (0);
470	if (len > SBUF_FREESPACE(s)) {
471		sbuf_extend(s, len - SBUF_FREESPACE(s));
472		if (SBUF_FREESPACE(s) < len)
473			len = SBUF_FREESPACE(s);
474	}
475	if (copyin(uaddr, s->s_buf + s->s_len, len) != 0)
476		return (-1);
477	s->s_len += len;
478
479	return (0);
480}
481#endif
482
483/*
484 * Copy a byte string into an sbuf.
485 */
486int
487sbuf_bcpy(struct sbuf *s, const void *buf, size_t len)
488{
489
490	assert_sbuf_integrity(s);
491	assert_sbuf_state(s, 0);
492
493	sbuf_clear(s);
494	return (sbuf_bcat(s, buf, len));
495}
496
497/*
498 * Append a string to an sbuf.
499 */
500int
501sbuf_cat(struct sbuf *s, const char *str)
502{
503	size_t n;
504
505	n = strlen(str);
506	sbuf_put_bytes(s, str, n);
507	if (s->s_error != 0)
508		return (-1);
509	return (0);
510}
511
512#ifdef _KERNEL
513/*
514 * Append a string from userland to an sbuf.
515 */
516int
517sbuf_copyin(struct sbuf *s, const void *uaddr, size_t len)
518{
519	size_t done;
520
521	assert_sbuf_integrity(s);
522	assert_sbuf_state(s, 0);
523	KASSERT(s->s_drain_func == NULL,
524	    ("Nonsensical copyin to sbuf %p with a drain", s));
525
526	if (s->s_error != 0)
527		return (-1);
528
529	if (len == 0)
530		len = SBUF_FREESPACE(s);	/* XXX return 0? */
531	if (len > SBUF_FREESPACE(s)) {
532		sbuf_extend(s, len);
533		if (SBUF_FREESPACE(s) < len)
534			len = SBUF_FREESPACE(s);
535	}
536	switch (copyinstr(uaddr, s->s_buf + s->s_len, len + 1, &done)) {
537	case ENAMETOOLONG:
538		s->s_error = ENOMEM;
539		/* fall through */
540	case 0:
541		s->s_len += done - 1;
542		if (SBUF_ISSECTION(s))
543			s->s_sect_len += done - 1;
544		break;
545	default:
546		return (-1);	/* XXX */
547	}
548
549	return (done);
550}
551#endif
552
553/*
554 * Copy a string into an sbuf.
555 */
556int
557sbuf_cpy(struct sbuf *s, const char *str)
558{
559
560	assert_sbuf_integrity(s);
561	assert_sbuf_state(s, 0);
562
563	sbuf_clear(s);
564	return (sbuf_cat(s, str));
565}
566
567/*
568 * Format the given argument list and append the resulting string to an sbuf.
569 */
570#ifdef _KERNEL
571
572/*
573 * Append a non-NUL character to an sbuf.  This prototype signature is
574 * suitable for use with kvprintf(9).
575 */
576static void
577sbuf_putc_func(int c, void *arg)
578{
579
580	if (c != '\0')
581		sbuf_put_byte(arg, c);
582}
583
584int
585sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap)
586{
587
588	assert_sbuf_integrity(s);
589	assert_sbuf_state(s, 0);
590
591	KASSERT(fmt != NULL,
592	    ("%s called with a NULL format string", __func__));
593
594	(void)kvprintf(fmt, sbuf_putc_func, s, 10, ap);
595	if (s->s_error != 0)
596		return (-1);
597	return (0);
598}
599#else /* !_KERNEL */
600int
601sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap)
602{
603	va_list ap_copy;
604	int error, len;
605
606	assert_sbuf_integrity(s);
607	assert_sbuf_state(s, 0);
608
609	KASSERT(fmt != NULL,
610	    ("%s called with a NULL format string", __func__));
611
612	if (s->s_error != 0)
613		return (-1);
614
615	/*
616	 * For the moment, there is no way to get vsnprintf(3) to hand
617	 * back a character at a time, to push everything into
618	 * sbuf_putc_func() as was done for the kernel.
619	 *
620	 * In userspace, while drains are useful, there's generally
621	 * not a problem attempting to malloc(3) on out of space.  So
622	 * expand a userland sbuf if there is not enough room for the
623	 * data produced by sbuf_[v]printf(3).
624	 */
625
626	error = 0;
627	do {
628		va_copy(ap_copy, ap);
629		len = vsnprintf(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1,
630		    fmt, ap_copy);
631		if (len < 0) {
632			s->s_error = errno;
633			return (-1);
634		}
635		va_end(ap_copy);
636
637		if (SBUF_FREESPACE(s) >= len)
638			break;
639		/* Cannot print with the current available space. */
640		if (s->s_drain_func != NULL && s->s_len > 0)
641			error = sbuf_drain(s);
642		else
643			error = sbuf_extend(s, len - SBUF_FREESPACE(s));
644	} while (error == 0);
645
646	/*
647	 * s->s_len is the length of the string, without the terminating nul.
648	 * When updating s->s_len, we must subtract 1 from the length that
649	 * we passed into vsnprintf() because that length includes the
650	 * terminating nul.
651	 *
652	 * vsnprintf() returns the amount that would have been copied,
653	 * given sufficient space, so don't over-increment s_len.
654	 */
655	if (SBUF_FREESPACE(s) < len)
656		len = SBUF_FREESPACE(s);
657	s->s_len += len;
658	if (SBUF_ISSECTION(s))
659		s->s_sect_len += len;
660	if (!SBUF_HASROOM(s) && !SBUF_CANEXTEND(s))
661		s->s_error = ENOMEM;
662
663	KASSERT(s->s_len < s->s_size,
664	    ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size));
665
666	if (s->s_error != 0)
667		return (-1);
668	return (0);
669}
670#endif /* _KERNEL */
671
672/*
673 * Format the given arguments and append the resulting string to an sbuf.
674 */
675int
676sbuf_printf(struct sbuf *s, const char *fmt, ...)
677{
678	va_list ap;
679	int result;
680
681	va_start(ap, fmt);
682	result = sbuf_vprintf(s, fmt, ap);
683	va_end(ap);
684	return (result);
685}
686
687/*
688 * Append a character to an sbuf.
689 */
690int
691sbuf_putc(struct sbuf *s, int c)
692{
693
694	sbuf_put_byte(s, c);
695	if (s->s_error != 0)
696		return (-1);
697	return (0);
698}
699
700/*
701 * Trim whitespace characters from end of an sbuf.
702 */
703int
704sbuf_trim(struct sbuf *s)
705{
706
707	assert_sbuf_integrity(s);
708	assert_sbuf_state(s, 0);
709	KASSERT(s->s_drain_func == NULL,
710	    ("%s makes no sense on sbuf %p with drain", __func__, s));
711
712	if (s->s_error != 0)
713		return (-1);
714
715	while (s->s_len > 0 && isspace(s->s_buf[s->s_len-1])) {
716		--s->s_len;
717		if (SBUF_ISSECTION(s))
718			s->s_sect_len--;
719	}
720
721	return (0);
722}
723
724/*
725 * Check if an sbuf has an error.
726 */
727int
728sbuf_error(const struct sbuf *s)
729{
730
731	return (s->s_error);
732}
733
734/*
735 * Finish off an sbuf.
736 */
737int
738sbuf_finish(struct sbuf *s)
739{
740
741	assert_sbuf_integrity(s);
742	assert_sbuf_state(s, 0);
743
744	s->s_buf[s->s_len] = '\0';
745	if (SBUF_NULINCLUDED(s))
746		s->s_len++;
747	if (s->s_drain_func != NULL) {
748		while (s->s_len > 0 && s->s_error == 0)
749			s->s_error = sbuf_drain(s);
750	}
751	SBUF_SETFLAG(s, SBUF_FINISHED);
752#ifdef _KERNEL
753	return (s->s_error);
754#else
755	if (s->s_error != 0) {
756		errno = s->s_error;
757		return (-1);
758	}
759	return (0);
760#endif
761}
762
763/*
764 * Return a pointer to the sbuf data.
765 */
766char *
767sbuf_data(struct sbuf *s)
768{
769
770	assert_sbuf_integrity(s);
771	assert_sbuf_state(s, SBUF_FINISHED);
772	KASSERT(s->s_drain_func == NULL,
773	    ("%s makes no sense on sbuf %p with drain", __func__, s));
774
775	return (s->s_buf);
776}
777
778/*
779 * Return the length of the sbuf data.
780 */
781ssize_t
782sbuf_len(struct sbuf *s)
783{
784
785	assert_sbuf_integrity(s);
786	/* don't care if it's finished or not */
787	KASSERT(s->s_drain_func == NULL,
788	    ("%s makes no sense on sbuf %p with drain", __func__, s));
789
790	if (s->s_error != 0)
791		return (-1);
792
793	/* If finished, nulterm is already in len, else add one. */
794	if (SBUF_NULINCLUDED(s) && !SBUF_ISFINISHED(s))
795		return (s->s_len + 1);
796	return (s->s_len);
797}
798
799/*
800 * Clear an sbuf, free its buffer if necessary.
801 */
802void
803sbuf_delete(struct sbuf *s)
804{
805	int isdyn;
806
807	assert_sbuf_integrity(s);
808	/* don't care if it's finished or not */
809
810	if (SBUF_ISDYNAMIC(s))
811		SBFREE(s->s_buf);
812	isdyn = SBUF_ISDYNSTRUCT(s);
813	memset(s, 0, sizeof(*s));
814	if (isdyn)
815		SBFREE(s);
816}
817
818/*
819 * Check if an sbuf has been finished.
820 */
821int
822sbuf_done(const struct sbuf *s)
823{
824
825	return (SBUF_ISFINISHED(s));
826}
827
828/*
829 * Start a section.
830 */
831void
832sbuf_start_section(struct sbuf *s, ssize_t *old_lenp)
833{
834
835	assert_sbuf_integrity(s);
836	assert_sbuf_state(s, 0);
837
838	if (!SBUF_ISSECTION(s)) {
839		KASSERT(s->s_sect_len == 0,
840		    ("s_sect_len != 0 when starting a section"));
841		if (old_lenp != NULL)
842			*old_lenp = -1;
843		SBUF_SETFLAG(s, SBUF_INSECTION);
844	} else {
845		KASSERT(old_lenp != NULL,
846		    ("s_sect_len should be saved when starting a subsection"));
847		*old_lenp = s->s_sect_len;
848		s->s_sect_len = 0;
849	}
850}
851
852/*
853 * End the section padding to the specified length with the specified
854 * character.
855 */
856ssize_t
857sbuf_end_section(struct sbuf *s, ssize_t old_len, size_t pad, int c)
858{
859	ssize_t len;
860
861	assert_sbuf_integrity(s);
862	assert_sbuf_state(s, 0);
863	KASSERT(SBUF_ISSECTION(s),
864	    ("attempt to end a section when not in a section"));
865
866	if (pad > 1) {
867		len = roundup(s->s_sect_len, pad) - s->s_sect_len;
868		for (; s->s_error == 0 && len > 0; len--)
869			sbuf_put_byte(s, c);
870	}
871	len = s->s_sect_len;
872	if (old_len == -1) {
873		s->s_sect_len = 0;
874		SBUF_CLEARFLAG(s, SBUF_INSECTION);
875	} else {
876		s->s_sect_len += old_len;
877	}
878	if (s->s_error != 0)
879		return (-1);
880	return (len);
881}
882