FreeBSD/Linux Kernel Cross Reference
sys/kern/subr_sbuf.c
1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2000-2008 Poul-Henning Kamp
5 * Copyright (c) 2000-2008 Dag-Erling Coïdan Smørgrav
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer
13 * in this position and unchanged.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD: releng/12.0/sys/kern/subr_sbuf.c 326271 2017-11-27 15:20:12Z pfg $");
33
34 #include <sys/param.h>
35
36 #ifdef _KERNEL
37 #include <sys/ctype.h>
38 #include <sys/errno.h>
39 #include <sys/kernel.h>
40 #include <sys/limits.h>
41 #include <sys/malloc.h>
42 #include <sys/systm.h>
43 #include <sys/uio.h>
44 #include <machine/stdarg.h>
45 #else /* _KERNEL */
46 #include <ctype.h>
47 #include <errno.h>
48 #include <limits.h>
49 #include <stdarg.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #endif /* _KERNEL */
54
55 #include <sys/sbuf.h>
56
57 #ifdef _KERNEL
58 static MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers");
59 #define SBMALLOC(size) malloc(size, M_SBUF, M_WAITOK|M_ZERO)
60 #define SBFREE(buf) free(buf, M_SBUF)
61 #else /* _KERNEL */
62 #define KASSERT(e, m)
63 #define SBMALLOC(size) calloc(1, size)
64 #define SBFREE(buf) free(buf)
65 #endif /* _KERNEL */
66
67 /*
68 * Predicates
69 */
70 #define SBUF_ISDYNAMIC(s) ((s)->s_flags & SBUF_DYNAMIC)
71 #define SBUF_ISDYNSTRUCT(s) ((s)->s_flags & SBUF_DYNSTRUCT)
72 #define SBUF_ISFINISHED(s) ((s)->s_flags & SBUF_FINISHED)
73 #define SBUF_HASROOM(s) ((s)->s_len < (s)->s_size - 1)
74 #define SBUF_FREESPACE(s) ((s)->s_size - ((s)->s_len + 1))
75 #define SBUF_CANEXTEND(s) ((s)->s_flags & SBUF_AUTOEXTEND)
76 #define SBUF_ISSECTION(s) ((s)->s_flags & SBUF_INSECTION)
77 #define SBUF_NULINCLUDED(s) ((s)->s_flags & SBUF_INCLUDENUL)
78 #define SBUF_ISDRAINTOEOR(s) ((s)->s_flags & SBUF_DRAINTOEOR)
79 #define SBUF_DODRAINTOEOR(s) (SBUF_ISSECTION(s) && SBUF_ISDRAINTOEOR(s))
80
81 /*
82 * Set / clear flags
83 */
84 #define SBUF_SETFLAG(s, f) do { (s)->s_flags |= (f); } while (0)
85 #define SBUF_CLEARFLAG(s, f) do { (s)->s_flags &= ~(f); } while (0)
86
87 #define SBUF_MINSIZE 2 /* Min is 1 byte + nulterm. */
88 #define SBUF_MINEXTENDSIZE 16 /* Should be power of 2. */
89
90 #ifdef PAGE_SIZE
91 #define SBUF_MAXEXTENDSIZE PAGE_SIZE
92 #define SBUF_MAXEXTENDINCR PAGE_SIZE
93 #else
94 #define SBUF_MAXEXTENDSIZE 4096
95 #define SBUF_MAXEXTENDINCR 4096
96 #endif
97
98 /*
99 * Debugging support
100 */
101 #if defined(_KERNEL) && defined(INVARIANTS)
102
103 static void
104 _assert_sbuf_integrity(const char *fun, struct sbuf *s)
105 {
106
107 KASSERT(s != NULL,
108 ("%s called with a NULL sbuf pointer", fun));
109 KASSERT(s->s_buf != NULL,
110 ("%s called with uninitialized or corrupt sbuf", fun));
111 if (SBUF_ISFINISHED(s) && SBUF_NULINCLUDED(s)) {
112 KASSERT(s->s_len <= s->s_size,
113 ("wrote past end of sbuf (%jd >= %jd)",
114 (intmax_t)s->s_len, (intmax_t)s->s_size));
115 } else {
116 KASSERT(s->s_len < s->s_size,
117 ("wrote past end of sbuf (%jd >= %jd)",
118 (intmax_t)s->s_len, (intmax_t)s->s_size));
119 }
120 }
121
122 static void
123 _assert_sbuf_state(const char *fun, struct sbuf *s, int state)
124 {
125
126 KASSERT((s->s_flags & SBUF_FINISHED) == state,
127 ("%s called with %sfinished or corrupt sbuf", fun,
128 (state ? "un" : "")));
129 }
130
131 #define assert_sbuf_integrity(s) _assert_sbuf_integrity(__func__, (s))
132 #define assert_sbuf_state(s, i) _assert_sbuf_state(__func__, (s), (i))
133
134 #else /* _KERNEL && INVARIANTS */
135
136 #define assert_sbuf_integrity(s) do { } while (0)
137 #define assert_sbuf_state(s, i) do { } while (0)
138
139 #endif /* _KERNEL && INVARIANTS */
140
141 #ifdef CTASSERT
142 CTASSERT(powerof2(SBUF_MAXEXTENDSIZE));
143 CTASSERT(powerof2(SBUF_MAXEXTENDINCR));
144 #endif
145
146 static int
147 sbuf_extendsize(int size)
148 {
149 int newsize;
150
151 if (size < (int)SBUF_MAXEXTENDSIZE) {
152 newsize = SBUF_MINEXTENDSIZE;
153 while (newsize < size)
154 newsize *= 2;
155 } else {
156 newsize = roundup2(size, SBUF_MAXEXTENDINCR);
157 }
158 KASSERT(newsize >= size, ("%s: %d < %d\n", __func__, newsize, size));
159 return (newsize);
160 }
161
162 /*
163 * Extend an sbuf.
164 */
165 static int
166 sbuf_extend(struct sbuf *s, int addlen)
167 {
168 char *newbuf;
169 int newsize;
170
171 if (!SBUF_CANEXTEND(s))
172 return (-1);
173 newsize = sbuf_extendsize(s->s_size + addlen);
174 newbuf = SBMALLOC(newsize);
175 if (newbuf == NULL)
176 return (-1);
177 memcpy(newbuf, s->s_buf, s->s_size);
178 if (SBUF_ISDYNAMIC(s))
179 SBFREE(s->s_buf);
180 else
181 SBUF_SETFLAG(s, SBUF_DYNAMIC);
182 s->s_buf = newbuf;
183 s->s_size = newsize;
184 return (0);
185 }
186
187 /*
188 * Initialize the internals of an sbuf.
189 * If buf is non-NULL, it points to a static or already-allocated string
190 * big enough to hold at least length characters.
191 */
192 static struct sbuf *
193 sbuf_newbuf(struct sbuf *s, char *buf, int length, int flags)
194 {
195
196 memset(s, 0, sizeof(*s));
197 s->s_flags = flags;
198 s->s_size = length;
199 s->s_buf = buf;
200
201 if ((s->s_flags & SBUF_AUTOEXTEND) == 0) {
202 KASSERT(s->s_size >= SBUF_MINSIZE,
203 ("attempt to create an sbuf smaller than %d bytes",
204 SBUF_MINSIZE));
205 }
206
207 if (s->s_buf != NULL)
208 return (s);
209
210 if ((flags & SBUF_AUTOEXTEND) != 0)
211 s->s_size = sbuf_extendsize(s->s_size);
212
213 s->s_buf = SBMALLOC(s->s_size);
214 if (s->s_buf == NULL)
215 return (NULL);
216 SBUF_SETFLAG(s, SBUF_DYNAMIC);
217 return (s);
218 }
219
220 /*
221 * Initialize an sbuf.
222 * If buf is non-NULL, it points to a static or already-allocated string
223 * big enough to hold at least length characters.
224 */
225 struct sbuf *
226 sbuf_new(struct sbuf *s, char *buf, int length, int flags)
227 {
228
229 KASSERT(length >= 0,
230 ("attempt to create an sbuf of negative length (%d)", length));
231 KASSERT((flags & ~SBUF_USRFLAGMSK) == 0,
232 ("%s called with invalid flags", __func__));
233
234 flags &= SBUF_USRFLAGMSK;
235 if (s != NULL)
236 return (sbuf_newbuf(s, buf, length, flags));
237
238 s = SBMALLOC(sizeof(*s));
239 if (s == NULL)
240 return (NULL);
241 if (sbuf_newbuf(s, buf, length, flags) == NULL) {
242 SBFREE(s);
243 return (NULL);
244 }
245 SBUF_SETFLAG(s, SBUF_DYNSTRUCT);
246 return (s);
247 }
248
249 #ifdef _KERNEL
250 /*
251 * Create an sbuf with uio data
252 */
253 struct sbuf *
254 sbuf_uionew(struct sbuf *s, struct uio *uio, int *error)
255 {
256
257 KASSERT(uio != NULL,
258 ("%s called with NULL uio pointer", __func__));
259 KASSERT(error != NULL,
260 ("%s called with NULL error pointer", __func__));
261
262 s = sbuf_new(s, NULL, uio->uio_resid + 1, 0);
263 if (s == NULL) {
264 *error = ENOMEM;
265 return (NULL);
266 }
267 *error = uiomove(s->s_buf, uio->uio_resid, uio);
268 if (*error != 0) {
269 sbuf_delete(s);
270 return (NULL);
271 }
272 s->s_len = s->s_size - 1;
273 if (SBUF_ISSECTION(s))
274 s->s_sect_len = s->s_size - 1;
275 *error = 0;
276 return (s);
277 }
278 #endif
279
280 int
281 sbuf_get_flags(struct sbuf *s)
282 {
283
284 return (s->s_flags & SBUF_USRFLAGMSK);
285 }
286
287 void
288 sbuf_clear_flags(struct sbuf *s, int flags)
289 {
290
291 s->s_flags &= ~(flags & SBUF_USRFLAGMSK);
292 }
293
294 void
295 sbuf_set_flags(struct sbuf *s, int flags)
296 {
297
298
299 s->s_flags |= (flags & SBUF_USRFLAGMSK);
300 }
301
302 /*
303 * Clear an sbuf and reset its position.
304 */
305 void
306 sbuf_clear(struct sbuf *s)
307 {
308
309 assert_sbuf_integrity(s);
310 /* don't care if it's finished or not */
311
312 SBUF_CLEARFLAG(s, SBUF_FINISHED);
313 s->s_error = 0;
314 s->s_len = 0;
315 s->s_rec_off = 0;
316 s->s_sect_len = 0;
317 }
318
319 /*
320 * Set the sbuf's end position to an arbitrary value.
321 * Effectively truncates the sbuf at the new position.
322 */
323 int
324 sbuf_setpos(struct sbuf *s, ssize_t pos)
325 {
326
327 assert_sbuf_integrity(s);
328 assert_sbuf_state(s, 0);
329
330 KASSERT(pos >= 0,
331 ("attempt to seek to a negative position (%jd)", (intmax_t)pos));
332 KASSERT(pos < s->s_size,
333 ("attempt to seek past end of sbuf (%jd >= %jd)",
334 (intmax_t)pos, (intmax_t)s->s_size));
335 KASSERT(!SBUF_ISSECTION(s),
336 ("attempt to seek when in a section"));
337
338 if (pos < 0 || pos > s->s_len)
339 return (-1);
340 s->s_len = pos;
341 return (0);
342 }
343
344 /*
345 * Set up a drain function and argument on an sbuf to flush data to
346 * when the sbuf buffer overflows.
347 */
348 void
349 sbuf_set_drain(struct sbuf *s, sbuf_drain_func *func, void *ctx)
350 {
351
352 assert_sbuf_state(s, 0);
353 assert_sbuf_integrity(s);
354 KASSERT(func == s->s_drain_func || s->s_len == 0,
355 ("Cannot change drain to %p on non-empty sbuf %p", func, s));
356 s->s_drain_func = func;
357 s->s_drain_arg = ctx;
358 }
359
360 /*
361 * Call the drain and process the return.
362 */
363 static int
364 sbuf_drain(struct sbuf *s)
365 {
366 int len;
367
368 KASSERT(s->s_len > 0, ("Shouldn't drain empty sbuf %p", s));
369 KASSERT(s->s_error == 0, ("Called %s with error on %p", __func__, s));
370 if (SBUF_DODRAINTOEOR(s) && s->s_rec_off == 0)
371 return (s->s_error = EDEADLK);
372 len = s->s_drain_func(s->s_drain_arg, s->s_buf,
373 SBUF_DODRAINTOEOR(s) ? s->s_rec_off : s->s_len);
374 if (len <= 0) {
375 s->s_error = len ? -len : EDEADLK;
376 return (s->s_error);
377 }
378 KASSERT(len > 0 && len <= s->s_len,
379 ("Bad drain amount %d for sbuf %p", len, s));
380 s->s_len -= len;
381 s->s_rec_off -= len;
382 /*
383 * Fast path for the expected case where all the data was
384 * drained.
385 */
386 if (s->s_len == 0)
387 return (0);
388 /*
389 * Move the remaining characters to the beginning of the
390 * string.
391 */
392 memmove(s->s_buf, s->s_buf + len, s->s_len);
393 return (0);
394 }
395
396 /*
397 * Append bytes to an sbuf. This is the core function for appending
398 * to an sbuf and is the main place that deals with extending the
399 * buffer and marking overflow.
400 */
401 static void
402 sbuf_put_bytes(struct sbuf *s, const char *buf, size_t len)
403 {
404 size_t n;
405
406 assert_sbuf_integrity(s);
407 assert_sbuf_state(s, 0);
408
409 if (s->s_error != 0)
410 return;
411 while (len > 0) {
412 if (SBUF_FREESPACE(s) <= 0) {
413 /*
414 * If there is a drain, use it, otherwise extend the
415 * buffer.
416 */
417 if (s->s_drain_func != NULL)
418 (void)sbuf_drain(s);
419 else if (sbuf_extend(s, len > INT_MAX ? INT_MAX : len)
420 < 0)
421 s->s_error = ENOMEM;
422 if (s->s_error != 0)
423 return;
424 }
425 n = SBUF_FREESPACE(s);
426 if (len < n)
427 n = len;
428 memcpy(&s->s_buf[s->s_len], buf, n);
429 s->s_len += n;
430 if (SBUF_ISSECTION(s))
431 s->s_sect_len += n;
432 len -= n;
433 buf += n;
434 }
435 }
436
437 static void
438 sbuf_put_byte(struct sbuf *s, char c)
439 {
440
441 sbuf_put_bytes(s, &c, 1);
442 }
443
444 /*
445 * Append a byte string to an sbuf.
446 */
447 int
448 sbuf_bcat(struct sbuf *s, const void *buf, size_t len)
449 {
450
451 sbuf_put_bytes(s, buf, len);
452 if (s->s_error != 0)
453 return (-1);
454 return (0);
455 }
456
457 #ifdef _KERNEL
458 /*
459 * Copy a byte string from userland into an sbuf.
460 */
461 int
462 sbuf_bcopyin(struct sbuf *s, const void *uaddr, size_t len)
463 {
464
465 assert_sbuf_integrity(s);
466 assert_sbuf_state(s, 0);
467 KASSERT(s->s_drain_func == NULL,
468 ("Nonsensical copyin to sbuf %p with a drain", s));
469
470 if (s->s_error != 0)
471 return (-1);
472 if (len == 0)
473 return (0);
474 if (len > SBUF_FREESPACE(s)) {
475 sbuf_extend(s, len - SBUF_FREESPACE(s));
476 if (SBUF_FREESPACE(s) < len)
477 len = SBUF_FREESPACE(s);
478 }
479 if (copyin(uaddr, s->s_buf + s->s_len, len) != 0)
480 return (-1);
481 s->s_len += len;
482
483 return (0);
484 }
485 #endif
486
487 /*
488 * Copy a byte string into an sbuf.
489 */
490 int
491 sbuf_bcpy(struct sbuf *s, const void *buf, size_t len)
492 {
493
494 assert_sbuf_integrity(s);
495 assert_sbuf_state(s, 0);
496
497 sbuf_clear(s);
498 return (sbuf_bcat(s, buf, len));
499 }
500
501 /*
502 * Append a string to an sbuf.
503 */
504 int
505 sbuf_cat(struct sbuf *s, const char *str)
506 {
507 size_t n;
508
509 n = strlen(str);
510 sbuf_put_bytes(s, str, n);
511 if (s->s_error != 0)
512 return (-1);
513 return (0);
514 }
515
516 #ifdef _KERNEL
517 /*
518 * Append a string from userland to an sbuf.
519 */
520 int
521 sbuf_copyin(struct sbuf *s, const void *uaddr, size_t len)
522 {
523 size_t done;
524
525 assert_sbuf_integrity(s);
526 assert_sbuf_state(s, 0);
527 KASSERT(s->s_drain_func == NULL,
528 ("Nonsensical copyin to sbuf %p with a drain", s));
529
530 if (s->s_error != 0)
531 return (-1);
532
533 if (len == 0)
534 len = SBUF_FREESPACE(s); /* XXX return 0? */
535 if (len > SBUF_FREESPACE(s)) {
536 sbuf_extend(s, len);
537 if (SBUF_FREESPACE(s) < len)
538 len = SBUF_FREESPACE(s);
539 }
540 switch (copyinstr(uaddr, s->s_buf + s->s_len, len + 1, &done)) {
541 case ENAMETOOLONG:
542 s->s_error = ENOMEM;
543 /* fall through */
544 case 0:
545 s->s_len += done - 1;
546 if (SBUF_ISSECTION(s))
547 s->s_sect_len += done - 1;
548 break;
549 default:
550 return (-1); /* XXX */
551 }
552
553 return (done);
554 }
555 #endif
556
557 /*
558 * Copy a string into an sbuf.
559 */
560 int
561 sbuf_cpy(struct sbuf *s, const char *str)
562 {
563
564 assert_sbuf_integrity(s);
565 assert_sbuf_state(s, 0);
566
567 sbuf_clear(s);
568 return (sbuf_cat(s, str));
569 }
570
571 /*
572 * Format the given argument list and append the resulting string to an sbuf.
573 */
574 #ifdef _KERNEL
575
576 /*
577 * Append a non-NUL character to an sbuf. This prototype signature is
578 * suitable for use with kvprintf(9).
579 */
580 static void
581 sbuf_putc_func(int c, void *arg)
582 {
583
584 if (c != '\0')
585 sbuf_put_byte(arg, c);
586 }
587
588 int
589 sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap)
590 {
591
592 assert_sbuf_integrity(s);
593 assert_sbuf_state(s, 0);
594
595 KASSERT(fmt != NULL,
596 ("%s called with a NULL format string", __func__));
597
598 (void)kvprintf(fmt, sbuf_putc_func, s, 10, ap);
599 if (s->s_error != 0)
600 return (-1);
601 return (0);
602 }
603 #else /* !_KERNEL */
604 int
605 sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap)
606 {
607 va_list ap_copy;
608 int error, len;
609
610 assert_sbuf_integrity(s);
611 assert_sbuf_state(s, 0);
612
613 KASSERT(fmt != NULL,
614 ("%s called with a NULL format string", __func__));
615
616 if (s->s_error != 0)
617 return (-1);
618
619 /*
620 * For the moment, there is no way to get vsnprintf(3) to hand
621 * back a character at a time, to push everything into
622 * sbuf_putc_func() as was done for the kernel.
623 *
624 * In userspace, while drains are useful, there's generally
625 * not a problem attempting to malloc(3) on out of space. So
626 * expand a userland sbuf if there is not enough room for the
627 * data produced by sbuf_[v]printf(3).
628 */
629
630 error = 0;
631 do {
632 va_copy(ap_copy, ap);
633 len = vsnprintf(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1,
634 fmt, ap_copy);
635 if (len < 0) {
636 s->s_error = errno;
637 return (-1);
638 }
639 va_end(ap_copy);
640
641 if (SBUF_FREESPACE(s) >= len)
642 break;
643 /* Cannot print with the current available space. */
644 if (s->s_drain_func != NULL && s->s_len > 0)
645 error = sbuf_drain(s); /* sbuf_drain() sets s_error. */
646 else if (sbuf_extend(s, len - SBUF_FREESPACE(s)) != 0)
647 s->s_error = error = ENOMEM;
648 } while (error == 0);
649
650 /*
651 * s->s_len is the length of the string, without the terminating nul.
652 * When updating s->s_len, we must subtract 1 from the length that
653 * we passed into vsnprintf() because that length includes the
654 * terminating nul.
655 *
656 * vsnprintf() returns the amount that would have been copied,
657 * given sufficient space, so don't over-increment s_len.
658 */
659 if (SBUF_FREESPACE(s) < len)
660 len = SBUF_FREESPACE(s);
661 s->s_len += len;
662 if (SBUF_ISSECTION(s))
663 s->s_sect_len += len;
664
665 KASSERT(s->s_len < s->s_size,
666 ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size));
667
668 if (s->s_error != 0)
669 return (-1);
670 return (0);
671 }
672 #endif /* _KERNEL */
673
674 /*
675 * Format the given arguments and append the resulting string to an sbuf.
676 */
677 int
678 sbuf_printf(struct sbuf *s, const char *fmt, ...)
679 {
680 va_list ap;
681 int result;
682
683 va_start(ap, fmt);
684 result = sbuf_vprintf(s, fmt, ap);
685 va_end(ap);
686 return (result);
687 }
688
689 /*
690 * Append a character to an sbuf.
691 */
692 int
693 sbuf_putc(struct sbuf *s, int c)
694 {
695
696 sbuf_put_byte(s, c);
697 if (s->s_error != 0)
698 return (-1);
699 return (0);
700 }
701
702 /*
703 * Trim whitespace characters from end of an sbuf.
704 */
705 int
706 sbuf_trim(struct sbuf *s)
707 {
708
709 assert_sbuf_integrity(s);
710 assert_sbuf_state(s, 0);
711 KASSERT(s->s_drain_func == NULL,
712 ("%s makes no sense on sbuf %p with drain", __func__, s));
713
714 if (s->s_error != 0)
715 return (-1);
716
717 while (s->s_len > 0 && isspace(s->s_buf[s->s_len-1])) {
718 --s->s_len;
719 if (SBUF_ISSECTION(s))
720 s->s_sect_len--;
721 }
722
723 return (0);
724 }
725
726 /*
727 * Check if an sbuf has an error.
728 */
729 int
730 sbuf_error(const struct sbuf *s)
731 {
732
733 return (s->s_error);
734 }
735
736 /*
737 * Finish off an sbuf.
738 */
739 int
740 sbuf_finish(struct sbuf *s)
741 {
742
743 assert_sbuf_integrity(s);
744 assert_sbuf_state(s, 0);
745
746 s->s_buf[s->s_len] = '\0';
747 if (SBUF_NULINCLUDED(s))
748 s->s_len++;
749 if (s->s_drain_func != NULL) {
750 while (s->s_len > 0 && s->s_error == 0)
751 s->s_error = sbuf_drain(s);
752 }
753 SBUF_SETFLAG(s, SBUF_FINISHED);
754 #ifdef _KERNEL
755 return (s->s_error);
756 #else
757 if (s->s_error != 0) {
758 errno = s->s_error;
759 return (-1);
760 }
761 return (0);
762 #endif
763 }
764
765 /*
766 * Return a pointer to the sbuf data.
767 */
768 char *
769 sbuf_data(struct sbuf *s)
770 {
771
772 assert_sbuf_integrity(s);
773 assert_sbuf_state(s, SBUF_FINISHED);
774 KASSERT(s->s_drain_func == NULL,
775 ("%s makes no sense on sbuf %p with drain", __func__, s));
776
777 return (s->s_buf);
778 }
779
780 /*
781 * Return the length of the sbuf data.
782 */
783 ssize_t
784 sbuf_len(struct sbuf *s)
785 {
786
787 assert_sbuf_integrity(s);
788 /* don't care if it's finished or not */
789 KASSERT(s->s_drain_func == NULL,
790 ("%s makes no sense on sbuf %p with drain", __func__, s));
791
792 if (s->s_error != 0)
793 return (-1);
794
795 /* If finished, nulterm is already in len, else add one. */
796 if (SBUF_NULINCLUDED(s) && !SBUF_ISFINISHED(s))
797 return (s->s_len + 1);
798 return (s->s_len);
799 }
800
801 /*
802 * Clear an sbuf, free its buffer if necessary.
803 */
804 void
805 sbuf_delete(struct sbuf *s)
806 {
807 int isdyn;
808
809 assert_sbuf_integrity(s);
810 /* don't care if it's finished or not */
811
812 if (SBUF_ISDYNAMIC(s))
813 SBFREE(s->s_buf);
814 isdyn = SBUF_ISDYNSTRUCT(s);
815 memset(s, 0, sizeof(*s));
816 if (isdyn)
817 SBFREE(s);
818 }
819
820 /*
821 * Check if an sbuf has been finished.
822 */
823 int
824 sbuf_done(const struct sbuf *s)
825 {
826
827 return (SBUF_ISFINISHED(s));
828 }
829
830 /*
831 * Start a section.
832 */
833 void
834 sbuf_start_section(struct sbuf *s, ssize_t *old_lenp)
835 {
836
837 assert_sbuf_integrity(s);
838 assert_sbuf_state(s, 0);
839
840 if (!SBUF_ISSECTION(s)) {
841 KASSERT(s->s_sect_len == 0,
842 ("s_sect_len != 0 when starting a section"));
843 if (old_lenp != NULL)
844 *old_lenp = -1;
845 s->s_rec_off = s->s_len;
846 SBUF_SETFLAG(s, SBUF_INSECTION);
847 } else {
848 KASSERT(old_lenp != NULL,
849 ("s_sect_len should be saved when starting a subsection"));
850 *old_lenp = s->s_sect_len;
851 s->s_sect_len = 0;
852 }
853 }
854
855 /*
856 * End the section padding to the specified length with the specified
857 * character.
858 */
859 ssize_t
860 sbuf_end_section(struct sbuf *s, ssize_t old_len, size_t pad, int c)
861 {
862 ssize_t len;
863
864 assert_sbuf_integrity(s);
865 assert_sbuf_state(s, 0);
866 KASSERT(SBUF_ISSECTION(s),
867 ("attempt to end a section when not in a section"));
868
869 if (pad > 1) {
870 len = roundup(s->s_sect_len, pad) - s->s_sect_len;
871 for (; s->s_error == 0 && len > 0; len--)
872 sbuf_put_byte(s, c);
873 }
874 len = s->s_sect_len;
875 if (old_len == -1) {
876 s->s_rec_off = s->s_sect_len = 0;
877 SBUF_CLEARFLAG(s, SBUF_INSECTION);
878 } else {
879 s->s_sect_len += old_len;
880 }
881 if (s->s_error != 0)
882 return (-1);
883 return (len);
884 }
Cache object: f32e9e76b84bd0a218a7660301616aaf
|