subr_sbuf.c revision 79162
169990Sdes/*-
269990Sdes * Copyright (c) 2000 Poul-Henning Kamp and Dag-Erling Co�dan Sm�rgrav
369990Sdes * All rights reserved.
469990Sdes *
569990Sdes * Redistribution and use in source and binary forms, with or without
669990Sdes * modification, are permitted provided that the following conditions
769990Sdes * are met:
869990Sdes * 1. Redistributions of source code must retain the above copyright
969990Sdes *    notice, this list of conditions and the following disclaimer
1069990Sdes *    in this position and unchanged.
1169990Sdes * 2. Redistributions in binary form must reproduce the above copyright
1269990Sdes *    notice, this list of conditions and the following disclaimer in the
1369990Sdes *    documentation and/or other materials provided with the distribution.
1469990Sdes * 3. The name of the author may not be used to endorse or promote products
1569990Sdes *    derived from this software without specific prior written permission.
1669990Sdes *
1769990Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1869990Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1969990Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2069990Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2169990Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2269990Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2369990Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2469990Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2569990Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2669990Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2769990Sdes *
2869990Sdes *      $FreeBSD: head/sys/kern/subr_sbuf.c 79162 2001-07-03 21:46:43Z des $
2969990Sdes */
3069990Sdes
3169990Sdes#include <sys/param.h>
3274840Sken#include <sys/sbuf.h>
3374840Sken
3474840Sken#ifdef _KERNEL
3569990Sdes#include <sys/kernel.h>
3669990Sdes#include <sys/malloc.h>
3769990Sdes#include <sys/systm.h>
3869990Sdes#include <machine/stdarg.h>
3974840Sken#else /* _KERNEL */
4074840Sken#include <stdarg.h>
4178340Sjlemon#include <stdlib.h>
4274840Sken#endif /* _KERNEL */
4369990Sdes
4474840Sken#ifdef _KERNEL
4569990SdesMALLOC_DEFINE(M_SBUF, "sbuf", "string buffers");
4674840Sken#define SBMALLOC(size)		malloc(size, M_SBUF, M_WAITOK)
4774840Sken#define SBFREE(buf)		free(buf, M_SBUF)
4874840Sken#else /* _KERNEL */
4974840Sken#define KASSERT(e, m)
5074840Sken#define SBMALLOC(size)		malloc(size)
5174840Sken#define SBFREE(buf)		free(buf)
5274840Sken#define min(x,y)		MIN(x,y)
5374840Sken#endif /* _KERNEL */
5469990Sdes
5571721Sdes/*
5671721Sdes * Predicates
5771721Sdes */
5871721Sdes#define SBUF_ISDYNAMIC(s)	((s)->s_flags & SBUF_DYNAMIC)
5977989Sdes#define SBUF_ISDYNSTRUCT(s)	((s)->s_flags & SBUF_DYNSTRUCT)
6071721Sdes#define SBUF_ISFINISHED(s)	((s)->s_flags & SBUF_FINISHED)
6171721Sdes#define SBUF_HASOVERFLOWED(s)	((s)->s_flags & SBUF_OVERFLOWED)
6271721Sdes#define SBUF_HASROOM(s)		((s)->s_len < (s)->s_size - 1)
6371721Sdes
6471721Sdes/*
6571721Sdes * Set / clear flags
6671721Sdes */
6771721Sdes#define SBUF_SETFLAG(s, f)	do { (s)->s_flags |= (f); } while (0)
6871721Sdes#define SBUF_CLEARFLAG(s, f)	do { (s)->s_flags &= ~(f); } while (0)
6971721Sdes
7071721Sdes/*
7171721Sdes * Debugging support
7271721Sdes */
7374840Sken#if defined(_KERNEL) && defined(INVARIANTS)
7469990Sdesstatic void
7573891Sdes_assert_sbuf_integrity(char *fun, struct sbuf *s)
7669990Sdes{
7769990Sdes	KASSERT(s != NULL,
7873891Sdes	    ("%s called with a NULL sbuf pointer", fun));
7969990Sdes	KASSERT(s->s_buf != NULL,
8073891Sdes	    ("%s called with unitialized or corrupt sbuf", fun));
8169990Sdes	KASSERT(s->s_len < s->s_size,
8269990Sdes	    ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size));
8369990Sdes}
8469990Sdes
8569990Sdesstatic void
8673891Sdes_assert_sbuf_state(char *fun, struct sbuf *s, int state)
8769990Sdes{
8869990Sdes	KASSERT((s->s_flags & SBUF_FINISHED) == state,
8973891Sdes	    ("%s called with %sfinished or corrupt sbuf", fun,
9069990Sdes	    (state ? "un" : "")));
9169990Sdes}
9273891Sdes#define assert_sbuf_integrity(s) _assert_sbuf_integrity(__FUNCTION__, (s))
9373891Sdes#define assert_sbuf_state(s, i)	 _assert_sbuf_state(__FUNCTION__, (s), (i))
9474840Sken#else /* _KERNEL && INVARIANTS */
9569990Sdes#define assert_sbuf_integrity(s) do { } while (0)
9669990Sdes#define assert_sbuf_state(s, i)	 do { } while (0)
9774840Sken#endif /* _KERNEL && INVARIANTS */
9869990Sdes
9969990Sdes/*
10069990Sdes * Initialize an sbuf.
10169990Sdes * If buf is non-NULL, it points to a static or already-allocated string
10269990Sdes * big enough to hold at least length characters.
10369990Sdes */
10477989Sdesstruct sbuf *
10571721Sdessbuf_new(struct sbuf *s, char *buf, int length, int flags)
10669990Sdes{
10771721Sdes	KASSERT(length >= 0,
10871721Sdes	    ("attempt to create an sbuf of negative length (%d)", length));
10969990Sdes	KASSERT(flags == 0,
11069990Sdes	    (__FUNCTION__ " called with non-zero flags"));
11169990Sdes
11277989Sdes	if (s == NULL) {
11377989Sdes		s = (struct sbuf *)SBMALLOC(sizeof *s);
11477989Sdes		if (s == NULL)
11577989Sdes			return (NULL);
11677989Sdes		bzero(s, sizeof *s);
11777989Sdes		SBUF_SETFLAG(s, SBUF_DYNSTRUCT);
11877989Sdes	} else {
11977989Sdes		bzero(s, sizeof *s);
12077989Sdes	}
12169990Sdes	s->s_size = length;
12269990Sdes	if (buf) {
12369990Sdes		s->s_buf = buf;
12477989Sdes		return (s);
12569990Sdes	}
12674840Sken	s->s_buf = (char *)SBMALLOC(s->s_size);
12777989Sdes	if (s->s_buf == NULL) {
12877989Sdes		if (SBUF_ISDYNSTRUCT(s))
12977989Sdes			SBFREE(s);
13077989Sdes		return (NULL);
13177989Sdes	}
13269990Sdes	SBUF_SETFLAG(s, SBUF_DYNAMIC);
13377989Sdes	return (s);
13469990Sdes}
13569990Sdes
13669990Sdes/*
13771721Sdes * Clear an sbuf and reset its position
13871721Sdes */
13971721Sdesvoid
14071721Sdessbuf_clear(struct sbuf *s)
14171721Sdes{
14271721Sdes	assert_sbuf_integrity(s);
14371724Sdes	/* don't care if it's finished or not */
14471721Sdes
14571721Sdes	SBUF_CLEARFLAG(s, SBUF_FINISHED);
14671721Sdes	SBUF_CLEARFLAG(s, SBUF_OVERFLOWED);
14771721Sdes	s->s_len = 0;
14871721Sdes}
14971721Sdes
15071721Sdes/*
15169990Sdes * Set the sbuf's position to an arbitrary value
15269990Sdes */
15369990Sdesint
15471721Sdessbuf_setpos(struct sbuf *s, int pos)
15569990Sdes{
15669990Sdes	assert_sbuf_integrity(s);
15769990Sdes	assert_sbuf_state(s, 0);
15869990Sdes
15969990Sdes	KASSERT(pos >= 0,
16069990Sdes	    ("attempt to seek to a negative position (%d)", pos));
16169990Sdes	KASSERT(pos < s->s_size,
16269990Sdes	    ("attempt to seek past end of sbuf (%d >= %d)", pos, s->s_size));
16369990Sdes
16469990Sdes	if (pos < 0 || pos > s->s_len)
16569990Sdes		return (-1);
16669990Sdes	s->s_len = pos;
16769990Sdes	return (0);
16869990Sdes}
16969990Sdes
17069990Sdes/*
17178077Sdes * Append a byte string to an sbuf.
17278077Sdes */
17378077Sdesint
17478077Sdessbuf_bcat(struct sbuf *s, const char *str, size_t len)
17578077Sdes{
17678077Sdes	assert_sbuf_integrity(s);
17778077Sdes	assert_sbuf_state(s, 0);
17878077Sdes
17978077Sdes	if (SBUF_HASOVERFLOWED(s))
18078077Sdes		return (-1);
18178077Sdes
18278077Sdes	while (len-- && SBUF_HASROOM(s))
18378077Sdes		s->s_buf[s->s_len++] = *str++;
18478077Sdes	if (len) {
18578077Sdes		SBUF_SETFLAG(s, SBUF_OVERFLOWED);
18678077Sdes		return (-1);
18778077Sdes	}
18878077Sdes	return (0);
18978077Sdes}
19078077Sdes
19178077Sdes#ifdef _KERNEL
19278077Sdes/*
19378077Sdes * Copy a byte string from userland into an sbuf.
19478077Sdes */
19578077Sdesint
19678077Sdessbuf_bcopyin(struct sbuf *s, const void *uaddr, size_t len)
19778077Sdes{
19878077Sdes	assert_sbuf_integrity(s);
19978077Sdes	assert_sbuf_state(s, 0);
20078077Sdes
20178077Sdes	if (SBUF_HASOVERFLOWED(s))
20278077Sdes		return (-1);
20378077Sdes
20478077Sdes	if (len == 0)
20578077Sdes		return (0);
20678077Sdes	if (len > (s->s_size - s->s_len - 1))
20778077Sdes		len = s->s_size - s->s_len - 1;
20878092Sdes	if (copyin(uaddr, s->s_buf + s->s_len, len) != 0)
20978092Sdes		return (-1);
21078095Sdes	s->s_len += len;
21178077Sdes
21278077Sdes	return (0);
21378077Sdes}
21478077Sdes#endif
21578077Sdes
21678077Sdes/*
21778077Sdes * Copy a byte string into an sbuf.
21878077Sdes */
21978077Sdesint
22078077Sdessbuf_bcpy(struct sbuf *s, const char *str, size_t len)
22178077Sdes{
22278077Sdes	assert_sbuf_integrity(s);
22378077Sdes	assert_sbuf_state(s, 0);
22478077Sdes
22578077Sdes	sbuf_clear(s);
22678077Sdes	return (sbuf_bcat(s, str, len));
22778077Sdes}
22878077Sdes
22978077Sdes/*
23069990Sdes * Append a string to an sbuf.
23169990Sdes */
23269990Sdesint
23374840Skensbuf_cat(struct sbuf *s, const char *str)
23469990Sdes{
23569990Sdes	assert_sbuf_integrity(s);
23669990Sdes	assert_sbuf_state(s, 0);
23769990Sdes
23869990Sdes	if (SBUF_HASOVERFLOWED(s))
23969990Sdes		return (-1);
24069990Sdes
24169990Sdes	while (*str && SBUF_HASROOM(s))
24269990Sdes		s->s_buf[s->s_len++] = *str++;
24369990Sdes	if (*str) {
24469990Sdes		SBUF_SETFLAG(s, SBUF_OVERFLOWED);
24569990Sdes		return (-1);
24669990Sdes	}
24769990Sdes	return (0);
24869990Sdes}
24969990Sdes
25078077Sdes#ifdef _KERNEL
25169990Sdes/*
25278077Sdes * Copy a string from userland into an sbuf.
25378077Sdes */
25478077Sdesint
25578077Sdessbuf_copyin(struct sbuf *s, const void *uaddr, size_t len)
25678077Sdes{
25778077Sdes	size_t done;
25878077Sdes
25978077Sdes	assert_sbuf_integrity(s);
26078077Sdes	assert_sbuf_state(s, 0);
26178077Sdes
26278077Sdes	if (SBUF_HASOVERFLOWED(s))
26378077Sdes		return (-1);
26478077Sdes
26578077Sdes	if (len == 0 || len > (s->s_size - s->s_len - 1))
26678077Sdes		len = s->s_size - s->s_len - 1;
26778077Sdes	switch (copyinstr(uaddr, s->s_buf + s->s_len, len + 1, &done)) {
26878077Sdes	case ENAMETOOLONG:
26978077Sdes		SBUF_SETFLAG(s, SBUF_OVERFLOWED);
27078077Sdes		/* fall through */
27178077Sdes	case 0:
27278077Sdes		s->s_len += done - 1;
27378077Sdes		break;
27478077Sdes	default:
27578077Sdes		return (-1);	/* XXX */
27678077Sdes	}
27778077Sdes
27878077Sdes	return (0);
27978077Sdes}
28078077Sdes#endif
28178077Sdes
28278077Sdes/*
28369990Sdes * Copy a string into an sbuf.
28469990Sdes */
28569990Sdesint
28674840Skensbuf_cpy(struct sbuf *s, const char *str)
28769990Sdes{
28869990Sdes	assert_sbuf_integrity(s);
28969990Sdes	assert_sbuf_state(s, 0);
29069990Sdes
29171721Sdes	sbuf_clear(s);
29269990Sdes	return (sbuf_cat(s, str));
29369990Sdes}
29469990Sdes
29569990Sdes/*
29669990Sdes * Format the given arguments and append the resulting string to an sbuf.
29769990Sdes */
29869990Sdesint
29979162Sdessbuf_printf(struct sbuf *s, const char *fmt, ...)
30069990Sdes{
30169990Sdes	va_list ap;
30271721Sdes	int len;
30369990Sdes
30469990Sdes	assert_sbuf_integrity(s);
30569990Sdes	assert_sbuf_state(s, 0);
30669990Sdes
30769990Sdes	KASSERT(fmt != NULL,
30869990Sdes	    (__FUNCTION__ " called with a NULL format string"));
30969990Sdes
31069990Sdes	if (SBUF_HASOVERFLOWED(s))
31169990Sdes		return (-1);
31269990Sdes
31369990Sdes	va_start(ap, fmt);
31474840Sken	len = vsnprintf(&s->s_buf[s->s_len], s->s_size - s->s_len, fmt, ap);
31569990Sdes	va_end(ap);
31669990Sdes
31774840Sken	/*
31874840Sken	 * s->s_len is the length of the string, without the terminating nul.
31974840Sken	 * When updating s->s_len, we must subtract 1 from the length that
32074840Sken	 * we passed into vsnprintf() because that length includes the
32174840Sken	 * terminating nul.
32274840Sken	 *
32374840Sken	 * vsnprintf() returns the amount that would have been copied,
32474840Sken	 * given sufficient space, hence the min() calculation below.
32574840Sken	 */
32674840Sken	s->s_len += min(len, s->s_size - s->s_len - 1);
32774840Sken	if (!SBUF_HASROOM(s))
32874840Sken		SBUF_SETFLAG(s, SBUF_OVERFLOWED);
32974840Sken
33069990Sdes	KASSERT(s->s_len < s->s_size,
33169990Sdes	    ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size));
33269990Sdes
33369990Sdes	if (SBUF_HASOVERFLOWED(s))
33469990Sdes		return (-1);
33569990Sdes	return (0);
33669990Sdes}
33769990Sdes
33869990Sdes/*
33969990Sdes * Append a character to an sbuf.
34069990Sdes */
34169990Sdesint
34269990Sdessbuf_putc(struct sbuf *s, int c)
34369990Sdes{
34469990Sdes	assert_sbuf_integrity(s);
34569990Sdes	assert_sbuf_state(s, 0);
34669990Sdes
34769990Sdes	if (SBUF_HASOVERFLOWED(s))
34869990Sdes		return (-1);
34969990Sdes
35069990Sdes	if (!SBUF_HASROOM(s)) {
35169990Sdes		SBUF_SETFLAG(s, SBUF_OVERFLOWED);
35269990Sdes		return (-1);
35369990Sdes	}
35473891Sdes	if (c != '\0')
35573891Sdes	    s->s_buf[s->s_len++] = c;
35669990Sdes	return (0);
35769990Sdes}
35869990Sdes
35969990Sdes/*
36071721Sdes * Check if an sbuf overflowed
36171721Sdes */
36271721Sdesint
36371721Sdessbuf_overflowed(struct sbuf *s)
36471721Sdes{
36571721Sdes    return SBUF_HASOVERFLOWED(s);
36671721Sdes}
36771721Sdes
36871721Sdes/*
36969990Sdes * Finish off an sbuf.
37069990Sdes */
37171721Sdesvoid
37269990Sdessbuf_finish(struct sbuf *s)
37369990Sdes{
37469990Sdes	assert_sbuf_integrity(s);
37569990Sdes	assert_sbuf_state(s, 0);
37669990Sdes
37773891Sdes	s->s_buf[s->s_len] = '\0';
37871721Sdes	SBUF_CLEARFLAG(s, SBUF_OVERFLOWED);
37969990Sdes	SBUF_SETFLAG(s, SBUF_FINISHED);
38069990Sdes}
38169990Sdes
38269990Sdes/*
38369990Sdes * Return a pointer to the sbuf data.
38469990Sdes */
38569990Sdeschar *
38669990Sdessbuf_data(struct sbuf *s)
38769990Sdes{
38869990Sdes	assert_sbuf_integrity(s);
38969990Sdes	assert_sbuf_state(s, SBUF_FINISHED);
39069990Sdes
39169990Sdes	return s->s_buf;
39269990Sdes}
39369990Sdes
39469990Sdes/*
39569990Sdes * Return the length of the sbuf data.
39669990Sdes */
39771721Sdesint
39869990Sdessbuf_len(struct sbuf *s)
39969990Sdes{
40069990Sdes	assert_sbuf_integrity(s);
40171724Sdes	/* don't care if it's finished or not */
40269990Sdes
40369990Sdes	if (SBUF_HASOVERFLOWED(s))
40471721Sdes		return (-1);
40569990Sdes	return s->s_len;
40669990Sdes}
40769990Sdes
40869990Sdes/*
40969990Sdes * Clear an sbuf, free its buffer if necessary.
41069990Sdes */
41169990Sdesvoid
41269990Sdessbuf_delete(struct sbuf *s)
41369990Sdes{
41469990Sdes	assert_sbuf_integrity(s);
41569990Sdes	/* don't care if it's finished or not */
41669990Sdes
41769990Sdes	if (SBUF_ISDYNAMIC(s))
41874840Sken		SBFREE(s->s_buf);
41969990Sdes	bzero(s, sizeof *s);
42077989Sdes	if (SBUF_ISDYNSTRUCT(s))
42177989Sdes		SBFREE(s);
42269990Sdes}
423