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

Cache object: 332c76275bd14b970d5c4c4750454a38


[ 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.