subr_sbuf.c revision 212184
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 212184 2010-09-03 17:42:17Z 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 string to an sbuf.
276 */
277int
278sbuf_bcat(struct sbuf *s, const void *buf, size_t len)
279{
280	const char *str = buf;
281
282	assert_sbuf_integrity(s);
283	assert_sbuf_state(s, 0);
284
285	if (SBUF_HASOVERFLOWED(s))
286		return (-1);
287	for (; len; len--) {
288		if (!SBUF_HASROOM(s) && sbuf_extend(s, len) < 0)
289			break;
290		s->s_buf[s->s_len++] = *str++;
291	}
292	if (len > 0) {
293		SBUF_SETFLAG(s, SBUF_OVERFLOWED);
294		return (-1);
295	}
296	return (0);
297}
298
299#ifdef _KERNEL
300/*
301 * Copy a byte string from userland into an sbuf.
302 */
303int
304sbuf_bcopyin(struct sbuf *s, const void *uaddr, size_t len)
305{
306
307	assert_sbuf_integrity(s);
308	assert_sbuf_state(s, 0);
309
310	if (SBUF_HASOVERFLOWED(s))
311		return (-1);
312	if (len == 0)
313		return (0);
314	if (len > SBUF_FREESPACE(s)) {
315		sbuf_extend(s, len - SBUF_FREESPACE(s));
316		if (SBUF_FREESPACE(s) < len)
317			len = SBUF_FREESPACE(s);
318	}
319	if (copyin(uaddr, s->s_buf + s->s_len, len) != 0)
320		return (-1);
321	s->s_len += len;
322
323	return (0);
324}
325#endif
326
327/*
328 * Copy a byte string into an sbuf.
329 */
330int
331sbuf_bcpy(struct sbuf *s, const void *buf, size_t len)
332{
333
334	assert_sbuf_integrity(s);
335	assert_sbuf_state(s, 0);
336
337	sbuf_clear(s);
338	return (sbuf_bcat(s, buf, len));
339}
340
341/*
342 * Append a string to an sbuf.
343 */
344int
345sbuf_cat(struct sbuf *s, const char *str)
346{
347
348	assert_sbuf_integrity(s);
349	assert_sbuf_state(s, 0);
350
351	if (SBUF_HASOVERFLOWED(s))
352		return (-1);
353
354	while (*str != '\0') {
355		if (!SBUF_HASROOM(s) && sbuf_extend(s, strlen(str)) < 0)
356			break;
357		s->s_buf[s->s_len++] = *str++;
358	}
359	if (*str != '\0') {
360		SBUF_SETFLAG(s, SBUF_OVERFLOWED);
361		return (-1);
362	}
363	return (0);
364}
365
366#ifdef _KERNEL
367/*
368 * Append a string from userland to an sbuf.
369 */
370int
371sbuf_copyin(struct sbuf *s, const void *uaddr, size_t len)
372{
373	size_t done;
374
375	assert_sbuf_integrity(s);
376	assert_sbuf_state(s, 0);
377
378	if (SBUF_HASOVERFLOWED(s))
379		return (-1);
380
381	if (len == 0)
382		len = SBUF_FREESPACE(s);	/* XXX return 0? */
383	if (len > SBUF_FREESPACE(s)) {
384		sbuf_extend(s, len);
385		if (SBUF_FREESPACE(s) < len)
386			len = SBUF_FREESPACE(s);
387	}
388	switch (copyinstr(uaddr, s->s_buf + s->s_len, len + 1, &done)) {
389	case ENAMETOOLONG:
390		SBUF_SETFLAG(s, SBUF_OVERFLOWED);
391		/* fall through */
392	case 0:
393		s->s_len += done - 1;
394		break;
395	default:
396		return (-1);	/* XXX */
397	}
398
399	return (done);
400}
401#endif
402
403/*
404 * Copy a string into an sbuf.
405 */
406int
407sbuf_cpy(struct sbuf *s, const char *str)
408{
409
410	assert_sbuf_integrity(s);
411	assert_sbuf_state(s, 0);
412
413	sbuf_clear(s);
414	return (sbuf_cat(s, str));
415}
416
417/*
418 * Format the given argument list and append the resulting string to an sbuf.
419 */
420int
421sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap)
422{
423	va_list ap_copy;
424	int len;
425
426	assert_sbuf_integrity(s);
427	assert_sbuf_state(s, 0);
428
429	KASSERT(fmt != NULL,
430	    ("%s called with a NULL format string", __func__));
431
432	if (SBUF_HASOVERFLOWED(s))
433		return (-1);
434
435	do {
436		va_copy(ap_copy, ap);
437		len = vsnprintf(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1,
438		    fmt, ap_copy);
439		va_end(ap_copy);
440	} while (len > SBUF_FREESPACE(s) &&
441	    sbuf_extend(s, len - SBUF_FREESPACE(s)) == 0);
442
443	/*
444	 * s->s_len is the length of the string, without the terminating nul.
445	 * When updating s->s_len, we must subtract 1 from the length that
446	 * we passed into vsnprintf() because that length includes the
447	 * terminating nul.
448	 *
449	 * vsnprintf() returns the amount that would have been copied,
450	 * given sufficient space, so don't over-increment s_len.
451	 */
452	if (SBUF_FREESPACE(s) < len)
453		len = SBUF_FREESPACE(s);
454	s->s_len += len;
455	if (!SBUF_HASROOM(s) && !SBUF_CANEXTEND(s))
456		SBUF_SETFLAG(s, SBUF_OVERFLOWED);
457
458	KASSERT(s->s_len < s->s_size,
459	    ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size));
460
461	if (SBUF_HASOVERFLOWED(s))
462		return (-1);
463	return (0);
464}
465
466/*
467 * Format the given arguments and append the resulting string to an sbuf.
468 */
469int
470sbuf_printf(struct sbuf *s, const char *fmt, ...)
471{
472	va_list ap;
473	int result;
474
475	va_start(ap, fmt);
476	result = sbuf_vprintf(s, fmt, ap);
477	va_end(ap);
478	return (result);
479}
480
481/*
482 * Append a character to an sbuf.
483 */
484int
485sbuf_putc(struct sbuf *s, int c)
486{
487
488	assert_sbuf_integrity(s);
489	assert_sbuf_state(s, 0);
490
491	if (SBUF_HASOVERFLOWED(s))
492		return (-1);
493	if (!SBUF_HASROOM(s) && sbuf_extend(s, 1) < 0) {
494		SBUF_SETFLAG(s, SBUF_OVERFLOWED);
495		return (-1);
496	}
497	if (c != '\0')
498		s->s_buf[s->s_len++] = c;
499	return (0);
500}
501
502/*
503 * Trim whitespace characters from end of an sbuf.
504 */
505int
506sbuf_trim(struct sbuf *s)
507{
508
509	assert_sbuf_integrity(s);
510	assert_sbuf_state(s, 0);
511
512	if (SBUF_HASOVERFLOWED(s))
513		return (-1);
514
515	while (s->s_len > 0 && isspace(s->s_buf[s->s_len-1]))
516		--s->s_len;
517
518	return (0);
519}
520
521/*
522 * Check if an sbuf overflowed
523 */
524int
525sbuf_overflowed(struct sbuf *s)
526{
527
528	return (SBUF_HASOVERFLOWED(s));
529}
530
531/*
532 * Finish off an sbuf.
533 */
534void
535sbuf_finish(struct sbuf *s)
536{
537
538	assert_sbuf_integrity(s);
539	assert_sbuf_state(s, 0);
540
541	s->s_buf[s->s_len] = '\0';
542	SBUF_CLEARFLAG(s, SBUF_OVERFLOWED);
543	SBUF_SETFLAG(s, SBUF_FINISHED);
544}
545
546/*
547 * Return a pointer to the sbuf data.
548 */
549char *
550sbuf_data(struct sbuf *s)
551{
552
553	assert_sbuf_integrity(s);
554	assert_sbuf_state(s, SBUF_FINISHED);
555
556	return (s->s_buf);
557}
558
559/*
560 * Return the length of the sbuf data.
561 */
562int
563sbuf_len(struct sbuf *s)
564{
565
566	assert_sbuf_integrity(s);
567	/* don't care if it's finished or not */
568
569	if (SBUF_HASOVERFLOWED(s))
570		return (-1);
571	return (s->s_len);
572}
573
574/*
575 * Clear an sbuf, free its buffer if necessary.
576 */
577void
578sbuf_delete(struct sbuf *s)
579{
580	int isdyn;
581
582	assert_sbuf_integrity(s);
583	/* don't care if it's finished or not */
584
585	if (SBUF_ISDYNAMIC(s))
586		SBFREE(s->s_buf);
587	isdyn = SBUF_ISDYNSTRUCT(s);
588	bzero(s, sizeof(*s));
589	if (isdyn)
590		SBFREE(s);
591}
592
593/*
594 * Check if an sbuf has been finished.
595 */
596int
597sbuf_done(struct sbuf *s)
598{
599
600	return (SBUF_ISFINISHED(s));
601}
602