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