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