The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/subr_sbuf.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 99673ab5cf989eebdaa47c4f29d2dfea


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.