subr_sbuf.c revision 212184
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: head/sys/kern/subr_sbuf.c 212184 2010-09-03 17:42:17Z mdf $"); 31 32#include <sys/param.h> 33 34#ifdef _KERNEL 35#include <sys/ctype.h> 36#include <sys/kernel.h> 37#include <sys/malloc.h> 38#include <sys/systm.h> 39#include <sys/uio.h> 40#include <machine/stdarg.h> 41#else /* _KERNEL */ 42#include <ctype.h> 43#include <stdarg.h> 44#include <stdio.h> 45#include <stdlib.h> 46#include <string.h> 47#endif /* _KERNEL */ 48 49#include <sys/sbuf.h> 50 51#ifdef _KERNEL 52static MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers"); 53#define SBMALLOC(size) malloc(size, M_SBUF, M_WAITOK) 54#define SBFREE(buf) free(buf, M_SBUF) 55#else /* _KERNEL */ 56#define KASSERT(e, m) 57#define SBMALLOC(size) malloc(size) 58#define SBFREE(buf) free(buf) 59#endif /* _KERNEL */ 60 61/* 62 * Predicates 63 */ 64#define SBUF_ISDYNAMIC(s) ((s)->s_flags & SBUF_DYNAMIC) 65#define SBUF_ISDYNSTRUCT(s) ((s)->s_flags & SBUF_DYNSTRUCT) 66#define SBUF_ISFINISHED(s) ((s)->s_flags & SBUF_FINISHED) 67#define SBUF_HASOVERFLOWED(s) ((s)->s_flags & SBUF_OVERFLOWED) 68#define SBUF_HASROOM(s) ((s)->s_len < (s)->s_size - 1) 69#define SBUF_FREESPACE(s) ((s)->s_size - (s)->s_len - 1) 70#define SBUF_CANEXTEND(s) ((s)->s_flags & SBUF_AUTOEXTEND) 71 72/* 73 * Set / clear flags 74 */ 75#define SBUF_SETFLAG(s, f) do { (s)->s_flags |= (f); } while (0) 76#define SBUF_CLEARFLAG(s, f) do { (s)->s_flags &= ~(f); } while (0) 77 78#define SBUF_MINEXTENDSIZE 16 /* Should be power of 2. */ 79#define SBUF_MAXEXTENDSIZE PAGE_SIZE 80#define SBUF_MAXEXTENDINCR PAGE_SIZE 81 82/* 83 * Debugging support 84 */ 85#if defined(_KERNEL) && defined(INVARIANTS) 86 87static void 88_assert_sbuf_integrity(const char *fun, struct sbuf *s) 89{ 90 91 KASSERT(s != NULL, 92 ("%s called with a NULL sbuf pointer", fun)); 93 KASSERT(s->s_buf != NULL, 94 ("%s called with uninitialized or corrupt sbuf", fun)); 95 KASSERT(s->s_len < s->s_size, 96 ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size)); 97} 98 99static void 100_assert_sbuf_state(const char *fun, struct sbuf *s, int state) 101{ 102 103 KASSERT((s->s_flags & SBUF_FINISHED) == state, 104 ("%s called with %sfinished or corrupt sbuf", fun, 105 (state ? "un" : ""))); 106} 107 108#define assert_sbuf_integrity(s) _assert_sbuf_integrity(__func__, (s)) 109#define assert_sbuf_state(s, i) _assert_sbuf_state(__func__, (s), (i)) 110 111#else /* _KERNEL && INVARIANTS */ 112 113#define assert_sbuf_integrity(s) do { } while (0) 114#define assert_sbuf_state(s, i) do { } while (0) 115 116#endif /* _KERNEL && INVARIANTS */ 117 118#ifdef CTASSERT 119CTASSERT(powerof2(SBUF_MAXEXTENDSIZE)); 120CTASSERT(powerof2(SBUF_MAXEXTENDINCR)); 121#endif 122 123static int 124sbuf_extendsize(int size) 125{ 126 int newsize; 127 128 if (size < (int)SBUF_MAXEXTENDSIZE) { 129 newsize = SBUF_MINEXTENDSIZE; 130 while (newsize < size) 131 newsize *= 2; 132 } else { 133 newsize = roundup2(size, SBUF_MAXEXTENDINCR); 134 } 135 KASSERT(newsize >= size, ("%s: %d < %d\n", __func__, newsize, size)); 136 return (newsize); 137} 138 139 140/* 141 * Extend an sbuf. 142 */ 143static int 144sbuf_extend(struct sbuf *s, int addlen) 145{ 146 char *newbuf; 147 int newsize; 148 149 if (!SBUF_CANEXTEND(s)) 150 return (-1); 151 newsize = sbuf_extendsize(s->s_size + addlen); 152 newbuf = SBMALLOC(newsize); 153 if (newbuf == NULL) 154 return (-1); 155 bcopy(s->s_buf, newbuf, s->s_size); 156 if (SBUF_ISDYNAMIC(s)) 157 SBFREE(s->s_buf); 158 else 159 SBUF_SETFLAG(s, SBUF_DYNAMIC); 160 s->s_buf = newbuf; 161 s->s_size = newsize; 162 return (0); 163} 164 165/* 166 * Initialize an sbuf. 167 * If buf is non-NULL, it points to a static or already-allocated string 168 * big enough to hold at least length characters. 169 */ 170struct sbuf * 171sbuf_new(struct sbuf *s, char *buf, int length, int flags) 172{ 173 174 KASSERT(length >= 0, 175 ("attempt to create an sbuf of negative length (%d)", length)); 176 KASSERT((flags & ~SBUF_USRFLAGMSK) == 0, 177 ("%s called with invalid flags", __func__)); 178 179 flags &= SBUF_USRFLAGMSK; 180 if (s == NULL) { 181 s = SBMALLOC(sizeof(*s)); 182 if (s == NULL) 183 return (NULL); 184 bzero(s, sizeof(*s)); 185 s->s_flags = flags; 186 SBUF_SETFLAG(s, SBUF_DYNSTRUCT); 187 } else { 188 bzero(s, sizeof(*s)); 189 s->s_flags = flags; 190 } 191 s->s_size = length; 192 if (buf != NULL) { 193 s->s_buf = buf; 194 return (s); 195 } 196 if ((flags & SBUF_AUTOEXTEND) != 0) 197 s->s_size = sbuf_extendsize(s->s_size); 198 s->s_buf = SBMALLOC(s->s_size); 199 if (s->s_buf == NULL) { 200 if (SBUF_ISDYNSTRUCT(s)) 201 SBFREE(s); 202 return (NULL); 203 } 204 SBUF_SETFLAG(s, SBUF_DYNAMIC); 205 return (s); 206} 207 208#ifdef _KERNEL 209/* 210 * Create an sbuf with uio data 211 */ 212struct sbuf * 213sbuf_uionew(struct sbuf *s, struct uio *uio, int *error) 214{ 215 216 KASSERT(uio != NULL, 217 ("%s called with NULL uio pointer", __func__)); 218 KASSERT(error != NULL, 219 ("%s called with NULL error pointer", __func__)); 220 221 s = sbuf_new(s, NULL, uio->uio_resid + 1, 0); 222 if (s == NULL) { 223 *error = ENOMEM; 224 return (NULL); 225 } 226 *error = uiomove(s->s_buf, uio->uio_resid, uio); 227 if (*error != 0) { 228 sbuf_delete(s); 229 return (NULL); 230 } 231 s->s_len = s->s_size - 1; 232 *error = 0; 233 return (s); 234} 235#endif 236 237/* 238 * Clear an sbuf and reset its position. 239 */ 240void 241sbuf_clear(struct sbuf *s) 242{ 243 244 assert_sbuf_integrity(s); 245 /* don't care if it's finished or not */ 246 247 SBUF_CLEARFLAG(s, SBUF_FINISHED); 248 SBUF_CLEARFLAG(s, SBUF_OVERFLOWED); 249 s->s_len = 0; 250} 251 252/* 253 * Set the sbuf's end position to an arbitrary value. 254 * Effectively truncates the sbuf at the new position. 255 */ 256int 257sbuf_setpos(struct sbuf *s, int pos) 258{ 259 260 assert_sbuf_integrity(s); 261 assert_sbuf_state(s, 0); 262 263 KASSERT(pos >= 0, 264 ("attempt to seek to a negative position (%d)", pos)); 265 KASSERT(pos < s->s_size, 266 ("attempt to seek past end of sbuf (%d >= %d)", pos, s->s_size)); 267 268 if (pos < 0 || pos > s->s_len) 269 return (-1); 270 s->s_len = pos; 271 return (0); 272} 273 274/* 275 * Append a byte string to an sbuf. 276 */ 277int 278sbuf_bcat(struct sbuf *s, const void *buf, size_t len) 279{ 280 const char *str = buf; 281 282 assert_sbuf_integrity(s); 283 assert_sbuf_state(s, 0); 284 285 if (SBUF_HASOVERFLOWED(s)) 286 return (-1); 287 for (; len; len--) { 288 if (!SBUF_HASROOM(s) && sbuf_extend(s, len) < 0) 289 break; 290 s->s_buf[s->s_len++] = *str++; 291 } 292 if (len > 0) { 293 SBUF_SETFLAG(s, SBUF_OVERFLOWED); 294 return (-1); 295 } 296 return (0); 297} 298 299#ifdef _KERNEL 300/* 301 * Copy a byte string from userland into an sbuf. 302 */ 303int 304sbuf_bcopyin(struct sbuf *s, const void *uaddr, size_t len) 305{ 306 307 assert_sbuf_integrity(s); 308 assert_sbuf_state(s, 0); 309 310 if (SBUF_HASOVERFLOWED(s)) 311 return (-1); 312 if (len == 0) 313 return (0); 314 if (len > SBUF_FREESPACE(s)) { 315 sbuf_extend(s, len - SBUF_FREESPACE(s)); 316 if (SBUF_FREESPACE(s) < len) 317 len = SBUF_FREESPACE(s); 318 } 319 if (copyin(uaddr, s->s_buf + s->s_len, len) != 0) 320 return (-1); 321 s->s_len += len; 322 323 return (0); 324} 325#endif 326 327/* 328 * Copy a byte string into an sbuf. 329 */ 330int 331sbuf_bcpy(struct sbuf *s, const void *buf, size_t len) 332{ 333 334 assert_sbuf_integrity(s); 335 assert_sbuf_state(s, 0); 336 337 sbuf_clear(s); 338 return (sbuf_bcat(s, buf, len)); 339} 340 341/* 342 * Append a string to an sbuf. 343 */ 344int 345sbuf_cat(struct sbuf *s, const char *str) 346{ 347 348 assert_sbuf_integrity(s); 349 assert_sbuf_state(s, 0); 350 351 if (SBUF_HASOVERFLOWED(s)) 352 return (-1); 353 354 while (*str != '\0') { 355 if (!SBUF_HASROOM(s) && sbuf_extend(s, strlen(str)) < 0) 356 break; 357 s->s_buf[s->s_len++] = *str++; 358 } 359 if (*str != '\0') { 360 SBUF_SETFLAG(s, SBUF_OVERFLOWED); 361 return (-1); 362 } 363 return (0); 364} 365 366#ifdef _KERNEL 367/* 368 * Append a string from userland to an sbuf. 369 */ 370int 371sbuf_copyin(struct sbuf *s, const void *uaddr, size_t len) 372{ 373 size_t done; 374 375 assert_sbuf_integrity(s); 376 assert_sbuf_state(s, 0); 377 378 if (SBUF_HASOVERFLOWED(s)) 379 return (-1); 380 381 if (len == 0) 382 len = SBUF_FREESPACE(s); /* XXX return 0? */ 383 if (len > SBUF_FREESPACE(s)) { 384 sbuf_extend(s, len); 385 if (SBUF_FREESPACE(s) < len) 386 len = SBUF_FREESPACE(s); 387 } 388 switch (copyinstr(uaddr, s->s_buf + s->s_len, len + 1, &done)) { 389 case ENAMETOOLONG: 390 SBUF_SETFLAG(s, SBUF_OVERFLOWED); 391 /* fall through */ 392 case 0: 393 s->s_len += done - 1; 394 break; 395 default: 396 return (-1); /* XXX */ 397 } 398 399 return (done); 400} 401#endif 402 403/* 404 * Copy a string into an sbuf. 405 */ 406int 407sbuf_cpy(struct sbuf *s, const char *str) 408{ 409 410 assert_sbuf_integrity(s); 411 assert_sbuf_state(s, 0); 412 413 sbuf_clear(s); 414 return (sbuf_cat(s, str)); 415} 416 417/* 418 * Format the given argument list and append the resulting string to an sbuf. 419 */ 420int 421sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap) 422{ 423 va_list ap_copy; 424 int len; 425 426 assert_sbuf_integrity(s); 427 assert_sbuf_state(s, 0); 428 429 KASSERT(fmt != NULL, 430 ("%s called with a NULL format string", __func__)); 431 432 if (SBUF_HASOVERFLOWED(s)) 433 return (-1); 434 435 do { 436 va_copy(ap_copy, ap); 437 len = vsnprintf(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1, 438 fmt, ap_copy); 439 va_end(ap_copy); 440 } while (len > SBUF_FREESPACE(s) && 441 sbuf_extend(s, len - SBUF_FREESPACE(s)) == 0); 442 443 /* 444 * s->s_len is the length of the string, without the terminating nul. 445 * When updating s->s_len, we must subtract 1 from the length that 446 * we passed into vsnprintf() because that length includes the 447 * terminating nul. 448 * 449 * vsnprintf() returns the amount that would have been copied, 450 * given sufficient space, so don't over-increment s_len. 451 */ 452 if (SBUF_FREESPACE(s) < len) 453 len = SBUF_FREESPACE(s); 454 s->s_len += len; 455 if (!SBUF_HASROOM(s) && !SBUF_CANEXTEND(s)) 456 SBUF_SETFLAG(s, SBUF_OVERFLOWED); 457 458 KASSERT(s->s_len < s->s_size, 459 ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size)); 460 461 if (SBUF_HASOVERFLOWED(s)) 462 return (-1); 463 return (0); 464} 465 466/* 467 * Format the given arguments and append the resulting string to an sbuf. 468 */ 469int 470sbuf_printf(struct sbuf *s, const char *fmt, ...) 471{ 472 va_list ap; 473 int result; 474 475 va_start(ap, fmt); 476 result = sbuf_vprintf(s, fmt, ap); 477 va_end(ap); 478 return (result); 479} 480 481/* 482 * Append a character to an sbuf. 483 */ 484int 485sbuf_putc(struct sbuf *s, int c) 486{ 487 488 assert_sbuf_integrity(s); 489 assert_sbuf_state(s, 0); 490 491 if (SBUF_HASOVERFLOWED(s)) 492 return (-1); 493 if (!SBUF_HASROOM(s) && sbuf_extend(s, 1) < 0) { 494 SBUF_SETFLAG(s, SBUF_OVERFLOWED); 495 return (-1); 496 } 497 if (c != '\0') 498 s->s_buf[s->s_len++] = c; 499 return (0); 500} 501 502/* 503 * Trim whitespace characters from end of an sbuf. 504 */ 505int 506sbuf_trim(struct sbuf *s) 507{ 508 509 assert_sbuf_integrity(s); 510 assert_sbuf_state(s, 0); 511 512 if (SBUF_HASOVERFLOWED(s)) 513 return (-1); 514 515 while (s->s_len > 0 && isspace(s->s_buf[s->s_len-1])) 516 --s->s_len; 517 518 return (0); 519} 520 521/* 522 * Check if an sbuf overflowed 523 */ 524int 525sbuf_overflowed(struct sbuf *s) 526{ 527 528 return (SBUF_HASOVERFLOWED(s)); 529} 530 531/* 532 * Finish off an sbuf. 533 */ 534void 535sbuf_finish(struct sbuf *s) 536{ 537 538 assert_sbuf_integrity(s); 539 assert_sbuf_state(s, 0); 540 541 s->s_buf[s->s_len] = '\0'; 542 SBUF_CLEARFLAG(s, SBUF_OVERFLOWED); 543 SBUF_SETFLAG(s, SBUF_FINISHED); 544} 545 546/* 547 * Return a pointer to the sbuf data. 548 */ 549char * 550sbuf_data(struct sbuf *s) 551{ 552 553 assert_sbuf_integrity(s); 554 assert_sbuf_state(s, SBUF_FINISHED); 555 556 return (s->s_buf); 557} 558 559/* 560 * Return the length of the sbuf data. 561 */ 562int 563sbuf_len(struct sbuf *s) 564{ 565 566 assert_sbuf_integrity(s); 567 /* don't care if it's finished or not */ 568 569 if (SBUF_HASOVERFLOWED(s)) 570 return (-1); 571 return (s->s_len); 572} 573 574/* 575 * Clear an sbuf, free its buffer if necessary. 576 */ 577void 578sbuf_delete(struct sbuf *s) 579{ 580 int isdyn; 581 582 assert_sbuf_integrity(s); 583 /* don't care if it's finished or not */ 584 585 if (SBUF_ISDYNAMIC(s)) 586 SBFREE(s->s_buf); 587 isdyn = SBUF_ISDYNSTRUCT(s); 588 bzero(s, sizeof(*s)); 589 if (isdyn) 590 SBFREE(s); 591} 592 593/* 594 * Check if an sbuf has been finished. 595 */ 596int 597sbuf_done(struct sbuf *s) 598{ 599 600 return (SBUF_ISFINISHED(s)); 601} 602