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