1 // SPDX-License-Identifier: (BSD-2-Clause AND BSD-3-Clause)
2 /*
3  * Imported from NetBSD 5.1 with modifications to make it a vsnprintf(3)
4  * function
5  */
6 
7 /*	$NetBSD: subr_prf.c,v 1.156 2014/08/15 11:05:35 apb Exp $	*/
8 
9 /*-
10  * Copyright (c) 1986, 1988, 1991, 1993
11  *	The Regents of the University of California.  All rights reserved.
12  * (c) UNIX System Laboratories, Inc.
13  * All or some portions of this file are derived from material licensed
14  * to the University of California by American Telephone and Telegraph
15  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
16  * the permission of UNIX System Laboratories, Inc.
17  *
18  * Redistribution and use in source and binary forms, with or without
19  * modification, are permitted provided that the following conditions
20  * are met:
21  * 1. Redistributions of source code must retain the above copyright
22  *    notice, this list of conditions and the following disclaimer.
23  * 2. Redistributions in binary form must reproduce the above copyright
24  *    notice, this list of conditions and the following disclaimer in the
25  *    documentation and/or other materials provided with the distribution.
26  * 3. Neither the name of the University nor the names of its contributors
27  *    may be used to endorse or promote products derived from this software
28  *    without specific prior written permission.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40  * SUCH DAMAGE.
41  *
42  *	@(#)subr_prf.c	8.4 (Berkeley) 5/4/95
43  *
44  * Copyright (c) 2015 Linaro Limited
45  * All rights reserved.
46  *
47  * Redistribution and use in source and binary forms, with or without
48  * modification, are permitted provided that the following conditions are met:
49  *
50  * 1. Redistributions of source code must retain the above copyright notice,
51  * this list of conditions and the following disclaimer.
52  *
53  * 2. Redistributions in binary form must reproduce the above copyright notice,
54  * this list of conditions and the following disclaimer in the documentation
55  * and/or other materials provided with the distribution.
56  *
57  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
58  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
61  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
62  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
63  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
64  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
65  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
66  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
67  * POSSIBILITY OF SUCH DAMAGE.
68  */
69 #include <compiler.h>
70 #include <unistd.h>
71 #include <stdint.h>
72 #include <string.h>
73 #include <stdarg.h>
74 #include <printk.h>
75 
76 /* flags for kprintf */
77 #define TOCONS        0x0001	/* to the console */
78 #define TOTTY        0x0002	/* to the process' tty */
79 #define TOLOG        0x0004	/* to the kernel message buffer */
80 #define TOBUFONLY    0x0008	/* to the buffer (only) [for snprintk] */
81 #define TODDB        0x0010	/* to ddb console */
82 #define NOLOCK        0x1000	/* don't acquire a tty lock */
83 
84 /* max size buffer kprintf needs to print a UUID */
85 #define KPRINTF_BUFSIZE        37
86 
87 /*
88  * The following macro is used to remove const cast-away warnings
89  * from gcc -Wcast-qual; it should be used with caution because it
90  * can hide valid errors; in particular most valid uses are in
91  * situations where the API requires it, not to cast away string
92  * constants. We don't use *intptr_t on purpose here and we are
93  * explicit about unsigned long so that we don't have additional
94  * dependencies.
95  */
96 #define __UNCONST(a)    ((void *)(unsigned long)(const void *)(a))
97 
98 #define putchar(c, flags, tty) \
99 	do { (void)(c); (void)(flags); (void)(tty); } while(0)
100 
101 static int kprintf(const char *fmt0, int oflags, void *vp, char *sbuf,
102 		   va_list ap, bool ext);
103 
104 static const char hexdigits[] = "0123456789abcdef";
105 static const char HEXDIGITS[] = "0123456789ABCDEF";
106 
107 /*
108  * snprintk: print a message to a buffer. Same as snprintf but supports
109  * format extensions.
110  */
111 int
snprintk(char * bf,size_t size,const char * fmt,...)112 snprintk(char *bf, size_t size, const char *fmt, ...)
113 {
114 	int retval;
115 	va_list ap;
116 
117 	va_start(ap, fmt);
118 	retval = vsnprintk(bf, size, fmt, ap);
119 	va_end(ap);
120 
121 	return retval;
122 }
123 
124 /*
125  * vsnprintk: print a message to a buffer [already have va_list]
126  * Same as vsnprintf but supports format extensions.
127  */
128 int
vsnprintk(char * bf,size_t size,const char * fmt,va_list ap)129 vsnprintk(char *bf, size_t size, const char *fmt, va_list ap)
130 {
131 	return __vsnprintf(bf, size, fmt, ap, true);
132 }
133 
134 int
__vsnprintf(char * bf,size_t size,const char * fmt,va_list ap,bool ext)135 __vsnprintf(char *bf, size_t size, const char *fmt, va_list ap,
136 	    bool ext)
137 
138 {
139 	int retval;
140 	char *p;
141 
142 	p = bf + size;
143 	retval = kprintf(fmt, TOBUFONLY, &p, bf, ap, ext);
144 	if (bf && size > 0) {
145 		/* nul terminate */
146 		if (size <= (size_t)retval)
147 			bf[size - 1] = '\0';
148 		else
149 			bf[retval] = '\0';
150 	}
151 	return retval;
152 }
153 
__vsprintf(char * bf,const char * fmt,va_list ap)154 int __vsprintf(char *bf, const char *fmt, va_list ap)
155 {
156 	return kprintf(fmt, TOBUFONLY, NULL, bf, ap, false);
157 }
158 
159 /*
160  * kprintf: scaled down version of printf(3).
161  *
162  * this version based on vfprintf() from libc which was derived from
163  * software contributed to Berkeley by Chris Torek.
164  *
165  */
166 
167 /*
168  * macros for converting digits to letters and vice versa
169  */
170 #define	to_digit(c)	((c) - '0')
171 #define is_digit(c)	((unsigned)to_digit(c) <= 9)
172 #define	to_char(n)	((n) + '0')
173 
174 /*
175  * flags used during conversion.
176  */
177 #define	ALT		0x001		/* alternate form */
178 #define	HEXPREFIX	0x002		/* add 0x or 0X prefix */
179 #define	LADJUST		0x004		/* left adjustment */
180 #define	LONGDBL		0x008		/* long double; unimplemented */
181 #define	LONGINT		0x010		/* long integer */
182 #define	QUADINT		0x020		/* quad integer */
183 #define	SHORTINT	0x040		/* short integer */
184 #define	MAXINT		0x080		/* intmax_t */
185 #define	PTRINT		0x100		/* intptr_t */
186 #define	SIZEINT		0x200		/* size_t */
187 #define	ZEROPAD		0x400		/* zero (as opposed to blank) pad */
188 #define FPT		0x800		/* Floating point number */
189 
190 	/*
191 	 * To extend shorts properly, we need both signed and unsigned
192 	 * argument extraction methods.
193 	 */
194 #define	SARG() \
195 	(flags&MAXINT ? va_arg(ap, intmax_t) : \
196 	    flags&PTRINT ? va_arg(ap, intptr_t) : \
197 	    flags&SIZEINT ? va_arg(ap, ssize_t) : /* XXX */ \
198 	    flags&QUADINT ? va_arg(ap, int64_t) : \
199 	    flags&LONGINT ? va_arg(ap, long) : \
200 	    flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
201 	    (long)va_arg(ap, int))
202 #define	UARG() \
203 	(flags&MAXINT ? va_arg(ap, uintmax_t) : \
204 	    flags&PTRINT ? va_arg(ap, uintptr_t) : \
205 	    flags&SIZEINT ? va_arg(ap, size_t) : \
206 	    flags&QUADINT ? va_arg(ap, uint64_t) : \
207 	    flags&LONGINT ? va_arg(ap, unsigned long) : \
208 	    flags&SHORTINT ? (unsigned long)(unsigned short)va_arg(ap, int) : \
209 	    (unsigned long)va_arg(ap, unsigned int))
210 
211 #define KPRINTF_PUTCHAR(C) {						\
212 	if (oflags == TOBUFONLY) {					\
213 		if (sbuf && ((vp == NULL) || (sbuf < tailp))) 		\
214 			*sbuf++ = (C);					\
215 	} else {							\
216 		putchar((C), oflags, vp);				\
217 	}								\
218 }
219 
uuid2str(char * dst,size_t size,void * ptr)220 static int uuid2str(char *dst, size_t size, void *ptr)
221 {
222 	struct {
223 		uint32_t lo;
224 		uint16_t mid;
225 		uint16_t hi_ver;
226 		uint8_t seq_n[8];
227 	} *uuid = ptr;
228 
229 	return snprintk(dst, size,
230 			"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
231 			uuid->lo, uuid->mid, uuid->hi_ver,
232 			uuid->seq_n[0], uuid->seq_n[1],
233 			uuid->seq_n[2],	uuid->seq_n[3],
234 			uuid->seq_n[4],	uuid->seq_n[5],
235 			uuid->seq_n[6],	uuid->seq_n[7]);
236 }
237 
238 /*
239  * Guts of kernel printf.  Note, we already expect to be in a mutex!
240  */
241 static int
kprintf(const char * fmt0,int oflags,void * vp,char * sbuf,va_list ap,bool ext)242 kprintf(const char *fmt0, int oflags, void *vp, char *sbuf, va_list ap,
243 	bool ext)
244 {
245 	const char *fmt;	/* format string */
246 	int ch;			/* character from fmt */
247 	int n;			/* handy integer (short term usage) */
248 	char *cp;		/* handy char pointer (short term usage) */
249 	int flags;		/* flags as above */
250 	int ret;		/* return value accumulator */
251 	int width;		/* width from format (%8d), or 0 */
252 	int prec;		/* precision from format (%.3d), or -1 */
253 	char sign;		/* sign prefix (' ', '+', '-', or \0) */
254 
255 	uint64_t _uquad;	/* integer arguments %[diouxX] */
256 	enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
257 	int dprec;		/* a copy of prec if [diouxX], 0 otherwise */
258 	int realsz;		/* field size expanded by dprec */
259 	int size;		/* size of converted field or string */
260 	const char *xdigs;	/* digits for [xX] conversion */
261 	char bf[KPRINTF_BUFSIZE]; /* space for %c, %[diouxX], possibly %pUl */
262 	char *tailp;		/* tail pointer for snprintk */
263 
264 	if (oflags == TOBUFONLY && (vp != NULL))
265 		tailp = *(char **)vp;
266 	else
267 		tailp = NULL;
268 
269 	cp = NULL;	/* XXX: shutup gcc */
270 	size = 0;	/* XXX: shutup gcc */
271 
272 	fmt = fmt0;
273 	ret = 0;
274 
275 	xdigs = NULL;		/* XXX: shut up gcc warning */
276 
277 	/*
278 	 * Scan the format for conversions (`%' character).
279 	 */
280 	for (;;) {
281 		for (; *fmt != '%' && *fmt; fmt++) {
282 			ret++;
283 			KPRINTF_PUTCHAR(*fmt);
284 		}
285 		if (*fmt == 0)
286 			goto done;
287 
288 		fmt++;		/* skip over '%' */
289 
290 		flags = 0;
291 		dprec = 0;
292 		width = 0;
293 		prec = -1;
294 		sign = '\0';
295 
296 rflag:		ch = *fmt++;
297 reswitch:	switch (ch) {
298 		case ' ':
299 			/*
300 			 * ``If the space and + flags both appear, the space
301 			 * flag will be ignored.''
302 			 *	-- ANSI X3J11
303 			 */
304 			if (!sign)
305 				sign = ' ';
306 			goto rflag;
307 		case '#':
308 			flags |= ALT;
309 			goto rflag;
310 		case '*':
311 			/*
312 			 * ``A negative field width argument is taken as a
313 			 * - flag followed by a positive field width.''
314 			 *	-- ANSI X3J11
315 			 * They don't exclude field widths read from args.
316 			 */
317 			if ((width = va_arg(ap, int)) >= 0)
318 				goto rflag;
319 			width = -width;
320 			fallthrough;
321 		case '-':
322 			flags |= LADJUST;
323 			goto rflag;
324 		case '+':
325 			sign = '+';
326 			goto rflag;
327 		case '.':
328 			if ((ch = *fmt++) == '*') {
329 				n = va_arg(ap, int);
330 				prec = n < 0 ? -1 : n;
331 				goto rflag;
332 			}
333 			n = 0;
334 			while (is_digit(ch)) {
335 				n = 10 * n + to_digit(ch);
336 				ch = *fmt++;
337 			}
338 			prec = n < 0 ? -1 : n;
339 			goto reswitch;
340 		case '0':
341 			/*
342 			 * ``Note that 0 is taken as a flag, not as the
343 			 * beginning of a field width.''
344 			 *	-- ANSI X3J11
345 			 */
346 			flags |= ZEROPAD;
347 			goto rflag;
348 		case '1': case '2': case '3': case '4':
349 		case '5': case '6': case '7': case '8': case '9':
350 			n = 0;
351 			do {
352 				n = 10 * n + to_digit(ch);
353 				ch = *fmt++;
354 			} while (is_digit(ch));
355 			width = n;
356 			goto reswitch;
357 		case 'h':
358 			flags |= SHORTINT;
359 			goto rflag;
360 		case 'j':
361 			flags |= MAXINT;
362 			goto rflag;
363 		case 'l':
364 			if (*fmt == 'l') {
365 				fmt++;
366 				flags |= QUADINT;
367 			} else {
368 				flags |= LONGINT;
369 			}
370 			goto rflag;
371 		case 'q':
372 			flags |= QUADINT;
373 			goto rflag;
374 		case 't':
375 			flags |= PTRINT;
376 			goto rflag;
377 		case 'z':
378 			flags |= SIZEINT;
379 			goto rflag;
380 		case 'c':
381 			*(cp = bf) = va_arg(ap, int);
382 			size = 1;
383 			sign = '\0';
384 			break;
385 		case 'D':
386 			flags |= LONGINT;
387 			fallthrough;
388 		case 'd':
389 		case 'i':
390 			_uquad = SARG();
391 			if ((int64_t)_uquad < 0) {
392 				_uquad = -_uquad;
393 				sign = '-';
394 			}
395 			base = DEC;
396 			goto number;
397 		case 'n':
398 			if (flags & MAXINT)
399 				*va_arg(ap, intmax_t *) = ret;
400 			else if (flags & PTRINT)
401 				*va_arg(ap, intptr_t *) = ret;
402 			else if (flags & SIZEINT)
403 				*va_arg(ap, ssize_t *) = ret;
404 			else if (flags & QUADINT)
405 				*va_arg(ap, int64_t *) = ret;
406 			else if (flags & LONGINT)
407 				*va_arg(ap, long *) = ret;
408 			else if (flags & SHORTINT)
409 				*va_arg(ap, short *) = ret;
410 			else
411 				*va_arg(ap, int *) = ret;
412 			continue;	/* no output */
413 		case 'O':
414 			flags |= LONGINT;
415 			fallthrough;
416 		case 'o':
417 			_uquad = UARG();
418 			base = OCT;
419 			goto nosign;
420 		case 'p':
421 			if (ext && *fmt == 'U' && *(fmt+1) == 'l') {
422 				/*
423 				 * Non-standard format available in [v]snprintk
424 				 * only
425 				 */
426 				fmt += 2;
427 				size = uuid2str(bf, sizeof(bf),
428 						va_arg(ap, void *));
429 				cp = bf;
430 				sign = '\0';
431 				break;
432 			}
433 			/*
434 			 * ``The argument shall be a pointer to void.  The
435 			 * value of the pointer is converted to a sequence
436 			 * of printable characters, in an implementation-
437 			 * defined manner.''
438 			 *	-- ANSI X3J11
439 			 */
440 			/* NOSTRICT */
441 			_uquad = (unsigned long)va_arg(ap, void *);
442 			base = HEX;
443 			xdigs = hexdigits;
444 			flags |= HEXPREFIX;
445 			ch = 'x';
446 			goto nosign;
447 		case 's':
448 			if ((cp = va_arg(ap, char *)) == NULL)
449 				/*XXXUNCONST*/
450 				cp = __UNCONST("(null)");
451 			if (prec >= 0) {
452 				/*
453 				 * can't use strlen; can only look for the
454 				 * NUL in the first `prec' characters, and
455 				 * strlen() will go further.
456 				 */
457 				char *p = memchr(cp, 0, prec);
458 
459 				if (p != NULL) {
460 					size = p - cp;
461 					if (size > prec)
462 						size = prec;
463 				} else
464 					size = prec;
465 			} else
466 				size = strlen(cp);
467 			sign = '\0';
468 			break;
469 		case 'U':
470 			flags |= LONGINT;
471 			fallthrough;
472 		case 'u':
473 			_uquad = UARG();
474 			base = DEC;
475 			goto nosign;
476 		case 'X':
477 			xdigs = HEXDIGITS;
478 			goto hex;
479 		case 'x':
480 			xdigs = hexdigits;
481 hex:			_uquad = UARG();
482 			base = HEX;
483 			/* leading 0x/X only if non-zero */
484 			if (flags & ALT && _uquad != 0)
485 				flags |= HEXPREFIX;
486 
487 			/* unsigned conversions */
488 nosign:			sign = '\0';
489 			/*
490 			 * ``... diouXx conversions ... if a precision is
491 			 * specified, the 0 flag will be ignored.''
492 			 *	-- ANSI X3J11
493 			 */
494 number:			if ((dprec = prec) >= 0)
495 				flags &= ~ZEROPAD;
496 
497 			/*
498 			 * ``The result of converting a zero value with an
499 			 * explicit precision of zero is no characters.''
500 			 *	-- ANSI X3J11
501 			 */
502 			cp = bf + KPRINTF_BUFSIZE;
503 			if (_uquad != 0 || prec != 0) {
504 				/*
505 				 * Unsigned mod is hard, and unsigned mod
506 				 * by a constant is easier than that by
507 				 * a variable; hence this switch.
508 				 */
509 				switch (base) {
510 				case OCT:
511 					do {
512 						*--cp = to_char(_uquad & 7);
513 						_uquad >>= 3;
514 					} while (_uquad);
515 					/* handle octal leading 0 */
516 					if (flags & ALT && *cp != '0')
517 						*--cp = '0';
518 					break;
519 
520 				case DEC:
521 					/* many numbers are 1 digit */
522 					while (_uquad >= 10) {
523 						*--cp = to_char(_uquad % 10);
524 						_uquad /= 10;
525 					}
526 					*--cp = to_char(_uquad);
527 					break;
528 
529 				case HEX:
530 					do {
531 						*--cp = xdigs[_uquad & 15];
532 						_uquad >>= 4;
533 					} while (_uquad);
534 					break;
535 
536 				default:
537 					/*XXXUNCONST*/
538 					cp = __UNCONST("bug in kprintf: bad base");
539 					size = strlen(cp);
540 					goto skipsize;
541 				}
542 			}
543 			size = bf + KPRINTF_BUFSIZE - cp;
544 		skipsize:
545 			break;
546 		default:	/* "%?" prints ?, unless ? is NUL */
547 			if (ch == '\0')
548 				goto done;
549 			/* pretend it was %c with argument ch */
550 			cp = bf;
551 			*cp = ch;
552 			size = 1;
553 			sign = '\0';
554 			break;
555 		}
556 
557 		/*
558 		 * All reasonable formats wind up here.  At this point, `cp'
559 		 * points to a string which (if not flags&LADJUST) should be
560 		 * padded out to `width' places.  If flags&ZEROPAD, it should
561 		 * first be prefixed by any sign or other prefix; otherwise,
562 		 * it should be blank padded before the prefix is emitted.
563 		 * After any left-hand padding and prefixing, emit zeroes
564 		 * required by a decimal [diouxX] precision, then print the
565 		 * string proper, then emit zeroes required by any leftover
566 		 * floating precision; finally, if LADJUST, pad with blanks.
567 		 *
568 		 * Compute actual size, so we know how much to pad.
569 		 * size excludes decimal prec; realsz includes it.
570 		 */
571 		realsz = dprec > size ? dprec : size;
572 		if (sign)
573 			realsz++;
574 		else if (flags & HEXPREFIX)
575 			realsz+= 2;
576 
577 		/* adjust ret */
578 		ret += width > realsz ? width : realsz;
579 
580 		/* right-adjusting blank padding */
581 		if ((flags & (LADJUST|ZEROPAD)) == 0) {
582 			n = width - realsz;
583 			while (n-- > 0)
584 				KPRINTF_PUTCHAR(' ');
585 		}
586 
587 		/* prefix */
588 		if (sign) {
589 			KPRINTF_PUTCHAR(sign);
590 		} else if (flags & HEXPREFIX) {
591 			KPRINTF_PUTCHAR('0');
592 			KPRINTF_PUTCHAR(ch);
593 		}
594 
595 		/* right-adjusting zero padding */
596 		if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) {
597 			n = width - realsz;
598 			while (n-- > 0)
599 				KPRINTF_PUTCHAR('0');
600 		}
601 
602 		/* leading zeroes from decimal precision */
603 		n = dprec - size;
604 		while (n-- > 0)
605 			KPRINTF_PUTCHAR('0');
606 
607 		/* the string or number proper */
608 		for (; size--; cp++)
609 			KPRINTF_PUTCHAR(*cp);
610 		/* left-adjusting padding (always blank) */
611 		if (flags & LADJUST) {
612 			n = width - realsz;
613 			while (n-- > 0)
614 				KPRINTF_PUTCHAR(' ');
615 		}
616 	}
617 
618 done:
619 	if ((oflags == TOBUFONLY) && (vp != NULL))
620 		*(char **)vp = sbuf;
621 	return ret;
622 }
623