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