160ec4130SDag-Erling Smørgrav /*- 2*8a36da99SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*8a36da99SPedro F. Giffuni * 4546d7890SDag-Erling Smørgrav * Copyright (c) 2000-2008 Poul-Henning Kamp 5546d7890SDag-Erling Smørgrav * Copyright (c) 2000-2008 Dag-Erling Coïdan Smørgrav 660ec4130SDag-Erling Smørgrav * All rights reserved. 760ec4130SDag-Erling Smørgrav * 860ec4130SDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 960ec4130SDag-Erling Smørgrav * modification, are permitted provided that the following conditions 1060ec4130SDag-Erling Smørgrav * are met: 1160ec4130SDag-Erling Smørgrav * 1. Redistributions of source code must retain the above copyright 1260ec4130SDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer 1360ec4130SDag-Erling Smørgrav * in this position and unchanged. 1460ec4130SDag-Erling Smørgrav * 2. Redistributions in binary form must reproduce the above copyright 1560ec4130SDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer in the 1660ec4130SDag-Erling Smørgrav * documentation and/or other materials provided with the distribution. 1760ec4130SDag-Erling Smørgrav * 18546d7890SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19546d7890SDag-Erling Smørgrav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20546d7890SDag-Erling Smørgrav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21546d7890SDag-Erling Smørgrav * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22546d7890SDag-Erling Smørgrav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23546d7890SDag-Erling Smørgrav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24546d7890SDag-Erling Smørgrav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25546d7890SDag-Erling Smørgrav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26546d7890SDag-Erling Smørgrav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27546d7890SDag-Erling Smørgrav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28546d7890SDag-Erling Smørgrav * SUCH DAMAGE. 2960ec4130SDag-Erling Smørgrav */ 3060ec4130SDag-Erling Smørgrav 31677b542eSDavid E. O'Brien #include <sys/cdefs.h> 32677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 33677b542eSDavid E. O'Brien 3460ec4130SDag-Erling Smørgrav #include <sys/param.h> 353393f8daSKenneth D. Merry 363393f8daSKenneth D. Merry #ifdef _KERNEL 375b6db477SDag-Erling Smørgrav #include <sys/ctype.h> 384351ba27SMatthew D Fleming #include <sys/errno.h> 3960ec4130SDag-Erling Smørgrav #include <sys/kernel.h> 402f1c4e0eSConrad Meyer #include <sys/limits.h> 4160ec4130SDag-Erling Smørgrav #include <sys/malloc.h> 4260ec4130SDag-Erling Smørgrav #include <sys/systm.h> 435b6db477SDag-Erling Smørgrav #include <sys/uio.h> 4460ec4130SDag-Erling Smørgrav #include <machine/stdarg.h> 453393f8daSKenneth D. Merry #else /* _KERNEL */ 465b6db477SDag-Erling Smørgrav #include <ctype.h> 474351ba27SMatthew D Fleming #include <errno.h> 482f1c4e0eSConrad Meyer #include <limits.h> 493393f8daSKenneth D. Merry #include <stdarg.h> 507195eb40SKelly Yancey #include <stdio.h> 519fa416caSJonathan Lemon #include <stdlib.h> 527195eb40SKelly Yancey #include <string.h> 533393f8daSKenneth D. Merry #endif /* _KERNEL */ 5460ec4130SDag-Erling Smørgrav 555b6db477SDag-Erling Smørgrav #include <sys/sbuf.h> 565b6db477SDag-Erling Smørgrav 573393f8daSKenneth D. Merry #ifdef _KERNEL 58c711aea6SPoul-Henning Kamp static MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers"); 590f7bc112SDag-Erling Smørgrav #define SBMALLOC(size) malloc(size, M_SBUF, M_WAITOK|M_ZERO) 603393f8daSKenneth D. Merry #define SBFREE(buf) free(buf, M_SBUF) 613393f8daSKenneth D. Merry #else /* _KERNEL */ 623393f8daSKenneth D. Merry #define KASSERT(e, m) 630f7bc112SDag-Erling Smørgrav #define SBMALLOC(size) calloc(1, size) 643393f8daSKenneth D. Merry #define SBFREE(buf) free(buf) 653393f8daSKenneth D. Merry #endif /* _KERNEL */ 6660ec4130SDag-Erling Smørgrav 674dc14139SDag-Erling Smørgrav /* 684dc14139SDag-Erling Smørgrav * Predicates 694dc14139SDag-Erling Smørgrav */ 704dc14139SDag-Erling Smørgrav #define SBUF_ISDYNAMIC(s) ((s)->s_flags & SBUF_DYNAMIC) 71d6479358SDag-Erling Smørgrav #define SBUF_ISDYNSTRUCT(s) ((s)->s_flags & SBUF_DYNSTRUCT) 724dc14139SDag-Erling Smørgrav #define SBUF_ISFINISHED(s) ((s)->s_flags & SBUF_FINISHED) 734dc14139SDag-Erling Smørgrav #define SBUF_HASROOM(s) ((s)->s_len < (s)->s_size - 1) 74eb05ee7aSPoul-Henning Kamp #define SBUF_FREESPACE(s) ((s)->s_size - ((s)->s_len + 1)) 757195eb40SKelly Yancey #define SBUF_CANEXTEND(s) ((s)->s_flags & SBUF_AUTOEXTEND) 76ddb9b612SMikolaj Golub #define SBUF_ISSECTION(s) ((s)->s_flags & SBUF_INSECTION) 778d5628fdSIan Lepore #define SBUF_NULINCLUDED(s) ((s)->s_flags & SBUF_INCLUDENUL) 78a8ec96afSLawrence Stewart #define SBUF_ISDRAINTOEOR(s) ((s)->s_flags & SBUF_DRAINTOEOR) 79a8ec96afSLawrence Stewart #define SBUF_DODRAINTOEOR(s) (SBUF_ISSECTION(s) && SBUF_ISDRAINTOEOR(s)) 804dc14139SDag-Erling Smørgrav 814dc14139SDag-Erling Smørgrav /* 824dc14139SDag-Erling Smørgrav * Set / clear flags 834dc14139SDag-Erling Smørgrav */ 844dc14139SDag-Erling Smørgrav #define SBUF_SETFLAG(s, f) do { (s)->s_flags |= (f); } while (0) 854dc14139SDag-Erling Smørgrav #define SBUF_CLEARFLAG(s, f) do { (s)->s_flags &= ~(f); } while (0) 864dc14139SDag-Erling Smørgrav 87612d9391SIan Lepore #define SBUF_MINSIZE 2 /* Min is 1 byte + nulterm. */ 887195eb40SKelly Yancey #define SBUF_MINEXTENDSIZE 16 /* Should be power of 2. */ 89eb05ee7aSPoul-Henning Kamp 90eb05ee7aSPoul-Henning Kamp #ifdef PAGE_SIZE 917195eb40SKelly Yancey #define SBUF_MAXEXTENDSIZE PAGE_SIZE 927195eb40SKelly Yancey #define SBUF_MAXEXTENDINCR PAGE_SIZE 93eb05ee7aSPoul-Henning Kamp #else 94eb05ee7aSPoul-Henning Kamp #define SBUF_MAXEXTENDSIZE 4096 95eb05ee7aSPoul-Henning Kamp #define SBUF_MAXEXTENDINCR 4096 96eb05ee7aSPoul-Henning Kamp #endif 977195eb40SKelly Yancey 984dc14139SDag-Erling Smørgrav /* 994dc14139SDag-Erling Smørgrav * Debugging support 1004dc14139SDag-Erling Smørgrav */ 1013393f8daSKenneth D. Merry #if defined(_KERNEL) && defined(INVARIANTS) 102546d7890SDag-Erling Smørgrav 10360ec4130SDag-Erling Smørgrav static void 104a5e7c7daSPeter Wemm _assert_sbuf_integrity(const char *fun, struct sbuf *s) 10560ec4130SDag-Erling Smørgrav { 106546d7890SDag-Erling Smørgrav 10760ec4130SDag-Erling Smørgrav KASSERT(s != NULL, 108cab5b963SDag-Erling Smørgrav ("%s called with a NULL sbuf pointer", fun)); 10960ec4130SDag-Erling Smørgrav KASSERT(s->s_buf != NULL, 1107195eb40SKelly Yancey ("%s called with uninitialized or corrupt sbuf", fun)); 1118d5628fdSIan Lepore if (SBUF_ISFINISHED(s) && SBUF_NULINCLUDED(s)) { 1128d5628fdSIan Lepore KASSERT(s->s_len <= s->s_size, 1138d5628fdSIan Lepore ("wrote past end of sbuf (%jd >= %jd)", 1148d5628fdSIan Lepore (intmax_t)s->s_len, (intmax_t)s->s_size)); 1158d5628fdSIan Lepore } else { 11660ec4130SDag-Erling Smørgrav KASSERT(s->s_len < s->s_size, 11771c2bc5cSPoul-Henning Kamp ("wrote past end of sbuf (%jd >= %jd)", 11871c2bc5cSPoul-Henning Kamp (intmax_t)s->s_len, (intmax_t)s->s_size)); 11960ec4130SDag-Erling Smørgrav } 1208d5628fdSIan Lepore } 12160ec4130SDag-Erling Smørgrav 12260ec4130SDag-Erling Smørgrav static void 123a5e7c7daSPeter Wemm _assert_sbuf_state(const char *fun, struct sbuf *s, int state) 12460ec4130SDag-Erling Smørgrav { 125546d7890SDag-Erling Smørgrav 12660ec4130SDag-Erling Smørgrav KASSERT((s->s_flags & SBUF_FINISHED) == state, 127cab5b963SDag-Erling Smørgrav ("%s called with %sfinished or corrupt sbuf", fun, 12860ec4130SDag-Erling Smørgrav (state ? "un" : ""))); 12960ec4130SDag-Erling Smørgrav } 130546d7890SDag-Erling Smørgrav 131a48740b6SDavid E. O'Brien #define assert_sbuf_integrity(s) _assert_sbuf_integrity(__func__, (s)) 132a48740b6SDavid E. O'Brien #define assert_sbuf_state(s, i) _assert_sbuf_state(__func__, (s), (i)) 133546d7890SDag-Erling Smørgrav 1343393f8daSKenneth D. Merry #else /* _KERNEL && INVARIANTS */ 135546d7890SDag-Erling Smørgrav 13660ec4130SDag-Erling Smørgrav #define assert_sbuf_integrity(s) do { } while (0) 13760ec4130SDag-Erling Smørgrav #define assert_sbuf_state(s, i) do { } while (0) 138546d7890SDag-Erling Smørgrav 1393393f8daSKenneth D. Merry #endif /* _KERNEL && INVARIANTS */ 14060ec4130SDag-Erling Smørgrav 141181ff3d5SMatthew D Fleming #ifdef CTASSERT 142f4bafab8SMatthew D Fleming CTASSERT(powerof2(SBUF_MAXEXTENDSIZE)); 143f4bafab8SMatthew D Fleming CTASSERT(powerof2(SBUF_MAXEXTENDINCR)); 144969292fbSMatthew D Fleming #endif 145f4bafab8SMatthew D Fleming 1467195eb40SKelly Yancey static int 1477195eb40SKelly Yancey sbuf_extendsize(int size) 1487195eb40SKelly Yancey { 1497195eb40SKelly Yancey int newsize; 1507195eb40SKelly Yancey 151f4bafab8SMatthew D Fleming if (size < (int)SBUF_MAXEXTENDSIZE) { 1527195eb40SKelly Yancey newsize = SBUF_MINEXTENDSIZE; 153f4bafab8SMatthew D Fleming while (newsize < size) 1547195eb40SKelly Yancey newsize *= 2; 155f4bafab8SMatthew D Fleming } else { 156f4bafab8SMatthew D Fleming newsize = roundup2(size, SBUF_MAXEXTENDINCR); 1577195eb40SKelly Yancey } 158f5a5dc5dSMatthew D Fleming KASSERT(newsize >= size, ("%s: %d < %d\n", __func__, newsize, size)); 1597195eb40SKelly Yancey return (newsize); 1607195eb40SKelly Yancey } 1617195eb40SKelly Yancey 1627195eb40SKelly Yancey /* 1637195eb40SKelly Yancey * Extend an sbuf. 1647195eb40SKelly Yancey */ 1657195eb40SKelly Yancey static int 1667195eb40SKelly Yancey sbuf_extend(struct sbuf *s, int addlen) 1677195eb40SKelly Yancey { 1687195eb40SKelly Yancey char *newbuf; 169adecd05bSPietro Cerutti int newsize; 1707195eb40SKelly Yancey 1717195eb40SKelly Yancey if (!SBUF_CANEXTEND(s)) 1727195eb40SKelly Yancey return (-1); 1737195eb40SKelly Yancey newsize = sbuf_extendsize(s->s_size + addlen); 174546d7890SDag-Erling Smørgrav newbuf = SBMALLOC(newsize); 1757195eb40SKelly Yancey if (newbuf == NULL) 1767195eb40SKelly Yancey return (-1); 177384bf94cSPoul-Henning Kamp memcpy(newbuf, s->s_buf, s->s_size); 1787195eb40SKelly Yancey if (SBUF_ISDYNAMIC(s)) 1797195eb40SKelly Yancey SBFREE(s->s_buf); 1807195eb40SKelly Yancey else 1817195eb40SKelly Yancey SBUF_SETFLAG(s, SBUF_DYNAMIC); 1827195eb40SKelly Yancey s->s_buf = newbuf; 1837195eb40SKelly Yancey s->s_size = newsize; 1847195eb40SKelly Yancey return (0); 1857195eb40SKelly Yancey } 1867195eb40SKelly Yancey 18760ec4130SDag-Erling Smørgrav /* 188384bf94cSPoul-Henning Kamp * Initialize the internals of an sbuf. 189384bf94cSPoul-Henning Kamp * If buf is non-NULL, it points to a static or already-allocated string 190384bf94cSPoul-Henning Kamp * big enough to hold at least length characters. 191384bf94cSPoul-Henning Kamp */ 192384bf94cSPoul-Henning Kamp static struct sbuf * 193adecd05bSPietro Cerutti sbuf_newbuf(struct sbuf *s, char *buf, int length, int flags) 194384bf94cSPoul-Henning Kamp { 195384bf94cSPoul-Henning Kamp 196384bf94cSPoul-Henning Kamp memset(s, 0, sizeof(*s)); 197384bf94cSPoul-Henning Kamp s->s_flags = flags; 198384bf94cSPoul-Henning Kamp s->s_size = length; 199384bf94cSPoul-Henning Kamp s->s_buf = buf; 200384bf94cSPoul-Henning Kamp 201384bf94cSPoul-Henning Kamp if ((s->s_flags & SBUF_AUTOEXTEND) == 0) { 202612d9391SIan Lepore KASSERT(s->s_size >= SBUF_MINSIZE, 203612d9391SIan Lepore ("attempt to create an sbuf smaller than %d bytes", 204612d9391SIan Lepore SBUF_MINSIZE)); 205384bf94cSPoul-Henning Kamp } 206384bf94cSPoul-Henning Kamp 207384bf94cSPoul-Henning Kamp if (s->s_buf != NULL) 208384bf94cSPoul-Henning Kamp return (s); 209384bf94cSPoul-Henning Kamp 210384bf94cSPoul-Henning Kamp if ((flags & SBUF_AUTOEXTEND) != 0) 211384bf94cSPoul-Henning Kamp s->s_size = sbuf_extendsize(s->s_size); 212384bf94cSPoul-Henning Kamp 213384bf94cSPoul-Henning Kamp s->s_buf = SBMALLOC(s->s_size); 214384bf94cSPoul-Henning Kamp if (s->s_buf == NULL) 215384bf94cSPoul-Henning Kamp return (NULL); 216384bf94cSPoul-Henning Kamp SBUF_SETFLAG(s, SBUF_DYNAMIC); 217384bf94cSPoul-Henning Kamp return (s); 218384bf94cSPoul-Henning Kamp } 219384bf94cSPoul-Henning Kamp 220384bf94cSPoul-Henning Kamp /* 22160ec4130SDag-Erling Smørgrav * Initialize an sbuf. 22260ec4130SDag-Erling Smørgrav * If buf is non-NULL, it points to a static or already-allocated string 22360ec4130SDag-Erling Smørgrav * big enough to hold at least length characters. 22460ec4130SDag-Erling Smørgrav */ 225d6479358SDag-Erling Smørgrav struct sbuf * 2264dc14139SDag-Erling Smørgrav sbuf_new(struct sbuf *s, char *buf, int length, int flags) 22760ec4130SDag-Erling Smørgrav { 228546d7890SDag-Erling Smørgrav 2294dc14139SDag-Erling Smørgrav KASSERT(length >= 0, 2304dc14139SDag-Erling Smørgrav ("attempt to create an sbuf of negative length (%d)", length)); 2317195eb40SKelly Yancey KASSERT((flags & ~SBUF_USRFLAGMSK) == 0, 2327195eb40SKelly Yancey ("%s called with invalid flags", __func__)); 23360ec4130SDag-Erling Smørgrav 2347195eb40SKelly Yancey flags &= SBUF_USRFLAGMSK; 235384bf94cSPoul-Henning Kamp if (s != NULL) 236384bf94cSPoul-Henning Kamp return (sbuf_newbuf(s, buf, length, flags)); 237384bf94cSPoul-Henning Kamp 238546d7890SDag-Erling Smørgrav s = SBMALLOC(sizeof(*s)); 239d6479358SDag-Erling Smørgrav if (s == NULL) 240d6479358SDag-Erling Smørgrav return (NULL); 241384bf94cSPoul-Henning Kamp if (sbuf_newbuf(s, buf, length, flags) == NULL) { 242d6479358SDag-Erling Smørgrav SBFREE(s); 243d6479358SDag-Erling Smørgrav return (NULL); 244d6479358SDag-Erling Smørgrav } 245384bf94cSPoul-Henning Kamp SBUF_SETFLAG(s, SBUF_DYNSTRUCT); 246d6479358SDag-Erling Smørgrav return (s); 24760ec4130SDag-Erling Smørgrav } 24860ec4130SDag-Erling Smørgrav 2495b6db477SDag-Erling Smørgrav #ifdef _KERNEL 2505b6db477SDag-Erling Smørgrav /* 2515b6db477SDag-Erling Smørgrav * Create an sbuf with uio data 2525b6db477SDag-Erling Smørgrav */ 2535b6db477SDag-Erling Smørgrav struct sbuf * 2545b6db477SDag-Erling Smørgrav sbuf_uionew(struct sbuf *s, struct uio *uio, int *error) 2555b6db477SDag-Erling Smørgrav { 256546d7890SDag-Erling Smørgrav 2575b6db477SDag-Erling Smørgrav KASSERT(uio != NULL, 258a48740b6SDavid E. O'Brien ("%s called with NULL uio pointer", __func__)); 2595b6db477SDag-Erling Smørgrav KASSERT(error != NULL, 260a48740b6SDavid E. O'Brien ("%s called with NULL error pointer", __func__)); 2615b6db477SDag-Erling Smørgrav 2625b6db477SDag-Erling Smørgrav s = sbuf_new(s, NULL, uio->uio_resid + 1, 0); 2635b6db477SDag-Erling Smørgrav if (s == NULL) { 2645b6db477SDag-Erling Smørgrav *error = ENOMEM; 2655b6db477SDag-Erling Smørgrav return (NULL); 2665b6db477SDag-Erling Smørgrav } 2675b6db477SDag-Erling Smørgrav *error = uiomove(s->s_buf, uio->uio_resid, uio); 2685b6db477SDag-Erling Smørgrav if (*error != 0) { 2695b6db477SDag-Erling Smørgrav sbuf_delete(s); 2705b6db477SDag-Erling Smørgrav return (NULL); 2715b6db477SDag-Erling Smørgrav } 2725b6db477SDag-Erling Smørgrav s->s_len = s->s_size - 1; 273ddb9b612SMikolaj Golub if (SBUF_ISSECTION(s)) 274ddb9b612SMikolaj Golub s->s_sect_len = s->s_size - 1; 2755b6db477SDag-Erling Smørgrav *error = 0; 2765b6db477SDag-Erling Smørgrav return (s); 2775b6db477SDag-Erling Smørgrav } 2785b6db477SDag-Erling Smørgrav #endif 2795b6db477SDag-Erling Smørgrav 280f4d28142SIan Lepore int 281f4d28142SIan Lepore sbuf_get_flags(struct sbuf *s) 282f4d28142SIan Lepore { 283f4d28142SIan Lepore 284f4d28142SIan Lepore return (s->s_flags & SBUF_USRFLAGMSK); 285f4d28142SIan Lepore } 286f4d28142SIan Lepore 287f4d28142SIan Lepore void 288f4d28142SIan Lepore sbuf_clear_flags(struct sbuf *s, int flags) 289f4d28142SIan Lepore { 290f4d28142SIan Lepore 291f4d28142SIan Lepore s->s_flags &= ~(flags & SBUF_USRFLAGMSK); 292f4d28142SIan Lepore } 293f4d28142SIan Lepore 294f4d28142SIan Lepore void 295f4d28142SIan Lepore sbuf_set_flags(struct sbuf *s, int flags) 296f4d28142SIan Lepore { 297f4d28142SIan Lepore 298f4d28142SIan Lepore 299f4d28142SIan Lepore s->s_flags |= (flags & SBUF_USRFLAGMSK); 300f4d28142SIan Lepore } 301f4d28142SIan Lepore 30260ec4130SDag-Erling Smørgrav /* 3037195eb40SKelly Yancey * Clear an sbuf and reset its position. 3044dc14139SDag-Erling Smørgrav */ 3054dc14139SDag-Erling Smørgrav void 3064dc14139SDag-Erling Smørgrav sbuf_clear(struct sbuf *s) 3074dc14139SDag-Erling Smørgrav { 308546d7890SDag-Erling Smørgrav 3094dc14139SDag-Erling Smørgrav assert_sbuf_integrity(s); 3109fa2ef3dSDag-Erling Smørgrav /* don't care if it's finished or not */ 3114dc14139SDag-Erling Smørgrav 3124dc14139SDag-Erling Smørgrav SBUF_CLEARFLAG(s, SBUF_FINISHED); 3134351ba27SMatthew D Fleming s->s_error = 0; 3144dc14139SDag-Erling Smørgrav s->s_len = 0; 315a8ec96afSLawrence Stewart s->s_rec_off = 0; 316ddb9b612SMikolaj Golub s->s_sect_len = 0; 3174dc14139SDag-Erling Smørgrav } 3184dc14139SDag-Erling Smørgrav 3194dc14139SDag-Erling Smørgrav /* 3207195eb40SKelly Yancey * Set the sbuf's end position to an arbitrary value. 3217195eb40SKelly Yancey * Effectively truncates the sbuf at the new position. 32260ec4130SDag-Erling Smørgrav */ 32360ec4130SDag-Erling Smørgrav int 324adecd05bSPietro Cerutti sbuf_setpos(struct sbuf *s, ssize_t pos) 32560ec4130SDag-Erling Smørgrav { 326546d7890SDag-Erling Smørgrav 32760ec4130SDag-Erling Smørgrav assert_sbuf_integrity(s); 32860ec4130SDag-Erling Smørgrav assert_sbuf_state(s, 0); 32960ec4130SDag-Erling Smørgrav 330adecd05bSPietro Cerutti KASSERT(pos >= 0, 331adecd05bSPietro Cerutti ("attempt to seek to a negative position (%jd)", (intmax_t)pos)); 33260ec4130SDag-Erling Smørgrav KASSERT(pos < s->s_size, 33371c2bc5cSPoul-Henning Kamp ("attempt to seek past end of sbuf (%jd >= %jd)", 33471c2bc5cSPoul-Henning Kamp (intmax_t)pos, (intmax_t)s->s_size)); 335ddb9b612SMikolaj Golub KASSERT(!SBUF_ISSECTION(s), 336ddb9b612SMikolaj Golub ("attempt to seek when in a section")); 33760ec4130SDag-Erling Smørgrav 338adecd05bSPietro Cerutti if (pos < 0 || pos > s->s_len) 33960ec4130SDag-Erling Smørgrav return (-1); 34060ec4130SDag-Erling Smørgrav s->s_len = pos; 34160ec4130SDag-Erling Smørgrav return (0); 34260ec4130SDag-Erling Smørgrav } 34360ec4130SDag-Erling Smørgrav 34460ec4130SDag-Erling Smørgrav /* 3454351ba27SMatthew D Fleming * Set up a drain function and argument on an sbuf to flush data to 3464351ba27SMatthew D Fleming * when the sbuf buffer overflows. 3474351ba27SMatthew D Fleming */ 3484351ba27SMatthew D Fleming void 3494351ba27SMatthew D Fleming sbuf_set_drain(struct sbuf *s, sbuf_drain_func *func, void *ctx) 3504351ba27SMatthew D Fleming { 3514351ba27SMatthew D Fleming 3524351ba27SMatthew D Fleming assert_sbuf_state(s, 0); 3534351ba27SMatthew D Fleming assert_sbuf_integrity(s); 3544351ba27SMatthew D Fleming KASSERT(func == s->s_drain_func || s->s_len == 0, 3554351ba27SMatthew D Fleming ("Cannot change drain to %p on non-empty sbuf %p", func, s)); 3564351ba27SMatthew D Fleming s->s_drain_func = func; 3574351ba27SMatthew D Fleming s->s_drain_arg = ctx; 3584351ba27SMatthew D Fleming } 3594351ba27SMatthew D Fleming 3604351ba27SMatthew D Fleming /* 3614351ba27SMatthew D Fleming * Call the drain and process the return. 3624351ba27SMatthew D Fleming */ 3634351ba27SMatthew D Fleming static int 3644351ba27SMatthew D Fleming sbuf_drain(struct sbuf *s) 3654351ba27SMatthew D Fleming { 3664351ba27SMatthew D Fleming int len; 3674351ba27SMatthew D Fleming 3684351ba27SMatthew D Fleming KASSERT(s->s_len > 0, ("Shouldn't drain empty sbuf %p", s)); 3694d369413SMatthew D Fleming KASSERT(s->s_error == 0, ("Called %s with error on %p", __func__, s)); 370a8ec96afSLawrence Stewart if (SBUF_DODRAINTOEOR(s) && s->s_rec_off == 0) 371a8ec96afSLawrence Stewart return (s->s_error = EDEADLK); 372a8ec96afSLawrence Stewart len = s->s_drain_func(s->s_drain_arg, s->s_buf, 373a8ec96afSLawrence Stewart SBUF_DODRAINTOEOR(s) ? s->s_rec_off : s->s_len); 3749a61faf6SLawrence Stewart if (len <= 0) { 3759a61faf6SLawrence Stewart s->s_error = len ? -len : EDEADLK; 3764351ba27SMatthew D Fleming return (s->s_error); 3774351ba27SMatthew D Fleming } 3784e657159SMatthew D Fleming KASSERT(len > 0 && len <= s->s_len, 3794e657159SMatthew D Fleming ("Bad drain amount %d for sbuf %p", len, s)); 3804351ba27SMatthew D Fleming s->s_len -= len; 381a8ec96afSLawrence Stewart s->s_rec_off -= len; 3824351ba27SMatthew D Fleming /* 3834351ba27SMatthew D Fleming * Fast path for the expected case where all the data was 3844351ba27SMatthew D Fleming * drained. 3854351ba27SMatthew D Fleming */ 3864351ba27SMatthew D Fleming if (s->s_len == 0) 3874351ba27SMatthew D Fleming return (0); 3884351ba27SMatthew D Fleming /* 3894351ba27SMatthew D Fleming * Move the remaining characters to the beginning of the 3904351ba27SMatthew D Fleming * string. 3914351ba27SMatthew D Fleming */ 3924351ba27SMatthew D Fleming memmove(s->s_buf, s->s_buf + len, s->s_len); 3934351ba27SMatthew D Fleming return (0); 3944351ba27SMatthew D Fleming } 3954351ba27SMatthew D Fleming 3964351ba27SMatthew D Fleming /* 3972f1c4e0eSConrad Meyer * Append bytes to an sbuf. This is the core function for appending 39801f6f5fcSMatthew D Fleming * to an sbuf and is the main place that deals with extending the 39901f6f5fcSMatthew D Fleming * buffer and marking overflow. 40001f6f5fcSMatthew D Fleming */ 40101f6f5fcSMatthew D Fleming static void 4022f1c4e0eSConrad Meyer sbuf_put_bytes(struct sbuf *s, const char *buf, size_t len) 40301f6f5fcSMatthew D Fleming { 4042f1c4e0eSConrad Meyer size_t n; 40501f6f5fcSMatthew D Fleming 40601f6f5fcSMatthew D Fleming assert_sbuf_integrity(s); 40701f6f5fcSMatthew D Fleming assert_sbuf_state(s, 0); 40801f6f5fcSMatthew D Fleming 4094d369413SMatthew D Fleming if (s->s_error != 0) 41001f6f5fcSMatthew D Fleming return; 4112f1c4e0eSConrad Meyer while (len > 0) { 41201f6f5fcSMatthew D Fleming if (SBUF_FREESPACE(s) <= 0) { 4134351ba27SMatthew D Fleming /* 4144351ba27SMatthew D Fleming * If there is a drain, use it, otherwise extend the 4154351ba27SMatthew D Fleming * buffer. 4164351ba27SMatthew D Fleming */ 4174351ba27SMatthew D Fleming if (s->s_drain_func != NULL) 4184351ba27SMatthew D Fleming (void)sbuf_drain(s); 4192f1c4e0eSConrad Meyer else if (sbuf_extend(s, len > INT_MAX ? INT_MAX : len) 4202f1c4e0eSConrad Meyer < 0) 4214d369413SMatthew D Fleming s->s_error = ENOMEM; 4224d369413SMatthew D Fleming if (s->s_error != 0) 42301f6f5fcSMatthew D Fleming return; 42401f6f5fcSMatthew D Fleming } 4252f1c4e0eSConrad Meyer n = SBUF_FREESPACE(s); 4262f1c4e0eSConrad Meyer if (len < n) 4272f1c4e0eSConrad Meyer n = len; 4282f1c4e0eSConrad Meyer memcpy(&s->s_buf[s->s_len], buf, n); 4292f1c4e0eSConrad Meyer s->s_len += n; 430ddb9b612SMikolaj Golub if (SBUF_ISSECTION(s)) 4312f1c4e0eSConrad Meyer s->s_sect_len += n; 4322f1c4e0eSConrad Meyer len -= n; 4332f1c4e0eSConrad Meyer buf += n; 4342f1c4e0eSConrad Meyer } 4352f1c4e0eSConrad Meyer } 4362f1c4e0eSConrad Meyer 4372f1c4e0eSConrad Meyer static void 4382f1c4e0eSConrad Meyer sbuf_put_byte(struct sbuf *s, char c) 4392f1c4e0eSConrad Meyer { 4402f1c4e0eSConrad Meyer 4412f1c4e0eSConrad Meyer sbuf_put_bytes(s, &c, 1); 44201f6f5fcSMatthew D Fleming } 44301f6f5fcSMatthew D Fleming 44401f6f5fcSMatthew D Fleming /* 445b0def2b5SDag-Erling Smørgrav * Append a byte string to an sbuf. 446b0def2b5SDag-Erling Smørgrav */ 447b0def2b5SDag-Erling Smørgrav int 448520df276SDag-Erling Smørgrav sbuf_bcat(struct sbuf *s, const void *buf, size_t len) 449b0def2b5SDag-Erling Smørgrav { 450d751f0a9SDag-Erling Smørgrav 4512f1c4e0eSConrad Meyer sbuf_put_bytes(s, buf, len); 4524d369413SMatthew D Fleming if (s->s_error != 0) 453b0def2b5SDag-Erling Smørgrav return (-1); 454b0def2b5SDag-Erling Smørgrav return (0); 455b0def2b5SDag-Erling Smørgrav } 456b0def2b5SDag-Erling Smørgrav 457b0def2b5SDag-Erling Smørgrav #ifdef _KERNEL 458b0def2b5SDag-Erling Smørgrav /* 459b0def2b5SDag-Erling Smørgrav * Copy a byte string from userland into an sbuf. 460b0def2b5SDag-Erling Smørgrav */ 461b0def2b5SDag-Erling Smørgrav int 462b0def2b5SDag-Erling Smørgrav sbuf_bcopyin(struct sbuf *s, const void *uaddr, size_t len) 463b0def2b5SDag-Erling Smørgrav { 464546d7890SDag-Erling Smørgrav 465b0def2b5SDag-Erling Smørgrav assert_sbuf_integrity(s); 466b0def2b5SDag-Erling Smørgrav assert_sbuf_state(s, 0); 4674351ba27SMatthew D Fleming KASSERT(s->s_drain_func == NULL, 4684351ba27SMatthew D Fleming ("Nonsensical copyin to sbuf %p with a drain", s)); 469b0def2b5SDag-Erling Smørgrav 4704d369413SMatthew D Fleming if (s->s_error != 0) 471b0def2b5SDag-Erling Smørgrav return (-1); 472b0def2b5SDag-Erling Smørgrav if (len == 0) 473b0def2b5SDag-Erling Smørgrav return (0); 4747195eb40SKelly Yancey if (len > SBUF_FREESPACE(s)) { 4757195eb40SKelly Yancey sbuf_extend(s, len - SBUF_FREESPACE(s)); 476c05dbe7aSMatthew D Fleming if (SBUF_FREESPACE(s) < len) 477c05dbe7aSMatthew D Fleming len = SBUF_FREESPACE(s); 4787195eb40SKelly Yancey } 479e3b37322SDag-Erling Smørgrav if (copyin(uaddr, s->s_buf + s->s_len, len) != 0) 480e3b37322SDag-Erling Smørgrav return (-1); 481fe463496SDag-Erling Smørgrav s->s_len += len; 482b0def2b5SDag-Erling Smørgrav 483b0def2b5SDag-Erling Smørgrav return (0); 484b0def2b5SDag-Erling Smørgrav } 485b0def2b5SDag-Erling Smørgrav #endif 486b0def2b5SDag-Erling Smørgrav 487b0def2b5SDag-Erling Smørgrav /* 488b0def2b5SDag-Erling Smørgrav * Copy a byte string into an sbuf. 489b0def2b5SDag-Erling Smørgrav */ 490b0def2b5SDag-Erling Smørgrav int 491520df276SDag-Erling Smørgrav sbuf_bcpy(struct sbuf *s, const void *buf, size_t len) 492b0def2b5SDag-Erling Smørgrav { 493546d7890SDag-Erling Smørgrav 494b0def2b5SDag-Erling Smørgrav assert_sbuf_integrity(s); 495b0def2b5SDag-Erling Smørgrav assert_sbuf_state(s, 0); 496b0def2b5SDag-Erling Smørgrav 497b0def2b5SDag-Erling Smørgrav sbuf_clear(s); 498520df276SDag-Erling Smørgrav return (sbuf_bcat(s, buf, len)); 499b0def2b5SDag-Erling Smørgrav } 500b0def2b5SDag-Erling Smørgrav 501b0def2b5SDag-Erling Smørgrav /* 50260ec4130SDag-Erling Smørgrav * Append a string to an sbuf. 50360ec4130SDag-Erling Smørgrav */ 50460ec4130SDag-Erling Smørgrav int 5053393f8daSKenneth D. Merry sbuf_cat(struct sbuf *s, const char *str) 50660ec4130SDag-Erling Smørgrav { 5072f1c4e0eSConrad Meyer size_t n; 508546d7890SDag-Erling Smørgrav 5092f1c4e0eSConrad Meyer n = strlen(str); 5102f1c4e0eSConrad Meyer sbuf_put_bytes(s, str, n); 5114d369413SMatthew D Fleming if (s->s_error != 0) 51260ec4130SDag-Erling Smørgrav return (-1); 51360ec4130SDag-Erling Smørgrav return (0); 51460ec4130SDag-Erling Smørgrav } 51560ec4130SDag-Erling Smørgrav 516b0def2b5SDag-Erling Smørgrav #ifdef _KERNEL 517b0def2b5SDag-Erling Smørgrav /* 5187195eb40SKelly Yancey * Append a string from userland to an sbuf. 519b0def2b5SDag-Erling Smørgrav */ 520b0def2b5SDag-Erling Smørgrav int 521b0def2b5SDag-Erling Smørgrav sbuf_copyin(struct sbuf *s, const void *uaddr, size_t len) 522b0def2b5SDag-Erling Smørgrav { 523b0def2b5SDag-Erling Smørgrav size_t done; 524b0def2b5SDag-Erling Smørgrav 525b0def2b5SDag-Erling Smørgrav assert_sbuf_integrity(s); 526b0def2b5SDag-Erling Smørgrav assert_sbuf_state(s, 0); 5274351ba27SMatthew D Fleming KASSERT(s->s_drain_func == NULL, 5284351ba27SMatthew D Fleming ("Nonsensical copyin to sbuf %p with a drain", s)); 529b0def2b5SDag-Erling Smørgrav 5304d369413SMatthew D Fleming if (s->s_error != 0) 531b0def2b5SDag-Erling Smørgrav return (-1); 532b0def2b5SDag-Erling Smørgrav 5337195eb40SKelly Yancey if (len == 0) 5347195eb40SKelly Yancey len = SBUF_FREESPACE(s); /* XXX return 0? */ 5357195eb40SKelly Yancey if (len > SBUF_FREESPACE(s)) { 5367195eb40SKelly Yancey sbuf_extend(s, len); 537c05dbe7aSMatthew D Fleming if (SBUF_FREESPACE(s) < len) 538c05dbe7aSMatthew D Fleming len = SBUF_FREESPACE(s); 5397195eb40SKelly Yancey } 540b0def2b5SDag-Erling Smørgrav switch (copyinstr(uaddr, s->s_buf + s->s_len, len + 1, &done)) { 541b0def2b5SDag-Erling Smørgrav case ENAMETOOLONG: 5424d369413SMatthew D Fleming s->s_error = ENOMEM; 543b0def2b5SDag-Erling Smørgrav /* fall through */ 544b0def2b5SDag-Erling Smørgrav case 0: 545b0def2b5SDag-Erling Smørgrav s->s_len += done - 1; 546ddb9b612SMikolaj Golub if (SBUF_ISSECTION(s)) 547ddb9b612SMikolaj Golub s->s_sect_len += done - 1; 548b0def2b5SDag-Erling Smørgrav break; 549b0def2b5SDag-Erling Smørgrav default: 550b0def2b5SDag-Erling Smørgrav return (-1); /* XXX */ 551b0def2b5SDag-Erling Smørgrav } 552b0def2b5SDag-Erling Smørgrav 55349091c48SPoul-Henning Kamp return (done); 554b0def2b5SDag-Erling Smørgrav } 555b0def2b5SDag-Erling Smørgrav #endif 556b0def2b5SDag-Erling Smørgrav 55760ec4130SDag-Erling Smørgrav /* 55860ec4130SDag-Erling Smørgrav * Copy a string into an sbuf. 55960ec4130SDag-Erling Smørgrav */ 56060ec4130SDag-Erling Smørgrav int 5613393f8daSKenneth D. Merry sbuf_cpy(struct sbuf *s, const char *str) 56260ec4130SDag-Erling Smørgrav { 563546d7890SDag-Erling Smørgrav 56460ec4130SDag-Erling Smørgrav assert_sbuf_integrity(s); 56560ec4130SDag-Erling Smørgrav assert_sbuf_state(s, 0); 56660ec4130SDag-Erling Smørgrav 5674dc14139SDag-Erling Smørgrav sbuf_clear(s); 56860ec4130SDag-Erling Smørgrav return (sbuf_cat(s, str)); 56960ec4130SDag-Erling Smørgrav } 57060ec4130SDag-Erling Smørgrav 57160ec4130SDag-Erling Smørgrav /* 5727195eb40SKelly Yancey * Format the given argument list and append the resulting string to an sbuf. 57360ec4130SDag-Erling Smørgrav */ 57401f6f5fcSMatthew D Fleming #ifdef _KERNEL 575eb05ee7aSPoul-Henning Kamp 576eb05ee7aSPoul-Henning Kamp /* 577eb05ee7aSPoul-Henning Kamp * Append a non-NUL character to an sbuf. This prototype signature is 578eb05ee7aSPoul-Henning Kamp * suitable for use with kvprintf(9). 579eb05ee7aSPoul-Henning Kamp */ 580eb05ee7aSPoul-Henning Kamp static void 581eb05ee7aSPoul-Henning Kamp sbuf_putc_func(int c, void *arg) 582eb05ee7aSPoul-Henning Kamp { 583eb05ee7aSPoul-Henning Kamp 584eb05ee7aSPoul-Henning Kamp if (c != '\0') 585eb05ee7aSPoul-Henning Kamp sbuf_put_byte(arg, c); 586eb05ee7aSPoul-Henning Kamp } 587eb05ee7aSPoul-Henning Kamp 58801f6f5fcSMatthew D Fleming int 58901f6f5fcSMatthew D Fleming sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap) 59001f6f5fcSMatthew D Fleming { 59101f6f5fcSMatthew D Fleming 59201f6f5fcSMatthew D Fleming assert_sbuf_integrity(s); 59301f6f5fcSMatthew D Fleming assert_sbuf_state(s, 0); 59401f6f5fcSMatthew D Fleming 59501f6f5fcSMatthew D Fleming KASSERT(fmt != NULL, 59601f6f5fcSMatthew D Fleming ("%s called with a NULL format string", __func__)); 59701f6f5fcSMatthew D Fleming 59801f6f5fcSMatthew D Fleming (void)kvprintf(fmt, sbuf_putc_func, s, 10, ap); 5994d369413SMatthew D Fleming if (s->s_error != 0) 60001f6f5fcSMatthew D Fleming return (-1); 60101f6f5fcSMatthew D Fleming return (0); 60201f6f5fcSMatthew D Fleming } 60301f6f5fcSMatthew D Fleming #else /* !_KERNEL */ 60460ec4130SDag-Erling Smørgrav int 6057195eb40SKelly Yancey sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap) 60660ec4130SDag-Erling Smørgrav { 607a9a0bbadSPeter Wemm va_list ap_copy; 608adecd05bSPietro Cerutti int error, len; 60960ec4130SDag-Erling Smørgrav 61060ec4130SDag-Erling Smørgrav assert_sbuf_integrity(s); 61160ec4130SDag-Erling Smørgrav assert_sbuf_state(s, 0); 61260ec4130SDag-Erling Smørgrav 61360ec4130SDag-Erling Smørgrav KASSERT(fmt != NULL, 614a48740b6SDavid E. O'Brien ("%s called with a NULL format string", __func__)); 61560ec4130SDag-Erling Smørgrav 6164d369413SMatthew D Fleming if (s->s_error != 0) 61760ec4130SDag-Erling Smørgrav return (-1); 61860ec4130SDag-Erling Smørgrav 61901f6f5fcSMatthew D Fleming /* 62001f6f5fcSMatthew D Fleming * For the moment, there is no way to get vsnprintf(3) to hand 62101f6f5fcSMatthew D Fleming * back a character at a time, to push everything into 62201f6f5fcSMatthew D Fleming * sbuf_putc_func() as was done for the kernel. 6234351ba27SMatthew D Fleming * 6244351ba27SMatthew D Fleming * In userspace, while drains are useful, there's generally 6254351ba27SMatthew D Fleming * not a problem attempting to malloc(3) on out of space. So 6264351ba27SMatthew D Fleming * expand a userland sbuf if there is not enough room for the 6274351ba27SMatthew D Fleming * data produced by sbuf_[v]printf(3). 62801f6f5fcSMatthew D Fleming */ 62901f6f5fcSMatthew D Fleming 6304351ba27SMatthew D Fleming error = 0; 6317195eb40SKelly Yancey do { 632a9a0bbadSPeter Wemm va_copy(ap_copy, ap); 6337195eb40SKelly Yancey len = vsnprintf(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1, 634a9a0bbadSPeter Wemm fmt, ap_copy); 635d58b610fSPoul-Henning Kamp if (len < 0) { 636d58b610fSPoul-Henning Kamp s->s_error = errno; 637d58b610fSPoul-Henning Kamp return (-1); 638d58b610fSPoul-Henning Kamp } 639a9a0bbadSPeter Wemm va_end(ap_copy); 6404351ba27SMatthew D Fleming 6414351ba27SMatthew D Fleming if (SBUF_FREESPACE(s) >= len) 6424351ba27SMatthew D Fleming break; 6434351ba27SMatthew D Fleming /* Cannot print with the current available space. */ 6444351ba27SMatthew D Fleming if (s->s_drain_func != NULL && s->s_len > 0) 6459a61faf6SLawrence Stewart error = sbuf_drain(s); /* sbuf_drain() sets s_error. */ 6469a61faf6SLawrence Stewart else if (sbuf_extend(s, len - SBUF_FREESPACE(s)) != 0) 6479a61faf6SLawrence Stewart s->s_error = error = ENOMEM; 6484351ba27SMatthew D Fleming } while (error == 0); 64960ec4130SDag-Erling Smørgrav 6503393f8daSKenneth D. Merry /* 6513393f8daSKenneth D. Merry * s->s_len is the length of the string, without the terminating nul. 6523393f8daSKenneth D. Merry * When updating s->s_len, we must subtract 1 from the length that 6533393f8daSKenneth D. Merry * we passed into vsnprintf() because that length includes the 6543393f8daSKenneth D. Merry * terminating nul. 6553393f8daSKenneth D. Merry * 6563393f8daSKenneth D. Merry * vsnprintf() returns the amount that would have been copied, 657c05dbe7aSMatthew D Fleming * given sufficient space, so don't over-increment s_len. 6583393f8daSKenneth D. Merry */ 659c05dbe7aSMatthew D Fleming if (SBUF_FREESPACE(s) < len) 660c05dbe7aSMatthew D Fleming len = SBUF_FREESPACE(s); 661c05dbe7aSMatthew D Fleming s->s_len += len; 662ddb9b612SMikolaj Golub if (SBUF_ISSECTION(s)) 663ddb9b612SMikolaj Golub s->s_sect_len += len; 6643393f8daSKenneth D. Merry 66560ec4130SDag-Erling Smørgrav KASSERT(s->s_len < s->s_size, 66660ec4130SDag-Erling Smørgrav ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size)); 66760ec4130SDag-Erling Smørgrav 6684d369413SMatthew D Fleming if (s->s_error != 0) 66960ec4130SDag-Erling Smørgrav return (-1); 67060ec4130SDag-Erling Smørgrav return (0); 67160ec4130SDag-Erling Smørgrav } 67201f6f5fcSMatthew D Fleming #endif /* _KERNEL */ 67360ec4130SDag-Erling Smørgrav 67460ec4130SDag-Erling Smørgrav /* 6757195eb40SKelly Yancey * Format the given arguments and append the resulting string to an sbuf. 6767195eb40SKelly Yancey */ 6777195eb40SKelly Yancey int 6787195eb40SKelly Yancey sbuf_printf(struct sbuf *s, const char *fmt, ...) 6797195eb40SKelly Yancey { 6807195eb40SKelly Yancey va_list ap; 6817195eb40SKelly Yancey int result; 6827195eb40SKelly Yancey 6837195eb40SKelly Yancey va_start(ap, fmt); 6847195eb40SKelly Yancey result = sbuf_vprintf(s, fmt, ap); 6857195eb40SKelly Yancey va_end(ap); 6867195eb40SKelly Yancey return (result); 6877195eb40SKelly Yancey } 6887195eb40SKelly Yancey 6897195eb40SKelly Yancey /* 69060ec4130SDag-Erling Smørgrav * Append a character to an sbuf. 69160ec4130SDag-Erling Smørgrav */ 69260ec4130SDag-Erling Smørgrav int 69360ec4130SDag-Erling Smørgrav sbuf_putc(struct sbuf *s, int c) 69460ec4130SDag-Erling Smørgrav { 695546d7890SDag-Erling Smørgrav 696eb05ee7aSPoul-Henning Kamp sbuf_put_byte(s, c); 6974d369413SMatthew D Fleming if (s->s_error != 0) 69860ec4130SDag-Erling Smørgrav return (-1); 69960ec4130SDag-Erling Smørgrav return (0); 70060ec4130SDag-Erling Smørgrav } 70160ec4130SDag-Erling Smørgrav 70260ec4130SDag-Erling Smørgrav /* 7037195eb40SKelly Yancey * Trim whitespace characters from end of an sbuf. 7045b6db477SDag-Erling Smørgrav */ 7055b6db477SDag-Erling Smørgrav int 7065b6db477SDag-Erling Smørgrav sbuf_trim(struct sbuf *s) 7075b6db477SDag-Erling Smørgrav { 708546d7890SDag-Erling Smørgrav 7095b6db477SDag-Erling Smørgrav assert_sbuf_integrity(s); 7105b6db477SDag-Erling Smørgrav assert_sbuf_state(s, 0); 7114351ba27SMatthew D Fleming KASSERT(s->s_drain_func == NULL, 7124351ba27SMatthew D Fleming ("%s makes no sense on sbuf %p with drain", __func__, s)); 7135b6db477SDag-Erling Smørgrav 7144d369413SMatthew D Fleming if (s->s_error != 0) 7155b6db477SDag-Erling Smørgrav return (-1); 7165b6db477SDag-Erling Smørgrav 717ddb9b612SMikolaj Golub while (s->s_len > 0 && isspace(s->s_buf[s->s_len-1])) { 7185b6db477SDag-Erling Smørgrav --s->s_len; 719ddb9b612SMikolaj Golub if (SBUF_ISSECTION(s)) 720ddb9b612SMikolaj Golub s->s_sect_len--; 721ddb9b612SMikolaj Golub } 7225b6db477SDag-Erling Smørgrav 7235b6db477SDag-Erling Smørgrav return (0); 7245b6db477SDag-Erling Smørgrav } 7255b6db477SDag-Erling Smørgrav 7265b6db477SDag-Erling Smørgrav /* 7274d369413SMatthew D Fleming * Check if an sbuf has an error. 72860ec4130SDag-Erling Smørgrav */ 72960ec4130SDag-Erling Smørgrav int 73071c2bc5cSPoul-Henning Kamp sbuf_error(const struct sbuf *s) 7314dc14139SDag-Erling Smørgrav { 732546d7890SDag-Erling Smørgrav 7334d369413SMatthew D Fleming return (s->s_error); 7344dc14139SDag-Erling Smørgrav } 7354dc14139SDag-Erling Smørgrav 7364dc14139SDag-Erling Smørgrav /* 7374dc14139SDag-Erling Smørgrav * Finish off an sbuf. 7384dc14139SDag-Erling Smørgrav */ 7394351ba27SMatthew D Fleming int 74060ec4130SDag-Erling Smørgrav sbuf_finish(struct sbuf *s) 74160ec4130SDag-Erling Smørgrav { 742546d7890SDag-Erling Smørgrav 74360ec4130SDag-Erling Smørgrav assert_sbuf_integrity(s); 74460ec4130SDag-Erling Smørgrav assert_sbuf_state(s, 0); 74560ec4130SDag-Erling Smørgrav 746f4d28142SIan Lepore s->s_buf[s->s_len] = '\0'; 7478d5628fdSIan Lepore if (SBUF_NULINCLUDED(s)) 748f4d28142SIan Lepore s->s_len++; 7494d369413SMatthew D Fleming if (s->s_drain_func != NULL) { 750eb05ee7aSPoul-Henning Kamp while (s->s_len > 0 && s->s_error == 0) 751eb05ee7aSPoul-Henning Kamp s->s_error = sbuf_drain(s); 7524d369413SMatthew D Fleming } 75360ec4130SDag-Erling Smørgrav SBUF_SETFLAG(s, SBUF_FINISHED); 7544351ba27SMatthew D Fleming #ifdef _KERNEL 755eb05ee7aSPoul-Henning Kamp return (s->s_error); 7564351ba27SMatthew D Fleming #else 757c532f8c4SJaakko Heinonen if (s->s_error != 0) { 758eb05ee7aSPoul-Henning Kamp errno = s->s_error; 7594351ba27SMatthew D Fleming return (-1); 760c532f8c4SJaakko Heinonen } 761eb05ee7aSPoul-Henning Kamp return (0); 7624351ba27SMatthew D Fleming #endif 76360ec4130SDag-Erling Smørgrav } 76460ec4130SDag-Erling Smørgrav 76560ec4130SDag-Erling Smørgrav /* 76660ec4130SDag-Erling Smørgrav * Return a pointer to the sbuf data. 76760ec4130SDag-Erling Smørgrav */ 76860ec4130SDag-Erling Smørgrav char * 76960ec4130SDag-Erling Smørgrav sbuf_data(struct sbuf *s) 77060ec4130SDag-Erling Smørgrav { 771546d7890SDag-Erling Smørgrav 77260ec4130SDag-Erling Smørgrav assert_sbuf_integrity(s); 77360ec4130SDag-Erling Smørgrav assert_sbuf_state(s, SBUF_FINISHED); 7744351ba27SMatthew D Fleming KASSERT(s->s_drain_func == NULL, 7754351ba27SMatthew D Fleming ("%s makes no sense on sbuf %p with drain", __func__, s)); 77660ec4130SDag-Erling Smørgrav 777546d7890SDag-Erling Smørgrav return (s->s_buf); 77860ec4130SDag-Erling Smørgrav } 77960ec4130SDag-Erling Smørgrav 78060ec4130SDag-Erling Smørgrav /* 78160ec4130SDag-Erling Smørgrav * Return the length of the sbuf data. 78260ec4130SDag-Erling Smørgrav */ 78371c2bc5cSPoul-Henning Kamp ssize_t 78460ec4130SDag-Erling Smørgrav sbuf_len(struct sbuf *s) 78560ec4130SDag-Erling Smørgrav { 786546d7890SDag-Erling Smørgrav 78760ec4130SDag-Erling Smørgrav assert_sbuf_integrity(s); 7889fa2ef3dSDag-Erling Smørgrav /* don't care if it's finished or not */ 7894351ba27SMatthew D Fleming KASSERT(s->s_drain_func == NULL, 7904351ba27SMatthew D Fleming ("%s makes no sense on sbuf %p with drain", __func__, s)); 79160ec4130SDag-Erling Smørgrav 7924d369413SMatthew D Fleming if (s->s_error != 0) 7934dc14139SDag-Erling Smørgrav return (-1); 794f4d28142SIan Lepore 795f4d28142SIan Lepore /* If finished, nulterm is already in len, else add one. */ 7968d5628fdSIan Lepore if (SBUF_NULINCLUDED(s) && !SBUF_ISFINISHED(s)) 797f4d28142SIan Lepore return (s->s_len + 1); 798546d7890SDag-Erling Smørgrav return (s->s_len); 79960ec4130SDag-Erling Smørgrav } 80060ec4130SDag-Erling Smørgrav 80160ec4130SDag-Erling Smørgrav /* 80260ec4130SDag-Erling Smørgrav * Clear an sbuf, free its buffer if necessary. 80360ec4130SDag-Erling Smørgrav */ 80460ec4130SDag-Erling Smørgrav void 80560ec4130SDag-Erling Smørgrav sbuf_delete(struct sbuf *s) 80660ec4130SDag-Erling Smørgrav { 807a57094a0SMatthew Dillon int isdyn; 808a57094a0SMatthew Dillon 80960ec4130SDag-Erling Smørgrav assert_sbuf_integrity(s); 81060ec4130SDag-Erling Smørgrav /* don't care if it's finished or not */ 81160ec4130SDag-Erling Smørgrav 81260ec4130SDag-Erling Smørgrav if (SBUF_ISDYNAMIC(s)) 8133393f8daSKenneth D. Merry SBFREE(s->s_buf); 814a57094a0SMatthew Dillon isdyn = SBUF_ISDYNSTRUCT(s); 815384bf94cSPoul-Henning Kamp memset(s, 0, sizeof(*s)); 816a57094a0SMatthew Dillon if (isdyn) 817d6479358SDag-Erling Smørgrav SBFREE(s); 81860ec4130SDag-Erling Smørgrav } 819c5f9218bSPoul-Henning Kamp 820c5f9218bSPoul-Henning Kamp /* 821c5f9218bSPoul-Henning Kamp * Check if an sbuf has been finished. 822c5f9218bSPoul-Henning Kamp */ 823c5f9218bSPoul-Henning Kamp int 82471c2bc5cSPoul-Henning Kamp sbuf_done(const struct sbuf *s) 825c5f9218bSPoul-Henning Kamp { 826c5f9218bSPoul-Henning Kamp 827c5f9218bSPoul-Henning Kamp return (SBUF_ISFINISHED(s)); 828c5f9218bSPoul-Henning Kamp } 829ddb9b612SMikolaj Golub 830ddb9b612SMikolaj Golub /* 831ddb9b612SMikolaj Golub * Start a section. 832ddb9b612SMikolaj Golub */ 833ddb9b612SMikolaj Golub void 834ddb9b612SMikolaj Golub sbuf_start_section(struct sbuf *s, ssize_t *old_lenp) 835ddb9b612SMikolaj Golub { 836ddb9b612SMikolaj Golub 837ddb9b612SMikolaj Golub assert_sbuf_integrity(s); 838ddb9b612SMikolaj Golub assert_sbuf_state(s, 0); 839ddb9b612SMikolaj Golub 840ddb9b612SMikolaj Golub if (!SBUF_ISSECTION(s)) { 841ddb9b612SMikolaj Golub KASSERT(s->s_sect_len == 0, 842ddb9b612SMikolaj Golub ("s_sect_len != 0 when starting a section")); 843ddb9b612SMikolaj Golub if (old_lenp != NULL) 844ddb9b612SMikolaj Golub *old_lenp = -1; 845a8ec96afSLawrence Stewart s->s_rec_off = s->s_len; 846ddb9b612SMikolaj Golub SBUF_SETFLAG(s, SBUF_INSECTION); 847ddb9b612SMikolaj Golub } else { 848ddb9b612SMikolaj Golub KASSERT(old_lenp != NULL, 849ddb9b612SMikolaj Golub ("s_sect_len should be saved when starting a subsection")); 850ddb9b612SMikolaj Golub *old_lenp = s->s_sect_len; 851ddb9b612SMikolaj Golub s->s_sect_len = 0; 852ddb9b612SMikolaj Golub } 853ddb9b612SMikolaj Golub } 854ddb9b612SMikolaj Golub 855ddb9b612SMikolaj Golub /* 856ddb9b612SMikolaj Golub * End the section padding to the specified length with the specified 857ddb9b612SMikolaj Golub * character. 858ddb9b612SMikolaj Golub */ 859ddb9b612SMikolaj Golub ssize_t 860ddb9b612SMikolaj Golub sbuf_end_section(struct sbuf *s, ssize_t old_len, size_t pad, int c) 861ddb9b612SMikolaj Golub { 862ddb9b612SMikolaj Golub ssize_t len; 863ddb9b612SMikolaj Golub 864ddb9b612SMikolaj Golub assert_sbuf_integrity(s); 865ddb9b612SMikolaj Golub assert_sbuf_state(s, 0); 866ddb9b612SMikolaj Golub KASSERT(SBUF_ISSECTION(s), 867ddb9b612SMikolaj Golub ("attempt to end a section when not in a section")); 868ddb9b612SMikolaj Golub 869ddb9b612SMikolaj Golub if (pad > 1) { 870ddb9b612SMikolaj Golub len = roundup(s->s_sect_len, pad) - s->s_sect_len; 871ddb9b612SMikolaj Golub for (; s->s_error == 0 && len > 0; len--) 872ddb9b612SMikolaj Golub sbuf_put_byte(s, c); 873ddb9b612SMikolaj Golub } 874ddb9b612SMikolaj Golub len = s->s_sect_len; 875ddb9b612SMikolaj Golub if (old_len == -1) { 876a8ec96afSLawrence Stewart s->s_rec_off = s->s_sect_len = 0; 877ddb9b612SMikolaj Golub SBUF_CLEARFLAG(s, SBUF_INSECTION); 878ddb9b612SMikolaj Golub } else { 879ddb9b612SMikolaj Golub s->s_sect_len += old_len; 880ddb9b612SMikolaj Golub } 881ddb9b612SMikolaj Golub if (s->s_error != 0) 882ddb9b612SMikolaj Golub return (-1); 883ddb9b612SMikolaj Golub return (len); 884ddb9b612SMikolaj Golub } 885