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