1/*- 2 * Copyright (c) 2000 Poul-Henning Kamp and Dag-Erling Co�dan Sm�rgrav 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30 31#include <sys/param.h> 32 33#ifdef KERNEL 34/* #include <ctype.h> */ 35#include <sys/kernel.h> 36#include <sys/malloc.h> 37#include <sys/systm.h> 38#include <sys/uio.h> 39#include <sys/uio_internal.h> 40#include <sys/systm.h> 41#include <stdarg.h> 42#else /* KERNEL */ 43#include <ctype.h> 44#include <stdarg.h> 45#include <stdio.h> 46#include <stdlib.h> 47#include <string.h> 48#endif /* KERNEL */ 49 50#include <sys/sbuf.h> 51 52#ifdef KERNEL 53/* MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers"); */ 54#define SBMALLOC(size) _MALLOC(size, M_SBUF, M_WAITOK) 55#define SBFREE(buf) FREE(buf, M_SBUF) 56#else /* KERNEL */ 57#define KASSERT(e, m) 58#define SBMALLOC(size) malloc(size) 59#define SBFREE(buf) free(buf) 60#define min(x,y) MIN(x,y) 61 62#endif /* KERNEL */ 63 64/* 65 * Predicates 66 */ 67#define SBUF_ISDYNAMIC(s) ((s)->s_flags & SBUF_DYNAMIC) 68#define SBUF_ISDYNSTRUCT(s) ((s)->s_flags & SBUF_DYNSTRUCT) 69#define SBUF_ISFINISHED(s) ((s)->s_flags & SBUF_FINISHED) 70#define SBUF_HASOVERFLOWED(s) ((s)->s_flags & SBUF_OVERFLOWED) 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 75/* 76 * Set / clear flags 77 */ 78#define SBUF_SETFLAG(s, f) do { (s)->s_flags |= (f); } while (0) 79#define SBUF_CLEARFLAG(s, f) do { (s)->s_flags &= ~(f); } while (0) 80 81#define SBUF_MINEXTENDSIZE 16 /* Should be power of 2. */ 82#define SBUF_MAXEXTENDSIZE PAGE_SIZE 83#define SBUF_MAXEXTENDINCR PAGE_SIZE 84 85/* 86 * Debugging support 87 */ 88#if defined(KERNEL) && defined(INVARIANTS) 89static void 90_assert_sbuf_integrity(const char *fun, struct sbuf *s) 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 KASSERT((s->s_flags & SBUF_FINISHED) == state, 104 ("%s called with %sfinished or corrupt sbuf", fun, 105 (state ? "un" : ""))); 106} 107#define assert_sbuf_integrity(s) _assert_sbuf_integrity(__func__, (s)) 108#define assert_sbuf_state(s, i) _assert_sbuf_state(__func__, (s), (i)) 109#else /* KERNEL && INVARIANTS */ 110#define assert_sbuf_integrity(s) do { } while (0) 111#define assert_sbuf_state(s, i) do { } while (0) 112#endif /* KERNEL && INVARIANTS */ 113 114static int 115sbuf_extendsize(int size) 116{ 117 int newsize; 118 119 newsize = SBUF_MINEXTENDSIZE; 120 while (newsize < size) { 121 if (newsize < (int)SBUF_MAXEXTENDSIZE) 122 newsize *= 2; 123 else 124 newsize += SBUF_MAXEXTENDINCR; 125 } 126 127 return (newsize); 128} 129 130 131/* 132 * Extend an sbuf. 133 */ 134static int 135sbuf_extend(struct sbuf *s, int addlen) 136{ 137 char *newbuf; 138 int newsize; 139 140 if (!SBUF_CANEXTEND(s)) 141 return (-1); 142 143 newsize = sbuf_extendsize(s->s_size + addlen); 144 newbuf = (char *)SBMALLOC(newsize); 145 if (newbuf == NULL) 146 return (-1); 147 bcopy(s->s_buf, newbuf, s->s_size); 148 if (SBUF_ISDYNAMIC(s)) 149 SBFREE(s->s_buf); 150 else 151 SBUF_SETFLAG(s, SBUF_DYNAMIC); 152 s->s_buf = newbuf; 153 s->s_size = newsize; 154 return (0); 155} 156 157/* 158 * Initialize an sbuf. 159 * If buf is non-NULL, it points to a static or already-allocated string 160 * big enough to hold at least length characters. 161 */ 162struct sbuf * 163sbuf_new(struct sbuf *s, char *buf, int length, int flags) 164{ 165 KASSERT(length >= 0, 166 ("attempt to create an sbuf of negative length (%d)", length)); 167 KASSERT((flags & ~SBUF_USRFLAGMSK) == 0, 168 ("%s called with invalid flags", __func__)); 169 170 flags &= SBUF_USRFLAGMSK; 171 if (s == NULL) { 172 s = (struct sbuf *)SBMALLOC(sizeof *s); 173 if (s == NULL) 174 return (NULL); 175 bzero(s, sizeof *s); 176 s->s_flags = flags; 177 SBUF_SETFLAG(s, SBUF_DYNSTRUCT); 178 } else { 179 bzero(s, sizeof *s); 180 s->s_flags = flags; 181 } 182 s->s_size = length; 183 if (buf) { 184 s->s_buf = buf; 185 return (s); 186 } 187 if (flags & SBUF_AUTOEXTEND) 188 s->s_size = sbuf_extendsize(s->s_size); 189 s->s_buf = (char *)SBMALLOC(s->s_size); 190 if (s->s_buf == NULL) { 191 if (SBUF_ISDYNSTRUCT(s)) 192 SBFREE(s); 193 return (NULL); 194 } 195 SBUF_SETFLAG(s, SBUF_DYNAMIC); 196 return (s); 197} 198 199#ifdef KERNEL 200/* 201 * Create an sbuf with uio data 202 */ 203struct sbuf * 204sbuf_uionew(struct sbuf *s, struct uio *uio, int *error) 205{ 206 KASSERT(uio != NULL, 207 ("%s called with NULL uio pointer", __func__)); 208 KASSERT(error != NULL, 209 ("%s called with NULL error pointer", __func__)); 210 211 s = sbuf_new(s, NULL, uio->uio_resid + 1, 0); 212 if (s == NULL) { 213 *error = ENOMEM; 214 return (NULL); 215 } 216 *error = uiomove(s->s_buf, uio->uio_resid, uio); 217 if (*error != 0) { 218 sbuf_delete(s); 219 return (NULL); 220 } 221 s->s_len = s->s_size - 1; 222 *error = 0; 223 return (s); 224} 225#endif 226 227/* 228 * Clear an sbuf and reset its position. 229 */ 230void 231sbuf_clear(struct sbuf *s) 232{ 233 assert_sbuf_integrity(s); 234 /* don't care if it's finished or not */ 235 236 SBUF_CLEARFLAG(s, SBUF_FINISHED); 237 SBUF_CLEARFLAG(s, SBUF_OVERFLOWED); 238 s->s_len = 0; 239} 240 241/* 242 * Set the sbuf's end position to an arbitrary value. 243 * Effectively truncates the sbuf at the new position. 244 */ 245int 246sbuf_setpos(struct sbuf *s, int pos) 247{ 248 assert_sbuf_integrity(s); 249 assert_sbuf_state(s, 0); 250 251 KASSERT(pos >= 0, 252 ("attempt to seek to a negative position (%d)", pos)); 253 KASSERT(pos < s->s_size, 254 ("attempt to seek past end of sbuf (%d >= %d)", pos, s->s_size)); 255 256 if (pos < 0 || pos > s->s_len) 257 return (-1); 258 s->s_len = pos; 259 return (0); 260} 261 262/* 263 * Append a byte string to an sbuf. 264 */ 265int 266sbuf_bcat(struct sbuf *s, const void *buf, size_t len) 267{ 268 const char *str = buf; 269 270 assert_sbuf_integrity(s); 271 assert_sbuf_state(s, 0); 272 273 if (SBUF_HASOVERFLOWED(s)) 274 return (-1); 275 276 for (; len; len--) { 277 if (!SBUF_HASROOM(s) && sbuf_extend(s, len) < 0) 278 break; 279 s->s_buf[s->s_len++] = *str++; 280 } 281 if (len) { 282 SBUF_SETFLAG(s, SBUF_OVERFLOWED); 283 return (-1); 284 } 285 return (0); 286} 287 288#ifdef KERNEL 289/* 290 * Copy a byte string from userland into an sbuf. 291 */ 292int 293sbuf_bcopyin(struct sbuf *s, const void *uaddr, size_t len) 294{ 295 assert_sbuf_integrity(s); 296 assert_sbuf_state(s, 0); 297 298 if (SBUF_HASOVERFLOWED(s)) 299 return (-1); 300 301 if (len == 0) 302 return (0); 303 if (len > (unsigned) SBUF_FREESPACE(s)) { 304 sbuf_extend(s, len - SBUF_FREESPACE(s)); 305 len = min(len, SBUF_FREESPACE(s)); 306 } 307 if (copyin(CAST_USER_ADDR_T(uaddr), s->s_buf + s->s_len, len) != 0) 308 return (-1); 309 s->s_len += len; 310 311 return (0); 312} 313#endif 314 315/* 316 * Copy a byte string into an sbuf. 317 */ 318int 319sbuf_bcpy(struct sbuf *s, const void *buf, size_t len) 320{ 321 assert_sbuf_integrity(s); 322 assert_sbuf_state(s, 0); 323 324 sbuf_clear(s); 325 return (sbuf_bcat(s, buf, len)); 326} 327 328/* 329 * Append a string to an sbuf. 330 */ 331int 332sbuf_cat(struct sbuf *s, const char *str) 333{ 334 assert_sbuf_integrity(s); 335 assert_sbuf_state(s, 0); 336 337 if (SBUF_HASOVERFLOWED(s)) 338 return (-1); 339 340 while (*str) { 341 if (!SBUF_HASROOM(s) && sbuf_extend(s, strlen(str)) < 0) 342 break; 343 s->s_buf[s->s_len++] = *str++; 344 } 345 if (*str) { 346 SBUF_SETFLAG(s, SBUF_OVERFLOWED); 347 return (-1); 348 } 349 return (0); 350} 351 352#ifdef KERNEL 353/* 354 * Append a string from userland to an sbuf. 355 */ 356int 357sbuf_copyin(struct sbuf *s, const void *uaddr, size_t len) 358{ 359 size_t done; 360 361 assert_sbuf_integrity(s); 362 assert_sbuf_state(s, 0); 363 364 if (SBUF_HASOVERFLOWED(s)) 365 return (-1); 366 367 if (len == 0) 368 len = SBUF_FREESPACE(s); /* XXX return 0? */ 369 if (len > (unsigned) SBUF_FREESPACE(s)) { 370 sbuf_extend(s, len); 371 len = min(len, SBUF_FREESPACE(s)); 372 } 373 switch (copyinstr(CAST_USER_ADDR_T(uaddr), s->s_buf + s->s_len, len + 1, &done)) { 374 case ENAMETOOLONG: 375 SBUF_SETFLAG(s, SBUF_OVERFLOWED); 376 /* fall through */ 377 case 0: 378 s->s_len += done - 1; 379 break; 380 default: 381 return (-1); /* XXX */ 382 } 383 384 return (done); 385} 386#endif 387 388/* 389 * Copy a string into an sbuf. 390 */ 391int 392sbuf_cpy(struct sbuf *s, const char *str) 393{ 394 assert_sbuf_integrity(s); 395 assert_sbuf_state(s, 0); 396 397 sbuf_clear(s); 398 return (sbuf_cat(s, str)); 399} 400 401/* 402 * Format the given argument list and append the resulting string to an sbuf. 403 */ 404int 405sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap) 406{ 407 __builtin_va_list ap_copy; /* XXX tduffy - blame on him */ 408 int len; 409 410 assert_sbuf_integrity(s); 411 assert_sbuf_state(s, 0); 412 413 KASSERT(fmt != NULL, 414 ("%s called with a NULL format string", __func__)); 415 416 if (SBUF_HASOVERFLOWED(s)) 417 return (-1); 418 419 do { 420 va_copy(ap_copy, ap); 421 len = vsnprintf(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1, 422 fmt, ap_copy); 423 va_end(ap_copy); 424 } while (len > SBUF_FREESPACE(s) && 425 sbuf_extend(s, len - SBUF_FREESPACE(s)) == 0); 426 427 /* 428 * s->s_len is the length of the string, without the terminating nul. 429 * When updating s->s_len, we must subtract 1 from the length that 430 * we passed into vsnprintf() because that length includes the 431 * terminating nul. 432 * 433 * vsnprintf() returns the amount that would have been copied, 434 * given sufficient space, hence the min() calculation below. 435 */ 436 s->s_len += min(len, SBUF_FREESPACE(s)); 437 if (!SBUF_HASROOM(s) && !SBUF_CANEXTEND(s)) 438 SBUF_SETFLAG(s, SBUF_OVERFLOWED); 439 440 KASSERT(s->s_len < s->s_size, 441 ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size)); 442 443 if (SBUF_HASOVERFLOWED(s)) 444 return (-1); 445 return (0); 446} 447 448/* 449 * Format the given arguments and append the resulting string to an sbuf. 450 */ 451int 452sbuf_printf(struct sbuf *s, const char *fmt, ...) 453{ 454 va_list ap; 455 int result; 456 457 va_start(ap, fmt); 458 result = sbuf_vprintf(s, fmt, ap); 459 va_end(ap); 460 return(result); 461} 462 463/* 464 * Append a character to an sbuf. 465 */ 466int 467sbuf_putc(struct sbuf *s, int c) 468{ 469 assert_sbuf_integrity(s); 470 assert_sbuf_state(s, 0); 471 472 if (SBUF_HASOVERFLOWED(s)) 473 return (-1); 474 475 if (!SBUF_HASROOM(s) && sbuf_extend(s, 1) < 0) { 476 SBUF_SETFLAG(s, SBUF_OVERFLOWED); 477 return (-1); 478 } 479 if (c != '\0') 480 s->s_buf[s->s_len++] = c; 481 return (0); 482} 483 484static inline int 485isspace(char ch) 486{ 487 return (ch == ' ' || ch == '\n' || ch == '\t'); 488} 489 490/* 491 * Trim whitespace characters from end of an sbuf. 492 */ 493int 494sbuf_trim(struct sbuf *s) 495{ 496 assert_sbuf_integrity(s); 497 assert_sbuf_state(s, 0); 498 499 if (SBUF_HASOVERFLOWED(s)) 500 return (-1); 501 502 while (s->s_len && isspace(s->s_buf[s->s_len-1])) 503 --s->s_len; 504 505 return (0); 506} 507 508/* 509 * Check if an sbuf overflowed 510 */ 511int 512sbuf_overflowed(struct sbuf *s) 513{ 514 return SBUF_HASOVERFLOWED(s); 515} 516 517/* 518 * Finish off an sbuf. 519 */ 520void 521sbuf_finish(struct sbuf *s) 522{ 523 assert_sbuf_integrity(s); 524 assert_sbuf_state(s, 0); 525 526 s->s_buf[s->s_len] = '\0'; 527 SBUF_CLEARFLAG(s, SBUF_OVERFLOWED); 528 SBUF_SETFLAG(s, SBUF_FINISHED); 529} 530 531/* 532 * Return a pointer to the sbuf data. 533 */ 534char * 535sbuf_data(struct sbuf *s) 536{ 537 assert_sbuf_integrity(s); 538 assert_sbuf_state(s, SBUF_FINISHED); 539 540 return s->s_buf; 541} 542 543/* 544 * Return the length of the sbuf data. 545 */ 546int 547sbuf_len(struct sbuf *s) 548{ 549 assert_sbuf_integrity(s); 550 /* don't care if it's finished or not */ 551 552 if (SBUF_HASOVERFLOWED(s)) 553 return (-1); 554 return s->s_len; 555} 556 557/* 558 * Clear an sbuf, free its buffer if necessary. 559 */ 560void 561sbuf_delete(struct sbuf *s) 562{ 563 int isdyn; 564 565 assert_sbuf_integrity(s); 566 /* don't care if it's finished or not */ 567 568 if (SBUF_ISDYNAMIC(s)) 569 SBFREE(s->s_buf); 570 isdyn = SBUF_ISDYNSTRUCT(s); 571 bzero(s, sizeof *s); 572 if (isdyn) 573 SBFREE(s); 574} 575 576/* 577 * Check if an sbuf has been finished. 578 */ 579int 580sbuf_done(struct sbuf *s) 581{ 582 583 return(SBUF_ISFINISHED(s)); 584} 585