160ec4130SDag-Erling Smørgrav /*- 2546d7890SDag-Erling Smørgrav * Copyright (c) 2000-2008 Poul-Henning Kamp 3546d7890SDag-Erling Smørgrav * Copyright (c) 2000-2008 Dag-Erling Coïdan Smørgrav 460ec4130SDag-Erling Smørgrav * All rights reserved. 560ec4130SDag-Erling Smørgrav * 660ec4130SDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 760ec4130SDag-Erling Smørgrav * modification, are permitted provided that the following conditions 860ec4130SDag-Erling Smørgrav * are met: 960ec4130SDag-Erling Smørgrav * 1. Redistributions of source code must retain the above copyright 1060ec4130SDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer 1160ec4130SDag-Erling Smørgrav * in this position and unchanged. 1260ec4130SDag-Erling Smørgrav * 2. Redistributions in binary form must reproduce the above copyright 1360ec4130SDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer in the 1460ec4130SDag-Erling Smørgrav * documentation and/or other materials provided with the distribution. 1560ec4130SDag-Erling Smørgrav * 16546d7890SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17546d7890SDag-Erling Smørgrav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18546d7890SDag-Erling Smørgrav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19546d7890SDag-Erling Smørgrav * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20546d7890SDag-Erling Smørgrav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21546d7890SDag-Erling Smørgrav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22546d7890SDag-Erling Smørgrav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23546d7890SDag-Erling Smørgrav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24546d7890SDag-Erling Smørgrav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25546d7890SDag-Erling Smørgrav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26546d7890SDag-Erling Smørgrav * SUCH DAMAGE. 2760ec4130SDag-Erling Smørgrav */ 2860ec4130SDag-Erling Smørgrav 29677b542eSDavid E. O'Brien #include <sys/cdefs.h> 30677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 31677b542eSDavid E. O'Brien 3260ec4130SDag-Erling Smørgrav #include <sys/param.h> 333393f8daSKenneth D. Merry 343393f8daSKenneth D. Merry #ifdef _KERNEL 355b6db477SDag-Erling Smørgrav #include <sys/ctype.h> 364351ba27SMatthew D Fleming #include <sys/errno.h> 3760ec4130SDag-Erling Smørgrav #include <sys/kernel.h> 38*2f1c4e0eSConrad Meyer #include <sys/limits.h> 3960ec4130SDag-Erling Smørgrav #include <sys/malloc.h> 4060ec4130SDag-Erling Smørgrav #include <sys/systm.h> 415b6db477SDag-Erling Smørgrav #include <sys/uio.h> 4260ec4130SDag-Erling Smørgrav #include <machine/stdarg.h> 433393f8daSKenneth D. Merry #else /* _KERNEL */ 445b6db477SDag-Erling Smørgrav #include <ctype.h> 454351ba27SMatthew D Fleming #include <errno.h> 46*2f1c4e0eSConrad Meyer #include <limits.h> 473393f8daSKenneth D. Merry #include <stdarg.h> 487195eb40SKelly Yancey #include <stdio.h> 499fa416caSJonathan Lemon #include <stdlib.h> 507195eb40SKelly Yancey #include <string.h> 513393f8daSKenneth D. Merry #endif /* _KERNEL */ 5260ec4130SDag-Erling Smørgrav 535b6db477SDag-Erling Smørgrav #include <sys/sbuf.h> 545b6db477SDag-Erling Smørgrav 553393f8daSKenneth D. Merry #ifdef _KERNEL 56c711aea6SPoul-Henning Kamp static MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers"); 570f7bc112SDag-Erling Smørgrav #define SBMALLOC(size) malloc(size, M_SBUF, M_WAITOK|M_ZERO) 583393f8daSKenneth D. Merry #define SBFREE(buf) free(buf, M_SBUF) 593393f8daSKenneth D. Merry #else /* _KERNEL */ 603393f8daSKenneth D. Merry #define KASSERT(e, m) 610f7bc112SDag-Erling Smørgrav #define SBMALLOC(size) calloc(1, size) 623393f8daSKenneth D. Merry #define SBFREE(buf) free(buf) 633393f8daSKenneth D. Merry #endif /* _KERNEL */ 6460ec4130SDag-Erling Smørgrav 654dc14139SDag-Erling Smørgrav /* 664dc14139SDag-Erling Smørgrav * Predicates 674dc14139SDag-Erling Smørgrav */ 684dc14139SDag-Erling Smørgrav #define SBUF_ISDYNAMIC(s) ((s)->s_flags & SBUF_DYNAMIC) 69d6479358SDag-Erling Smørgrav #define SBUF_ISDYNSTRUCT(s) ((s)->s_flags & SBUF_DYNSTRUCT) 704dc14139SDag-Erling Smørgrav #define SBUF_ISFINISHED(s) ((s)->s_flags & SBUF_FINISHED) 714dc14139SDag-Erling Smørgrav #define SBUF_HASROOM(s) ((s)->s_len < (s)->s_size - 1) 72eb05ee7aSPoul-Henning Kamp #define SBUF_FREESPACE(s) ((s)->s_size - ((s)->s_len + 1)) 737195eb40SKelly Yancey #define SBUF_CANEXTEND(s) ((s)->s_flags & SBUF_AUTOEXTEND) 74ddb9b612SMikolaj Golub #define SBUF_ISSECTION(s) ((s)->s_flags & SBUF_INSECTION) 758d5628fdSIan Lepore #define SBUF_NULINCLUDED(s) ((s)->s_flags & SBUF_INCLUDENUL) 764dc14139SDag-Erling Smørgrav 774dc14139SDag-Erling Smørgrav /* 784dc14139SDag-Erling Smørgrav * Set / clear flags 794dc14139SDag-Erling Smørgrav */ 804dc14139SDag-Erling Smørgrav #define SBUF_SETFLAG(s, f) do { (s)->s_flags |= (f); } while (0) 814dc14139SDag-Erling Smørgrav #define SBUF_CLEARFLAG(s, f) do { (s)->s_flags &= ~(f); } while (0) 824dc14139SDag-Erling Smørgrav 83612d9391SIan Lepore #define SBUF_MINSIZE 2 /* Min is 1 byte + nulterm. */ 847195eb40SKelly Yancey #define SBUF_MINEXTENDSIZE 16 /* Should be power of 2. */ 85eb05ee7aSPoul-Henning Kamp 86eb05ee7aSPoul-Henning Kamp #ifdef PAGE_SIZE 877195eb40SKelly Yancey #define SBUF_MAXEXTENDSIZE PAGE_SIZE 887195eb40SKelly Yancey #define SBUF_MAXEXTENDINCR PAGE_SIZE 89eb05ee7aSPoul-Henning Kamp #else 90eb05ee7aSPoul-Henning Kamp #define SBUF_MAXEXTENDSIZE 4096 91eb05ee7aSPoul-Henning Kamp #define SBUF_MAXEXTENDINCR 4096 92eb05ee7aSPoul-Henning Kamp #endif 937195eb40SKelly Yancey 944dc14139SDag-Erling Smørgrav /* 954dc14139SDag-Erling Smørgrav * Debugging support 964dc14139SDag-Erling Smørgrav */ 973393f8daSKenneth D. Merry #if defined(_KERNEL) && defined(INVARIANTS) 98546d7890SDag-Erling Smørgrav 9960ec4130SDag-Erling Smørgrav static void 100a5e7c7daSPeter Wemm _assert_sbuf_integrity(const char *fun, struct sbuf *s) 10160ec4130SDag-Erling Smørgrav { 102546d7890SDag-Erling Smørgrav 10360ec4130SDag-Erling Smørgrav KASSERT(s != NULL, 104cab5b963SDag-Erling Smørgrav ("%s called with a NULL sbuf pointer", fun)); 10560ec4130SDag-Erling Smørgrav KASSERT(s->s_buf != NULL, 1067195eb40SKelly Yancey ("%s called with uninitialized or corrupt sbuf", fun)); 1078d5628fdSIan Lepore if (SBUF_ISFINISHED(s) && SBUF_NULINCLUDED(s)) { 1088d5628fdSIan Lepore KASSERT(s->s_len <= s->s_size, 1098d5628fdSIan Lepore ("wrote past end of sbuf (%jd >= %jd)", 1108d5628fdSIan Lepore (intmax_t)s->s_len, (intmax_t)s->s_size)); 1118d5628fdSIan Lepore } else { 11260ec4130SDag-Erling Smørgrav KASSERT(s->s_len < s->s_size, 11371c2bc5cSPoul-Henning Kamp ("wrote past end of sbuf (%jd >= %jd)", 11471c2bc5cSPoul-Henning Kamp (intmax_t)s->s_len, (intmax_t)s->s_size)); 11560ec4130SDag-Erling Smørgrav } 1168d5628fdSIan Lepore } 11760ec4130SDag-Erling Smørgrav 11860ec4130SDag-Erling Smørgrav static void 119a5e7c7daSPeter Wemm _assert_sbuf_state(const char *fun, struct sbuf *s, int state) 12060ec4130SDag-Erling Smørgrav { 121546d7890SDag-Erling Smørgrav 12260ec4130SDag-Erling Smørgrav KASSERT((s->s_flags & SBUF_FINISHED) == state, 123cab5b963SDag-Erling Smørgrav ("%s called with %sfinished or corrupt sbuf", fun, 12460ec4130SDag-Erling Smørgrav (state ? "un" : ""))); 12560ec4130SDag-Erling Smørgrav } 126546d7890SDag-Erling Smørgrav 127a48740b6SDavid E. O'Brien #define assert_sbuf_integrity(s) _assert_sbuf_integrity(__func__, (s)) 128a48740b6SDavid E. O'Brien #define assert_sbuf_state(s, i) _assert_sbuf_state(__func__, (s), (i)) 129546d7890SDag-Erling Smørgrav 1303393f8daSKenneth D. Merry #else /* _KERNEL && INVARIANTS */ 131546d7890SDag-Erling Smørgrav 13260ec4130SDag-Erling Smørgrav #define assert_sbuf_integrity(s) do { } while (0) 13360ec4130SDag-Erling Smørgrav #define assert_sbuf_state(s, i) do { } while (0) 134546d7890SDag-Erling Smørgrav 1353393f8daSKenneth D. Merry #endif /* _KERNEL && INVARIANTS */ 13660ec4130SDag-Erling Smørgrav 137181ff3d5SMatthew D Fleming #ifdef CTASSERT 138f4bafab8SMatthew D Fleming CTASSERT(powerof2(SBUF_MAXEXTENDSIZE)); 139f4bafab8SMatthew D Fleming CTASSERT(powerof2(SBUF_MAXEXTENDINCR)); 140969292fbSMatthew D Fleming #endif 141f4bafab8SMatthew D Fleming 1427195eb40SKelly Yancey static int 1437195eb40SKelly Yancey sbuf_extendsize(int size) 1447195eb40SKelly Yancey { 1457195eb40SKelly Yancey int newsize; 1467195eb40SKelly Yancey 147f4bafab8SMatthew D Fleming if (size < (int)SBUF_MAXEXTENDSIZE) { 1487195eb40SKelly Yancey newsize = SBUF_MINEXTENDSIZE; 149f4bafab8SMatthew D Fleming while (newsize < size) 1507195eb40SKelly Yancey newsize *= 2; 151f4bafab8SMatthew D Fleming } else { 152f4bafab8SMatthew D Fleming newsize = roundup2(size, SBUF_MAXEXTENDINCR); 1537195eb40SKelly Yancey } 154f5a5dc5dSMatthew D Fleming KASSERT(newsize >= size, ("%s: %d < %d\n", __func__, newsize, size)); 1557195eb40SKelly Yancey return (newsize); 1567195eb40SKelly Yancey } 1577195eb40SKelly Yancey 1587195eb40SKelly Yancey /* 1597195eb40SKelly Yancey * Extend an sbuf. 1607195eb40SKelly Yancey */ 1617195eb40SKelly Yancey static int 1627195eb40SKelly Yancey sbuf_extend(struct sbuf *s, int addlen) 1637195eb40SKelly Yancey { 1647195eb40SKelly Yancey char *newbuf; 165adecd05bSPietro Cerutti int newsize; 1667195eb40SKelly Yancey 1677195eb40SKelly Yancey if (!SBUF_CANEXTEND(s)) 1687195eb40SKelly Yancey return (-1); 1697195eb40SKelly Yancey newsize = sbuf_extendsize(s->s_size + addlen); 170546d7890SDag-Erling Smørgrav newbuf = SBMALLOC(newsize); 1717195eb40SKelly Yancey if (newbuf == NULL) 1727195eb40SKelly Yancey return (-1); 173384bf94cSPoul-Henning Kamp memcpy(newbuf, s->s_buf, s->s_size); 1747195eb40SKelly Yancey if (SBUF_ISDYNAMIC(s)) 1757195eb40SKelly Yancey SBFREE(s->s_buf); 1767195eb40SKelly Yancey else 1777195eb40SKelly Yancey SBUF_SETFLAG(s, SBUF_DYNAMIC); 1787195eb40SKelly Yancey s->s_buf = newbuf; 1797195eb40SKelly Yancey s->s_size = newsize; 1807195eb40SKelly Yancey return (0); 1817195eb40SKelly Yancey } 1827195eb40SKelly Yancey 18360ec4130SDag-Erling Smørgrav /* 184384bf94cSPoul-Henning Kamp * Initialize the internals of an sbuf. 185384bf94cSPoul-Henning Kamp * If buf is non-NULL, it points to a static or already-allocated string 186384bf94cSPoul-Henning Kamp * big enough to hold at least length characters. 187384bf94cSPoul-Henning Kamp */ 188384bf94cSPoul-Henning Kamp static struct sbuf * 189adecd05bSPietro Cerutti sbuf_newbuf(struct sbuf *s, char *buf, int length, int flags) 190384bf94cSPoul-Henning Kamp { 191384bf94cSPoul-Henning Kamp 192384bf94cSPoul-Henning Kamp memset(s, 0, sizeof(*s)); 193384bf94cSPoul-Henning Kamp s->s_flags = flags; 194384bf94cSPoul-Henning Kamp s->s_size = length; 195384bf94cSPoul-Henning Kamp s->s_buf = buf; 196384bf94cSPoul-Henning Kamp 197384bf94cSPoul-Henning Kamp if ((s->s_flags & SBUF_AUTOEXTEND) == 0) { 198612d9391SIan Lepore KASSERT(s->s_size >= SBUF_MINSIZE, 199612d9391SIan Lepore ("attempt to create an sbuf smaller than %d bytes", 200612d9391SIan Lepore SBUF_MINSIZE)); 201384bf94cSPoul-Henning Kamp } 202384bf94cSPoul-Henning Kamp 203384bf94cSPoul-Henning Kamp if (s->s_buf != NULL) 204384bf94cSPoul-Henning Kamp return (s); 205384bf94cSPoul-Henning Kamp 206384bf94cSPoul-Henning Kamp if ((flags & SBUF_AUTOEXTEND) != 0) 207384bf94cSPoul-Henning Kamp s->s_size = sbuf_extendsize(s->s_size); 208384bf94cSPoul-Henning Kamp 209384bf94cSPoul-Henning Kamp s->s_buf = SBMALLOC(s->s_size); 210384bf94cSPoul-Henning Kamp if (s->s_buf == NULL) 211384bf94cSPoul-Henning Kamp return (NULL); 212384bf94cSPoul-Henning Kamp SBUF_SETFLAG(s, SBUF_DYNAMIC); 213384bf94cSPoul-Henning Kamp return (s); 214384bf94cSPoul-Henning Kamp } 215384bf94cSPoul-Henning Kamp 216384bf94cSPoul-Henning Kamp /* 21760ec4130SDag-Erling Smørgrav * Initialize an sbuf. 21860ec4130SDag-Erling Smørgrav * If buf is non-NULL, it points to a static or already-allocated string 21960ec4130SDag-Erling Smørgrav * big enough to hold at least length characters. 22060ec4130SDag-Erling Smørgrav */ 221d6479358SDag-Erling Smørgrav struct sbuf * 2224dc14139SDag-Erling Smørgrav sbuf_new(struct sbuf *s, char *buf, int length, int flags) 22360ec4130SDag-Erling Smørgrav { 224546d7890SDag-Erling Smørgrav 2254dc14139SDag-Erling Smørgrav KASSERT(length >= 0, 2264dc14139SDag-Erling Smørgrav ("attempt to create an sbuf of negative length (%d)", length)); 2277195eb40SKelly Yancey KASSERT((flags & ~SBUF_USRFLAGMSK) == 0, 2287195eb40SKelly Yancey ("%s called with invalid flags", __func__)); 22960ec4130SDag-Erling Smørgrav 2307195eb40SKelly Yancey flags &= SBUF_USRFLAGMSK; 231384bf94cSPoul-Henning Kamp if (s != NULL) 232384bf94cSPoul-Henning Kamp return (sbuf_newbuf(s, buf, length, flags)); 233384bf94cSPoul-Henning Kamp 234546d7890SDag-Erling Smørgrav s = SBMALLOC(sizeof(*s)); 235d6479358SDag-Erling Smørgrav if (s == NULL) 236d6479358SDag-Erling Smørgrav return (NULL); 237384bf94cSPoul-Henning Kamp if (sbuf_newbuf(s, buf, length, flags) == NULL) { 238d6479358SDag-Erling Smørgrav SBFREE(s); 239d6479358SDag-Erling Smørgrav return (NULL); 240d6479358SDag-Erling Smørgrav } 241384bf94cSPoul-Henning Kamp SBUF_SETFLAG(s, SBUF_DYNSTRUCT); 242d6479358SDag-Erling Smørgrav return (s); 24360ec4130SDag-Erling Smørgrav } 24460ec4130SDag-Erling Smørgrav 2455b6db477SDag-Erling Smørgrav #ifdef _KERNEL 2465b6db477SDag-Erling Smørgrav /* 2475b6db477SDag-Erling Smørgrav * Create an sbuf with uio data 2485b6db477SDag-Erling Smørgrav */ 2495b6db477SDag-Erling Smørgrav struct sbuf * 2505b6db477SDag-Erling Smørgrav sbuf_uionew(struct sbuf *s, struct uio *uio, int *error) 2515b6db477SDag-Erling Smørgrav { 252546d7890SDag-Erling Smørgrav 2535b6db477SDag-Erling Smørgrav KASSERT(uio != NULL, 254a48740b6SDavid E. O'Brien ("%s called with NULL uio pointer", __func__)); 2555b6db477SDag-Erling Smørgrav KASSERT(error != NULL, 256a48740b6SDavid E. O'Brien ("%s called with NULL error pointer", __func__)); 2575b6db477SDag-Erling Smørgrav 2585b6db477SDag-Erling Smørgrav s = sbuf_new(s, NULL, uio->uio_resid + 1, 0); 2595b6db477SDag-Erling Smørgrav if (s == NULL) { 2605b6db477SDag-Erling Smørgrav *error = ENOMEM; 2615b6db477SDag-Erling Smørgrav return (NULL); 2625b6db477SDag-Erling Smørgrav } 2635b6db477SDag-Erling Smørgrav *error = uiomove(s->s_buf, uio->uio_resid, uio); 2645b6db477SDag-Erling Smørgrav if (*error != 0) { 2655b6db477SDag-Erling Smørgrav sbuf_delete(s); 2665b6db477SDag-Erling Smørgrav return (NULL); 2675b6db477SDag-Erling Smørgrav } 2685b6db477SDag-Erling Smørgrav s->s_len = s->s_size - 1; 269ddb9b612SMikolaj Golub if (SBUF_ISSECTION(s)) 270ddb9b612SMikolaj Golub s->s_sect_len = s->s_size - 1; 2715b6db477SDag-Erling Smørgrav *error = 0; 2725b6db477SDag-Erling Smørgrav return (s); 2735b6db477SDag-Erling Smørgrav } 2745b6db477SDag-Erling Smørgrav #endif 2755b6db477SDag-Erling Smørgrav 276f4d28142SIan Lepore int 277f4d28142SIan Lepore sbuf_get_flags(struct sbuf *s) 278f4d28142SIan Lepore { 279f4d28142SIan Lepore 280f4d28142SIan Lepore return (s->s_flags & SBUF_USRFLAGMSK); 281f4d28142SIan Lepore } 282f4d28142SIan Lepore 283f4d28142SIan Lepore void 284f4d28142SIan Lepore sbuf_clear_flags(struct sbuf *s, int flags) 285f4d28142SIan Lepore { 286f4d28142SIan Lepore 287f4d28142SIan Lepore s->s_flags &= ~(flags & SBUF_USRFLAGMSK); 288f4d28142SIan Lepore } 289f4d28142SIan Lepore 290f4d28142SIan Lepore void 291f4d28142SIan Lepore sbuf_set_flags(struct sbuf *s, int flags) 292f4d28142SIan Lepore { 293f4d28142SIan Lepore 294f4d28142SIan Lepore 295f4d28142SIan Lepore s->s_flags |= (flags & SBUF_USRFLAGMSK); 296f4d28142SIan Lepore } 297f4d28142SIan Lepore 29860ec4130SDag-Erling Smørgrav /* 2997195eb40SKelly Yancey * Clear an sbuf and reset its position. 3004dc14139SDag-Erling Smørgrav */ 3014dc14139SDag-Erling Smørgrav void 3024dc14139SDag-Erling Smørgrav sbuf_clear(struct sbuf *s) 3034dc14139SDag-Erling Smørgrav { 304546d7890SDag-Erling Smørgrav 3054dc14139SDag-Erling Smørgrav assert_sbuf_integrity(s); 3069fa2ef3dSDag-Erling Smørgrav /* don't care if it's finished or not */ 3074dc14139SDag-Erling Smørgrav 3084dc14139SDag-Erling Smørgrav SBUF_CLEARFLAG(s, SBUF_FINISHED); 3094351ba27SMatthew D Fleming s->s_error = 0; 3104dc14139SDag-Erling Smørgrav s->s_len = 0; 311ddb9b612SMikolaj Golub s->s_sect_len = 0; 3124dc14139SDag-Erling Smørgrav } 3134dc14139SDag-Erling Smørgrav 3144dc14139SDag-Erling Smørgrav /* 3157195eb40SKelly Yancey * Set the sbuf's end position to an arbitrary value. 3167195eb40SKelly Yancey * Effectively truncates the sbuf at the new position. 31760ec4130SDag-Erling Smørgrav */ 31860ec4130SDag-Erling Smørgrav int 319adecd05bSPietro Cerutti sbuf_setpos(struct sbuf *s, ssize_t pos) 32060ec4130SDag-Erling Smørgrav { 321546d7890SDag-Erling Smørgrav 32260ec4130SDag-Erling Smørgrav assert_sbuf_integrity(s); 32360ec4130SDag-Erling Smørgrav assert_sbuf_state(s, 0); 32460ec4130SDag-Erling Smørgrav 325adecd05bSPietro Cerutti KASSERT(pos >= 0, 326adecd05bSPietro Cerutti ("attempt to seek to a negative position (%jd)", (intmax_t)pos)); 32760ec4130SDag-Erling Smørgrav KASSERT(pos < s->s_size, 32871c2bc5cSPoul-Henning Kamp ("attempt to seek past end of sbuf (%jd >= %jd)", 32971c2bc5cSPoul-Henning Kamp (intmax_t)pos, (intmax_t)s->s_size)); 330ddb9b612SMikolaj Golub KASSERT(!SBUF_ISSECTION(s), 331ddb9b612SMikolaj Golub ("attempt to seek when in a section")); 33260ec4130SDag-Erling Smørgrav 333adecd05bSPietro Cerutti if (pos < 0 || pos > s->s_len) 33460ec4130SDag-Erling Smørgrav return (-1); 33560ec4130SDag-Erling Smørgrav s->s_len = pos; 33660ec4130SDag-Erling Smørgrav return (0); 33760ec4130SDag-Erling Smørgrav } 33860ec4130SDag-Erling Smørgrav 33960ec4130SDag-Erling Smørgrav /* 3404351ba27SMatthew D Fleming * Set up a drain function and argument on an sbuf to flush data to 3414351ba27SMatthew D Fleming * when the sbuf buffer overflows. 3424351ba27SMatthew D Fleming */ 3434351ba27SMatthew D Fleming void 3444351ba27SMatthew D Fleming sbuf_set_drain(struct sbuf *s, sbuf_drain_func *func, void *ctx) 3454351ba27SMatthew D Fleming { 3464351ba27SMatthew D Fleming 3474351ba27SMatthew D Fleming assert_sbuf_state(s, 0); 3484351ba27SMatthew D Fleming assert_sbuf_integrity(s); 3494351ba27SMatthew D Fleming KASSERT(func == s->s_drain_func || s->s_len == 0, 3504351ba27SMatthew D Fleming ("Cannot change drain to %p on non-empty sbuf %p", func, s)); 3514351ba27SMatthew D Fleming s->s_drain_func = func; 3524351ba27SMatthew D Fleming s->s_drain_arg = ctx; 3534351ba27SMatthew D Fleming } 3544351ba27SMatthew D Fleming 3554351ba27SMatthew D Fleming /* 3564351ba27SMatthew D Fleming * Call the drain and process the return. 3574351ba27SMatthew D Fleming */ 3584351ba27SMatthew D Fleming static int 3594351ba27SMatthew D Fleming sbuf_drain(struct sbuf *s) 3604351ba27SMatthew D Fleming { 3614351ba27SMatthew D Fleming int len; 3624351ba27SMatthew D Fleming 3634351ba27SMatthew D Fleming KASSERT(s->s_len > 0, ("Shouldn't drain empty sbuf %p", s)); 3644d369413SMatthew D Fleming KASSERT(s->s_error == 0, ("Called %s with error on %p", __func__, s)); 3654351ba27SMatthew D Fleming len = s->s_drain_func(s->s_drain_arg, s->s_buf, s->s_len); 3664351ba27SMatthew D Fleming if (len < 0) { 3674351ba27SMatthew D Fleming s->s_error = -len; 3684351ba27SMatthew D Fleming return (s->s_error); 3694351ba27SMatthew D Fleming } 3704e657159SMatthew D Fleming KASSERT(len > 0 && len <= s->s_len, 3714e657159SMatthew D Fleming ("Bad drain amount %d for sbuf %p", len, s)); 3724351ba27SMatthew D Fleming s->s_len -= len; 3734351ba27SMatthew D Fleming /* 3744351ba27SMatthew D Fleming * Fast path for the expected case where all the data was 3754351ba27SMatthew D Fleming * drained. 3764351ba27SMatthew D Fleming */ 3774351ba27SMatthew D Fleming if (s->s_len == 0) 3784351ba27SMatthew D Fleming return (0); 3794351ba27SMatthew D Fleming /* 3804351ba27SMatthew D Fleming * Move the remaining characters to the beginning of the 3814351ba27SMatthew D Fleming * string. 3824351ba27SMatthew D Fleming */ 3834351ba27SMatthew D Fleming memmove(s->s_buf, s->s_buf + len, s->s_len); 3844351ba27SMatthew D Fleming return (0); 3854351ba27SMatthew D Fleming } 3864351ba27SMatthew D Fleming 3874351ba27SMatthew D Fleming /* 388*2f1c4e0eSConrad Meyer * Append bytes to an sbuf. This is the core function for appending 38901f6f5fcSMatthew D Fleming * to an sbuf and is the main place that deals with extending the 39001f6f5fcSMatthew D Fleming * buffer and marking overflow. 39101f6f5fcSMatthew D Fleming */ 39201f6f5fcSMatthew D Fleming static void 393*2f1c4e0eSConrad Meyer sbuf_put_bytes(struct sbuf *s, const char *buf, size_t len) 39401f6f5fcSMatthew D Fleming { 395*2f1c4e0eSConrad Meyer size_t n; 39601f6f5fcSMatthew D Fleming 39701f6f5fcSMatthew D Fleming assert_sbuf_integrity(s); 39801f6f5fcSMatthew D Fleming assert_sbuf_state(s, 0); 39901f6f5fcSMatthew D Fleming 4004d369413SMatthew D Fleming if (s->s_error != 0) 40101f6f5fcSMatthew D Fleming return; 402*2f1c4e0eSConrad Meyer while (len > 0) { 40301f6f5fcSMatthew D Fleming if (SBUF_FREESPACE(s) <= 0) { 4044351ba27SMatthew D Fleming /* 4054351ba27SMatthew D Fleming * If there is a drain, use it, otherwise extend the 4064351ba27SMatthew D Fleming * buffer. 4074351ba27SMatthew D Fleming */ 4084351ba27SMatthew D Fleming if (s->s_drain_func != NULL) 4094351ba27SMatthew D Fleming (void)sbuf_drain(s); 410*2f1c4e0eSConrad Meyer else if (sbuf_extend(s, len > INT_MAX ? INT_MAX : len) 411*2f1c4e0eSConrad Meyer < 0) 4124d369413SMatthew D Fleming s->s_error = ENOMEM; 4134d369413SMatthew D Fleming if (s->s_error != 0) 41401f6f5fcSMatthew D Fleming return; 41501f6f5fcSMatthew D Fleming } 416*2f1c4e0eSConrad Meyer n = SBUF_FREESPACE(s); 417*2f1c4e0eSConrad Meyer if (len < n) 418*2f1c4e0eSConrad Meyer n = len; 419*2f1c4e0eSConrad Meyer memcpy(&s->s_buf[s->s_len], buf, n); 420*2f1c4e0eSConrad Meyer s->s_len += n; 421ddb9b612SMikolaj Golub if (SBUF_ISSECTION(s)) 422*2f1c4e0eSConrad Meyer s->s_sect_len += n; 423*2f1c4e0eSConrad Meyer len -= n; 424*2f1c4e0eSConrad Meyer buf += n; 425*2f1c4e0eSConrad Meyer } 426*2f1c4e0eSConrad Meyer } 427*2f1c4e0eSConrad Meyer 428*2f1c4e0eSConrad Meyer static void 429*2f1c4e0eSConrad Meyer sbuf_put_byte(struct sbuf *s, char c) 430*2f1c4e0eSConrad Meyer { 431*2f1c4e0eSConrad Meyer 432*2f1c4e0eSConrad Meyer sbuf_put_bytes(s, &c, 1); 43301f6f5fcSMatthew D Fleming } 43401f6f5fcSMatthew D Fleming 43501f6f5fcSMatthew D Fleming /* 436b0def2b5SDag-Erling Smørgrav * Append a byte string to an sbuf. 437b0def2b5SDag-Erling Smørgrav */ 438b0def2b5SDag-Erling Smørgrav int 439520df276SDag-Erling Smørgrav sbuf_bcat(struct sbuf *s, const void *buf, size_t len) 440b0def2b5SDag-Erling Smørgrav { 441d751f0a9SDag-Erling Smørgrav 442*2f1c4e0eSConrad Meyer sbuf_put_bytes(s, buf, len); 4434d369413SMatthew D Fleming if (s->s_error != 0) 444b0def2b5SDag-Erling Smørgrav return (-1); 445b0def2b5SDag-Erling Smørgrav return (0); 446b0def2b5SDag-Erling Smørgrav } 447b0def2b5SDag-Erling Smørgrav 448b0def2b5SDag-Erling Smørgrav #ifdef _KERNEL 449b0def2b5SDag-Erling Smørgrav /* 450b0def2b5SDag-Erling Smørgrav * Copy a byte string from userland into an sbuf. 451b0def2b5SDag-Erling Smørgrav */ 452b0def2b5SDag-Erling Smørgrav int 453b0def2b5SDag-Erling Smørgrav sbuf_bcopyin(struct sbuf *s, const void *uaddr, size_t len) 454b0def2b5SDag-Erling Smørgrav { 455546d7890SDag-Erling Smørgrav 456b0def2b5SDag-Erling Smørgrav assert_sbuf_integrity(s); 457b0def2b5SDag-Erling Smørgrav assert_sbuf_state(s, 0); 4584351ba27SMatthew D Fleming KASSERT(s->s_drain_func == NULL, 4594351ba27SMatthew D Fleming ("Nonsensical copyin to sbuf %p with a drain", s)); 460b0def2b5SDag-Erling Smørgrav 4614d369413SMatthew D Fleming if (s->s_error != 0) 462b0def2b5SDag-Erling Smørgrav return (-1); 463b0def2b5SDag-Erling Smørgrav if (len == 0) 464b0def2b5SDag-Erling Smørgrav return (0); 4657195eb40SKelly Yancey if (len > SBUF_FREESPACE(s)) { 4667195eb40SKelly Yancey sbuf_extend(s, len - SBUF_FREESPACE(s)); 467c05dbe7aSMatthew D Fleming if (SBUF_FREESPACE(s) < len) 468c05dbe7aSMatthew D Fleming len = SBUF_FREESPACE(s); 4697195eb40SKelly Yancey } 470e3b37322SDag-Erling Smørgrav if (copyin(uaddr, s->s_buf + s->s_len, len) != 0) 471e3b37322SDag-Erling Smørgrav return (-1); 472fe463496SDag-Erling Smørgrav s->s_len += len; 473b0def2b5SDag-Erling Smørgrav 474b0def2b5SDag-Erling Smørgrav return (0); 475b0def2b5SDag-Erling Smørgrav } 476b0def2b5SDag-Erling Smørgrav #endif 477b0def2b5SDag-Erling Smørgrav 478b0def2b5SDag-Erling Smørgrav /* 479b0def2b5SDag-Erling Smørgrav * Copy a byte string into an sbuf. 480b0def2b5SDag-Erling Smørgrav */ 481b0def2b5SDag-Erling Smørgrav int 482520df276SDag-Erling Smørgrav sbuf_bcpy(struct sbuf *s, const void *buf, size_t len) 483b0def2b5SDag-Erling Smørgrav { 484546d7890SDag-Erling Smørgrav 485b0def2b5SDag-Erling Smørgrav assert_sbuf_integrity(s); 486b0def2b5SDag-Erling Smørgrav assert_sbuf_state(s, 0); 487b0def2b5SDag-Erling Smørgrav 488b0def2b5SDag-Erling Smørgrav sbuf_clear(s); 489520df276SDag-Erling Smørgrav return (sbuf_bcat(s, buf, len)); 490b0def2b5SDag-Erling Smørgrav } 491b0def2b5SDag-Erling Smørgrav 492b0def2b5SDag-Erling Smørgrav /* 49360ec4130SDag-Erling Smørgrav * Append a string to an sbuf. 49460ec4130SDag-Erling Smørgrav */ 49560ec4130SDag-Erling Smørgrav int 4963393f8daSKenneth D. Merry sbuf_cat(struct sbuf *s, const char *str) 49760ec4130SDag-Erling Smørgrav { 498*2f1c4e0eSConrad Meyer size_t n; 499546d7890SDag-Erling Smørgrav 500*2f1c4e0eSConrad Meyer n = strlen(str); 501*2f1c4e0eSConrad Meyer sbuf_put_bytes(s, str, n); 5024d369413SMatthew D Fleming if (s->s_error != 0) 50360ec4130SDag-Erling Smørgrav return (-1); 50460ec4130SDag-Erling Smørgrav return (0); 50560ec4130SDag-Erling Smørgrav } 50660ec4130SDag-Erling Smørgrav 507b0def2b5SDag-Erling Smørgrav #ifdef _KERNEL 508b0def2b5SDag-Erling Smørgrav /* 5097195eb40SKelly Yancey * Append a string from userland to an sbuf. 510b0def2b5SDag-Erling Smørgrav */ 511b0def2b5SDag-Erling Smørgrav int 512b0def2b5SDag-Erling Smørgrav sbuf_copyin(struct sbuf *s, const void *uaddr, size_t len) 513b0def2b5SDag-Erling Smørgrav { 514b0def2b5SDag-Erling Smørgrav size_t done; 515b0def2b5SDag-Erling Smørgrav 516b0def2b5SDag-Erling Smørgrav assert_sbuf_integrity(s); 517b0def2b5SDag-Erling Smørgrav assert_sbuf_state(s, 0); 5184351ba27SMatthew D Fleming KASSERT(s->s_drain_func == NULL, 5194351ba27SMatthew D Fleming ("Nonsensical copyin to sbuf %p with a drain", s)); 520b0def2b5SDag-Erling Smørgrav 5214d369413SMatthew D Fleming if (s->s_error != 0) 522b0def2b5SDag-Erling Smørgrav return (-1); 523b0def2b5SDag-Erling Smørgrav 5247195eb40SKelly Yancey if (len == 0) 5257195eb40SKelly Yancey len = SBUF_FREESPACE(s); /* XXX return 0? */ 5267195eb40SKelly Yancey if (len > SBUF_FREESPACE(s)) { 5277195eb40SKelly Yancey sbuf_extend(s, len); 528c05dbe7aSMatthew D Fleming if (SBUF_FREESPACE(s) < len) 529c05dbe7aSMatthew D Fleming len = SBUF_FREESPACE(s); 5307195eb40SKelly Yancey } 531b0def2b5SDag-Erling Smørgrav switch (copyinstr(uaddr, s->s_buf + s->s_len, len + 1, &done)) { 532b0def2b5SDag-Erling Smørgrav case ENAMETOOLONG: 5334d369413SMatthew D Fleming s->s_error = ENOMEM; 534b0def2b5SDag-Erling Smørgrav /* fall through */ 535b0def2b5SDag-Erling Smørgrav case 0: 536b0def2b5SDag-Erling Smørgrav s->s_len += done - 1; 537ddb9b612SMikolaj Golub if (SBUF_ISSECTION(s)) 538ddb9b612SMikolaj Golub s->s_sect_len += done - 1; 539b0def2b5SDag-Erling Smørgrav break; 540b0def2b5SDag-Erling Smørgrav default: 541b0def2b5SDag-Erling Smørgrav return (-1); /* XXX */ 542b0def2b5SDag-Erling Smørgrav } 543b0def2b5SDag-Erling Smørgrav 54449091c48SPoul-Henning Kamp return (done); 545b0def2b5SDag-Erling Smørgrav } 546b0def2b5SDag-Erling Smørgrav #endif 547b0def2b5SDag-Erling Smørgrav 54860ec4130SDag-Erling Smørgrav /* 54960ec4130SDag-Erling Smørgrav * Copy a string into an sbuf. 55060ec4130SDag-Erling Smørgrav */ 55160ec4130SDag-Erling Smørgrav int 5523393f8daSKenneth D. Merry sbuf_cpy(struct sbuf *s, const char *str) 55360ec4130SDag-Erling Smørgrav { 554546d7890SDag-Erling Smørgrav 55560ec4130SDag-Erling Smørgrav assert_sbuf_integrity(s); 55660ec4130SDag-Erling Smørgrav assert_sbuf_state(s, 0); 55760ec4130SDag-Erling Smørgrav 5584dc14139SDag-Erling Smørgrav sbuf_clear(s); 55960ec4130SDag-Erling Smørgrav return (sbuf_cat(s, str)); 56060ec4130SDag-Erling Smørgrav } 56160ec4130SDag-Erling Smørgrav 56260ec4130SDag-Erling Smørgrav /* 5637195eb40SKelly Yancey * Format the given argument list and append the resulting string to an sbuf. 56460ec4130SDag-Erling Smørgrav */ 56501f6f5fcSMatthew D Fleming #ifdef _KERNEL 566eb05ee7aSPoul-Henning Kamp 567eb05ee7aSPoul-Henning Kamp /* 568eb05ee7aSPoul-Henning Kamp * Append a non-NUL character to an sbuf. This prototype signature is 569eb05ee7aSPoul-Henning Kamp * suitable for use with kvprintf(9). 570eb05ee7aSPoul-Henning Kamp */ 571eb05ee7aSPoul-Henning Kamp static void 572eb05ee7aSPoul-Henning Kamp sbuf_putc_func(int c, void *arg) 573eb05ee7aSPoul-Henning Kamp { 574eb05ee7aSPoul-Henning Kamp 575eb05ee7aSPoul-Henning Kamp if (c != '\0') 576eb05ee7aSPoul-Henning Kamp sbuf_put_byte(arg, c); 577eb05ee7aSPoul-Henning Kamp } 578eb05ee7aSPoul-Henning Kamp 57901f6f5fcSMatthew D Fleming int 58001f6f5fcSMatthew D Fleming sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap) 58101f6f5fcSMatthew D Fleming { 58201f6f5fcSMatthew D Fleming 58301f6f5fcSMatthew D Fleming assert_sbuf_integrity(s); 58401f6f5fcSMatthew D Fleming assert_sbuf_state(s, 0); 58501f6f5fcSMatthew D Fleming 58601f6f5fcSMatthew D Fleming KASSERT(fmt != NULL, 58701f6f5fcSMatthew D Fleming ("%s called with a NULL format string", __func__)); 58801f6f5fcSMatthew D Fleming 58901f6f5fcSMatthew D Fleming (void)kvprintf(fmt, sbuf_putc_func, s, 10, ap); 5904d369413SMatthew D Fleming if (s->s_error != 0) 59101f6f5fcSMatthew D Fleming return (-1); 59201f6f5fcSMatthew D Fleming return (0); 59301f6f5fcSMatthew D Fleming } 59401f6f5fcSMatthew D Fleming #else /* !_KERNEL */ 59560ec4130SDag-Erling Smørgrav int 5967195eb40SKelly Yancey sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap) 59760ec4130SDag-Erling Smørgrav { 598a9a0bbadSPeter Wemm va_list ap_copy; 599adecd05bSPietro Cerutti int error, len; 60060ec4130SDag-Erling Smørgrav 60160ec4130SDag-Erling Smørgrav assert_sbuf_integrity(s); 60260ec4130SDag-Erling Smørgrav assert_sbuf_state(s, 0); 60360ec4130SDag-Erling Smørgrav 60460ec4130SDag-Erling Smørgrav KASSERT(fmt != NULL, 605a48740b6SDavid E. O'Brien ("%s called with a NULL format string", __func__)); 60660ec4130SDag-Erling Smørgrav 6074d369413SMatthew D Fleming if (s->s_error != 0) 60860ec4130SDag-Erling Smørgrav return (-1); 60960ec4130SDag-Erling Smørgrav 61001f6f5fcSMatthew D Fleming /* 61101f6f5fcSMatthew D Fleming * For the moment, there is no way to get vsnprintf(3) to hand 61201f6f5fcSMatthew D Fleming * back a character at a time, to push everything into 61301f6f5fcSMatthew D Fleming * sbuf_putc_func() as was done for the kernel. 6144351ba27SMatthew D Fleming * 6154351ba27SMatthew D Fleming * In userspace, while drains are useful, there's generally 6164351ba27SMatthew D Fleming * not a problem attempting to malloc(3) on out of space. So 6174351ba27SMatthew D Fleming * expand a userland sbuf if there is not enough room for the 6184351ba27SMatthew D Fleming * data produced by sbuf_[v]printf(3). 61901f6f5fcSMatthew D Fleming */ 62001f6f5fcSMatthew D Fleming 6214351ba27SMatthew D Fleming error = 0; 6227195eb40SKelly Yancey do { 623a9a0bbadSPeter Wemm va_copy(ap_copy, ap); 6247195eb40SKelly Yancey len = vsnprintf(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1, 625a9a0bbadSPeter Wemm fmt, ap_copy); 626a9a0bbadSPeter Wemm va_end(ap_copy); 6274351ba27SMatthew D Fleming 6284351ba27SMatthew D Fleming if (SBUF_FREESPACE(s) >= len) 6294351ba27SMatthew D Fleming break; 6304351ba27SMatthew D Fleming /* Cannot print with the current available space. */ 6314351ba27SMatthew D Fleming if (s->s_drain_func != NULL && s->s_len > 0) 6324351ba27SMatthew D Fleming error = sbuf_drain(s); 6334351ba27SMatthew D Fleming else 6344351ba27SMatthew D Fleming error = sbuf_extend(s, len - SBUF_FREESPACE(s)); 6354351ba27SMatthew D Fleming } while (error == 0); 63660ec4130SDag-Erling Smørgrav 6373393f8daSKenneth D. Merry /* 6383393f8daSKenneth D. Merry * s->s_len is the length of the string, without the terminating nul. 6393393f8daSKenneth D. Merry * When updating s->s_len, we must subtract 1 from the length that 6403393f8daSKenneth D. Merry * we passed into vsnprintf() because that length includes the 6413393f8daSKenneth D. Merry * terminating nul. 6423393f8daSKenneth D. Merry * 6433393f8daSKenneth D. Merry * vsnprintf() returns the amount that would have been copied, 644c05dbe7aSMatthew D Fleming * given sufficient space, so don't over-increment s_len. 6453393f8daSKenneth D. Merry */ 646c05dbe7aSMatthew D Fleming if (SBUF_FREESPACE(s) < len) 647c05dbe7aSMatthew D Fleming len = SBUF_FREESPACE(s); 648c05dbe7aSMatthew D Fleming s->s_len += len; 649ddb9b612SMikolaj Golub if (SBUF_ISSECTION(s)) 650ddb9b612SMikolaj Golub s->s_sect_len += len; 6511a25c86bSPoul-Henning Kamp if (!SBUF_HASROOM(s) && !SBUF_CANEXTEND(s)) 6524d369413SMatthew D Fleming s->s_error = ENOMEM; 6533393f8daSKenneth D. Merry 65460ec4130SDag-Erling Smørgrav KASSERT(s->s_len < s->s_size, 65560ec4130SDag-Erling Smørgrav ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size)); 65660ec4130SDag-Erling Smørgrav 6574d369413SMatthew D Fleming if (s->s_error != 0) 65860ec4130SDag-Erling Smørgrav return (-1); 65960ec4130SDag-Erling Smørgrav return (0); 66060ec4130SDag-Erling Smørgrav } 66101f6f5fcSMatthew D Fleming #endif /* _KERNEL */ 66260ec4130SDag-Erling Smørgrav 66360ec4130SDag-Erling Smørgrav /* 6647195eb40SKelly Yancey * Format the given arguments and append the resulting string to an sbuf. 6657195eb40SKelly Yancey */ 6667195eb40SKelly Yancey int 6677195eb40SKelly Yancey sbuf_printf(struct sbuf *s, const char *fmt, ...) 6687195eb40SKelly Yancey { 6697195eb40SKelly Yancey va_list ap; 6707195eb40SKelly Yancey int result; 6717195eb40SKelly Yancey 6727195eb40SKelly Yancey va_start(ap, fmt); 6737195eb40SKelly Yancey result = sbuf_vprintf(s, fmt, ap); 6747195eb40SKelly Yancey va_end(ap); 6757195eb40SKelly Yancey return (result); 6767195eb40SKelly Yancey } 6777195eb40SKelly Yancey 6787195eb40SKelly Yancey /* 67960ec4130SDag-Erling Smørgrav * Append a character to an sbuf. 68060ec4130SDag-Erling Smørgrav */ 68160ec4130SDag-Erling Smørgrav int 68260ec4130SDag-Erling Smørgrav sbuf_putc(struct sbuf *s, int c) 68360ec4130SDag-Erling Smørgrav { 684546d7890SDag-Erling Smørgrav 685eb05ee7aSPoul-Henning Kamp sbuf_put_byte(s, c); 6864d369413SMatthew D Fleming if (s->s_error != 0) 68760ec4130SDag-Erling Smørgrav return (-1); 68860ec4130SDag-Erling Smørgrav return (0); 68960ec4130SDag-Erling Smørgrav } 69060ec4130SDag-Erling Smørgrav 69160ec4130SDag-Erling Smørgrav /* 6927195eb40SKelly Yancey * Trim whitespace characters from end of an sbuf. 6935b6db477SDag-Erling Smørgrav */ 6945b6db477SDag-Erling Smørgrav int 6955b6db477SDag-Erling Smørgrav sbuf_trim(struct sbuf *s) 6965b6db477SDag-Erling Smørgrav { 697546d7890SDag-Erling Smørgrav 6985b6db477SDag-Erling Smørgrav assert_sbuf_integrity(s); 6995b6db477SDag-Erling Smørgrav assert_sbuf_state(s, 0); 7004351ba27SMatthew D Fleming KASSERT(s->s_drain_func == NULL, 7014351ba27SMatthew D Fleming ("%s makes no sense on sbuf %p with drain", __func__, s)); 7025b6db477SDag-Erling Smørgrav 7034d369413SMatthew D Fleming if (s->s_error != 0) 7045b6db477SDag-Erling Smørgrav return (-1); 7055b6db477SDag-Erling Smørgrav 706ddb9b612SMikolaj Golub while (s->s_len > 0 && isspace(s->s_buf[s->s_len-1])) { 7075b6db477SDag-Erling Smørgrav --s->s_len; 708ddb9b612SMikolaj Golub if (SBUF_ISSECTION(s)) 709ddb9b612SMikolaj Golub s->s_sect_len--; 710ddb9b612SMikolaj Golub } 7115b6db477SDag-Erling Smørgrav 7125b6db477SDag-Erling Smørgrav return (0); 7135b6db477SDag-Erling Smørgrav } 7145b6db477SDag-Erling Smørgrav 7155b6db477SDag-Erling Smørgrav /* 7164d369413SMatthew D Fleming * Check if an sbuf has an error. 71760ec4130SDag-Erling Smørgrav */ 71860ec4130SDag-Erling Smørgrav int 71971c2bc5cSPoul-Henning Kamp sbuf_error(const struct sbuf *s) 7204dc14139SDag-Erling Smørgrav { 721546d7890SDag-Erling Smørgrav 7224d369413SMatthew D Fleming return (s->s_error); 7234dc14139SDag-Erling Smørgrav } 7244dc14139SDag-Erling Smørgrav 7254dc14139SDag-Erling Smørgrav /* 7264dc14139SDag-Erling Smørgrav * Finish off an sbuf. 7274dc14139SDag-Erling Smørgrav */ 7284351ba27SMatthew D Fleming int 72960ec4130SDag-Erling Smørgrav sbuf_finish(struct sbuf *s) 73060ec4130SDag-Erling Smørgrav { 731546d7890SDag-Erling Smørgrav 73260ec4130SDag-Erling Smørgrav assert_sbuf_integrity(s); 73360ec4130SDag-Erling Smørgrav assert_sbuf_state(s, 0); 73460ec4130SDag-Erling Smørgrav 735f4d28142SIan Lepore s->s_buf[s->s_len] = '\0'; 7368d5628fdSIan Lepore if (SBUF_NULINCLUDED(s)) 737f4d28142SIan Lepore s->s_len++; 7384d369413SMatthew D Fleming if (s->s_drain_func != NULL) { 739eb05ee7aSPoul-Henning Kamp while (s->s_len > 0 && s->s_error == 0) 740eb05ee7aSPoul-Henning Kamp s->s_error = sbuf_drain(s); 7414d369413SMatthew D Fleming } 74260ec4130SDag-Erling Smørgrav SBUF_SETFLAG(s, SBUF_FINISHED); 7434351ba27SMatthew D Fleming #ifdef _KERNEL 744eb05ee7aSPoul-Henning Kamp return (s->s_error); 7454351ba27SMatthew D Fleming #else 746c532f8c4SJaakko Heinonen if (s->s_error != 0) { 747eb05ee7aSPoul-Henning Kamp errno = s->s_error; 7484351ba27SMatthew D Fleming return (-1); 749c532f8c4SJaakko Heinonen } 750eb05ee7aSPoul-Henning Kamp return (0); 7514351ba27SMatthew D Fleming #endif 75260ec4130SDag-Erling Smørgrav } 75360ec4130SDag-Erling Smørgrav 75460ec4130SDag-Erling Smørgrav /* 75560ec4130SDag-Erling Smørgrav * Return a pointer to the sbuf data. 75660ec4130SDag-Erling Smørgrav */ 75760ec4130SDag-Erling Smørgrav char * 75860ec4130SDag-Erling Smørgrav sbuf_data(struct sbuf *s) 75960ec4130SDag-Erling Smørgrav { 760546d7890SDag-Erling Smørgrav 76160ec4130SDag-Erling Smørgrav assert_sbuf_integrity(s); 76260ec4130SDag-Erling Smørgrav assert_sbuf_state(s, SBUF_FINISHED); 7634351ba27SMatthew D Fleming KASSERT(s->s_drain_func == NULL, 7644351ba27SMatthew D Fleming ("%s makes no sense on sbuf %p with drain", __func__, s)); 76560ec4130SDag-Erling Smørgrav 766546d7890SDag-Erling Smørgrav return (s->s_buf); 76760ec4130SDag-Erling Smørgrav } 76860ec4130SDag-Erling Smørgrav 76960ec4130SDag-Erling Smørgrav /* 77060ec4130SDag-Erling Smørgrav * Return the length of the sbuf data. 77160ec4130SDag-Erling Smørgrav */ 77271c2bc5cSPoul-Henning Kamp ssize_t 77360ec4130SDag-Erling Smørgrav sbuf_len(struct sbuf *s) 77460ec4130SDag-Erling Smørgrav { 775546d7890SDag-Erling Smørgrav 77660ec4130SDag-Erling Smørgrav assert_sbuf_integrity(s); 7779fa2ef3dSDag-Erling Smørgrav /* don't care if it's finished or not */ 7784351ba27SMatthew D Fleming KASSERT(s->s_drain_func == NULL, 7794351ba27SMatthew D Fleming ("%s makes no sense on sbuf %p with drain", __func__, s)); 78060ec4130SDag-Erling Smørgrav 7814d369413SMatthew D Fleming if (s->s_error != 0) 7824dc14139SDag-Erling Smørgrav return (-1); 783f4d28142SIan Lepore 784f4d28142SIan Lepore /* If finished, nulterm is already in len, else add one. */ 7858d5628fdSIan Lepore if (SBUF_NULINCLUDED(s) && !SBUF_ISFINISHED(s)) 786f4d28142SIan Lepore return (s->s_len + 1); 787546d7890SDag-Erling Smørgrav return (s->s_len); 78860ec4130SDag-Erling Smørgrav } 78960ec4130SDag-Erling Smørgrav 79060ec4130SDag-Erling Smørgrav /* 79160ec4130SDag-Erling Smørgrav * Clear an sbuf, free its buffer if necessary. 79260ec4130SDag-Erling Smørgrav */ 79360ec4130SDag-Erling Smørgrav void 79460ec4130SDag-Erling Smørgrav sbuf_delete(struct sbuf *s) 79560ec4130SDag-Erling Smørgrav { 796a57094a0SMatthew Dillon int isdyn; 797a57094a0SMatthew Dillon 79860ec4130SDag-Erling Smørgrav assert_sbuf_integrity(s); 79960ec4130SDag-Erling Smørgrav /* don't care if it's finished or not */ 80060ec4130SDag-Erling Smørgrav 80160ec4130SDag-Erling Smørgrav if (SBUF_ISDYNAMIC(s)) 8023393f8daSKenneth D. Merry SBFREE(s->s_buf); 803a57094a0SMatthew Dillon isdyn = SBUF_ISDYNSTRUCT(s); 804384bf94cSPoul-Henning Kamp memset(s, 0, sizeof(*s)); 805a57094a0SMatthew Dillon if (isdyn) 806d6479358SDag-Erling Smørgrav SBFREE(s); 80760ec4130SDag-Erling Smørgrav } 808c5f9218bSPoul-Henning Kamp 809c5f9218bSPoul-Henning Kamp /* 810c5f9218bSPoul-Henning Kamp * Check if an sbuf has been finished. 811c5f9218bSPoul-Henning Kamp */ 812c5f9218bSPoul-Henning Kamp int 81371c2bc5cSPoul-Henning Kamp sbuf_done(const struct sbuf *s) 814c5f9218bSPoul-Henning Kamp { 815c5f9218bSPoul-Henning Kamp 816c5f9218bSPoul-Henning Kamp return (SBUF_ISFINISHED(s)); 817c5f9218bSPoul-Henning Kamp } 818ddb9b612SMikolaj Golub 819ddb9b612SMikolaj Golub /* 820ddb9b612SMikolaj Golub * Start a section. 821ddb9b612SMikolaj Golub */ 822ddb9b612SMikolaj Golub void 823ddb9b612SMikolaj Golub sbuf_start_section(struct sbuf *s, ssize_t *old_lenp) 824ddb9b612SMikolaj Golub { 825ddb9b612SMikolaj Golub 826ddb9b612SMikolaj Golub assert_sbuf_integrity(s); 827ddb9b612SMikolaj Golub assert_sbuf_state(s, 0); 828ddb9b612SMikolaj Golub 829ddb9b612SMikolaj Golub if (!SBUF_ISSECTION(s)) { 830ddb9b612SMikolaj Golub KASSERT(s->s_sect_len == 0, 831ddb9b612SMikolaj Golub ("s_sect_len != 0 when starting a section")); 832ddb9b612SMikolaj Golub if (old_lenp != NULL) 833ddb9b612SMikolaj Golub *old_lenp = -1; 834ddb9b612SMikolaj Golub SBUF_SETFLAG(s, SBUF_INSECTION); 835ddb9b612SMikolaj Golub } else { 836ddb9b612SMikolaj Golub KASSERT(old_lenp != NULL, 837ddb9b612SMikolaj Golub ("s_sect_len should be saved when starting a subsection")); 838ddb9b612SMikolaj Golub *old_lenp = s->s_sect_len; 839ddb9b612SMikolaj Golub s->s_sect_len = 0; 840ddb9b612SMikolaj Golub } 841ddb9b612SMikolaj Golub } 842ddb9b612SMikolaj Golub 843ddb9b612SMikolaj Golub /* 844ddb9b612SMikolaj Golub * End the section padding to the specified length with the specified 845ddb9b612SMikolaj Golub * character. 846ddb9b612SMikolaj Golub */ 847ddb9b612SMikolaj Golub ssize_t 848ddb9b612SMikolaj Golub sbuf_end_section(struct sbuf *s, ssize_t old_len, size_t pad, int c) 849ddb9b612SMikolaj Golub { 850ddb9b612SMikolaj Golub ssize_t len; 851ddb9b612SMikolaj Golub 852ddb9b612SMikolaj Golub assert_sbuf_integrity(s); 853ddb9b612SMikolaj Golub assert_sbuf_state(s, 0); 854ddb9b612SMikolaj Golub KASSERT(SBUF_ISSECTION(s), 855ddb9b612SMikolaj Golub ("attempt to end a section when not in a section")); 856ddb9b612SMikolaj Golub 857ddb9b612SMikolaj Golub if (pad > 1) { 858ddb9b612SMikolaj Golub len = roundup(s->s_sect_len, pad) - s->s_sect_len; 859ddb9b612SMikolaj Golub for (; s->s_error == 0 && len > 0; len--) 860ddb9b612SMikolaj Golub sbuf_put_byte(s, c); 861ddb9b612SMikolaj Golub } 862ddb9b612SMikolaj Golub len = s->s_sect_len; 863ddb9b612SMikolaj Golub if (old_len == -1) { 864ddb9b612SMikolaj Golub s->s_sect_len = 0; 865ddb9b612SMikolaj Golub SBUF_CLEARFLAG(s, SBUF_INSECTION); 866ddb9b612SMikolaj Golub } else { 867ddb9b612SMikolaj Golub s->s_sect_len += old_len; 868ddb9b612SMikolaj Golub } 869ddb9b612SMikolaj Golub if (s->s_error != 0) 870ddb9b612SMikolaj Golub return (-1); 871ddb9b612SMikolaj Golub return (len); 872ddb9b612SMikolaj Golub } 873