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