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