From 17a2ba84155f0e102bb32bdfd6303ecd584f0250 Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Wed, 4 Jan 2017 13:22:19 +0000 Subject: [PATCH] Drop vsprintf.c Drop custom vfprintf implementation that was disabled by default. Apparently nobody tests strace with this vfprintf enabled, otherwise multiple uses of format specifiers not supported by this custom vfprintf would not left unnoticed. The GNU C library is not the only libc available, so those who want faster implementations of libc functions are encouraged to try building strace with other libc implementations. * vsprintf.c: Remove. * Makefile.am (strace_SOURCES): Remove vsprintf.c. * defs.h (USE_CUSTOM_PRINTF, strace_vfprintf): Remove. * strace.c (tprintf): Replace strace_vfprintf with vfprintf. --- Makefile.am | 1 - defs.h | 19 -- strace.c | 2 +- vsprintf.c | 788 ---------------------------------------------------- 4 files changed, 1 insertion(+), 809 deletions(-) delete mode 100644 vsprintf.c diff --git a/Makefile.am b/Makefile.am index aa2927ca..3369e1ef 100644 --- a/Makefile.am +++ b/Makefile.am @@ -251,7 +251,6 @@ strace_SOURCES = \ utime.c \ utimes.c \ v4l2.c \ - vsprintf.c \ wait.c \ xattr.c \ xlat.h \ diff --git a/defs.h b/defs.h index 934d21c2..9deb6926 100644 --- a/defs.h +++ b/defs.h @@ -125,15 +125,6 @@ extern char *stpcpy(char *dst, const char *src); #define USE_SEIZE 1 /* To force NOMMU build, set to 1 */ #define NOMMU_SYSTEM 0 -/* - * Set to 1 to use speed-optimized vfprintf implementation. - * It results in strace using about 5% less CPU in user space - * (compared to glibc version). - * But strace spends a lot of time in kernel space, - * so overall it does not appear to be a significant win. - * Thus disabled by default. - */ -#define USE_CUSTOM_PRINTF 0 #ifndef ERESTARTSYS # define ERESTARTSYS 512 @@ -404,16 +395,6 @@ void *xreallocarray(void *ptr, size_t nmemb, size_t size) ATTRIBUTE_ALLOC_SIZE((2, 3)); char *xstrdup(const char *str) ATTRIBUTE_MALLOC; -#if USE_CUSTOM_PRINTF -/* - * See comment in vsprintf.c for allowed formats. - * Short version: %h[h]u, %zu, %tu are not allowed, use %[l[l]]u. - */ -int strace_vfprintf(FILE *fp, const char *fmt, va_list args); -#else -# define strace_vfprintf vfprintf -#endif - extern int read_int_from_file(const char *, int *); extern void set_sortby(const char *); diff --git a/strace.c b/strace.c index 394b657c..a337362e 100644 --- a/strace.c +++ b/strace.c @@ -573,7 +573,7 @@ tprintf(const char *fmt, ...) va_start(args, fmt); if (current_tcp) { - int n = strace_vfprintf(current_tcp->outf, fmt, args); + int n = vfprintf(current_tcp->outf, fmt, args); if (n < 0) { if (current_tcp->outf != stderr) perror_msg("%s", outfname); diff --git a/vsprintf.c b/vsprintf.c deleted file mode 100644 index aae40db3..00000000 --- a/vsprintf.c +++ /dev/null @@ -1,788 +0,0 @@ -/* - * Taken from Linux kernel's linux/lib/vsprintf.c - * and somewhat simplified. - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ -/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ -/* - * Wirzenius wrote this portably, Torvalds fucked it up :-) - */ - -#include "defs.h" - -#if USE_CUSTOM_PRINTF - -#include -#include - -#ifndef HAVE_FPUTS_UNLOCKED -# define fputs_unlocked fputs -#endif - -#define noinline_for_stack /*nothing*/ -#define likely(expr) (expr) -#define unlikely(expr) (expr) - -#define do_div(n, d) ({ __typeof(num) t = n % d; n /= d; t; }) - -#undef isdigit -#define isdigit(a) ((unsigned char)((a) - '0') <= 9) - -static inline -int skip_atoi(const char **s) -{ - int i = 0; - const char *p = *s; - - while (isdigit(*p)) - i = i*10 + *p++ - '0'; - - *s = p; - return i; -} - -/* Decimal conversion is by far the most typical, and is used - * for /proc and /sys data. This directly impacts e.g. top performance - * with many processes running. We optimize it for speed - * using ideas described at - * (with permission from the author, Douglas W. Jones). - */ - -#if LONG_MAX != 0x7fffffffUL || LLONG_MAX != 0x7fffffffffffffffULL -/* Formats correctly any integer in [0, 999999999] */ -static noinline_for_stack -char *put_dec_full9(char *buf, unsigned q) -{ - unsigned r; - - /* Possible ways to approx. divide by 10 - * (x * 0x1999999a) >> 32 x < 1073741829 (multiply must be 64-bit) - * (x * 0xcccd) >> 19 x < 81920 (x < 262149 when 64-bit mul) - * (x * 0x6667) >> 18 x < 43699 - * (x * 0x3334) >> 17 x < 16389 - * (x * 0x199a) >> 16 x < 16389 - * (x * 0x0ccd) >> 15 x < 16389 - * (x * 0x0667) >> 14 x < 2739 - * (x * 0x0334) >> 13 x < 1029 - * (x * 0x019a) >> 12 x < 1029 - * (x * 0x00cd) >> 11 x < 1029 shorter code than * 0x67 (on i386) - * (x * 0x0067) >> 10 x < 179 - * (x * 0x0034) >> 9 x < 69 same - * (x * 0x001a) >> 8 x < 69 same - * (x * 0x000d) >> 7 x < 69 same, shortest code (on i386) - * (x * 0x0007) >> 6 x < 19 - * See - */ - r = (q * (uint64_t)0x1999999a) >> 32; - *buf++ = (q - 10 * r) + '0'; /* 1 */ - q = (r * (uint64_t)0x1999999a) >> 32; - *buf++ = (r - 10 * q) + '0'; /* 2 */ - r = (q * (uint64_t)0x1999999a) >> 32; - *buf++ = (q - 10 * r) + '0'; /* 3 */ - q = (r * (uint64_t)0x1999999a) >> 32; - *buf++ = (r - 10 * q) + '0'; /* 4 */ - r = (q * (uint64_t)0x1999999a) >> 32; - *buf++ = (q - 10 * r) + '0'; /* 5 */ - /* Now value is under 10000, can avoid 64-bit multiply */ - q = (r * 0x199a) >> 16; - *buf++ = (r - 10 * q) + '0'; /* 6 */ - r = (q * 0xcd) >> 11; - *buf++ = (q - 10 * r) + '0'; /* 7 */ - q = (r * 0xcd) >> 11; - *buf++ = (r - 10 * q) + '0'; /* 8 */ - *buf++ = q + '0'; /* 9 */ - return buf; -} -#endif - -/* Similar to above but do not pad with zeros. - * Code can be easily arranged to print 9 digits too, but our callers - * always call put_dec_full9() instead when the number has 9 decimal digits. - */ -static noinline_for_stack -char *put_dec_trunc8(char *buf, unsigned r) -{ - unsigned q; - - /* Copy of previous function's body with added early returns */ - q = (r * (uint64_t)0x1999999a) >> 32; - *buf++ = (r - 10 * q) + '0'; /* 2 */ - if (q == 0) return buf; - r = (q * (uint64_t)0x1999999a) >> 32; - *buf++ = (q - 10 * r) + '0'; /* 3 */ - if (r == 0) return buf; - q = (r * (uint64_t)0x1999999a) >> 32; - *buf++ = (r - 10 * q) + '0'; /* 4 */ - if (q == 0) return buf; - r = (q * (uint64_t)0x1999999a) >> 32; - *buf++ = (q - 10 * r) + '0'; /* 5 */ - if (r == 0) return buf; - q = (r * 0x199a) >> 16; - *buf++ = (r - 10 * q) + '0'; /* 6 */ - if (q == 0) return buf; - r = (q * 0xcd) >> 11; - *buf++ = (q - 10 * r) + '0'; /* 7 */ - if (r == 0) return buf; - q = (r * 0xcd) >> 11; - *buf++ = (r - 10 * q) + '0'; /* 8 */ - if (q == 0) return buf; - *buf++ = q + '0'; /* 9 */ - return buf; -} - -/* There are two algorithms to print larger numbers. - * One is generic: divide by 1000000000 and repeatedly print - * groups of (up to) 9 digits. It's conceptually simple, - * but requires a (unsigned long long) / 1000000000 division. - * - * Second algorithm splits 64-bit unsigned long long into 16-bit chunks, - * manipulates them cleverly and generates groups of 4 decimal digits. - * It so happens that it does NOT require long long division. - * - * If long is > 32 bits, division of 64-bit values is relatively easy, - * and we will use the first algorithm. - * If long long is > 64 bits (strange architecture with VERY large long long), - * second algorithm can't be used, and we again use the first one. - * - * Else (if long is 32 bits and long long is 64 bits) we use second one. - */ - -#if LONG_MAX != 0x7fffffffUL || LLONG_MAX != 0x7fffffffffffffffULL - -/* First algorithm: generic */ - -static -char *put_dec(char *buf, unsigned long long n) -{ - if (n >= 100*1000*1000) { - while (n >= 1000*1000*1000) - buf = put_dec_full9(buf, do_div(n, 1000*1000*1000)); - if (n >= 100*1000*1000) - return put_dec_full9(buf, n); - } - return put_dec_trunc8(buf, n); -} - -#else - -/* Second algorithm: valid only for 64-bit long longs */ - -static noinline_for_stack -char *put_dec_full4(char *buf, unsigned q) -{ - unsigned r; - r = (q * 0xcccd) >> 19; - *buf++ = (q - 10 * r) + '0'; - q = (r * 0x199a) >> 16; - *buf++ = (r - 10 * q) + '0'; - r = (q * 0xcd) >> 11; - *buf++ = (q - 10 * r) + '0'; - *buf++ = r + '0'; - return buf; -} - -/* Based on code by Douglas W. Jones found at - * - * (with permission from the author). - * Performs no 64-bit division and hence should be fast on 32-bit machines. - */ -static -char *put_dec(char *buf, unsigned long long n) -{ - uint32_t d3, d2, d1, q, h; - - if (n < 100*1000*1000) - return put_dec_trunc8(buf, n); - - d1 = ((uint32_t)n >> 16); /* implicit "& 0xffff" */ - h = (n >> 32); - d2 = (h ) & 0xffff; - d3 = (h >> 16); /* implicit "& 0xffff" */ - - q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((uint32_t)n & 0xffff); - - buf = put_dec_full4(buf, q % 10000); - q = q / 10000; - - d1 = q + 7671 * d3 + 9496 * d2 + 6 * d1; - buf = put_dec_full4(buf, d1 % 10000); - q = d1 / 10000; - - d2 = q + 4749 * d3 + 42 * d2; - buf = put_dec_full4(buf, d2 % 10000); - q = d2 / 10000; - - d3 = q + 281 * d3; - if (!d3) - goto done; - buf = put_dec_full4(buf, d3 % 10000); - q = d3 / 10000; - if (!q) - goto done; - buf = put_dec_full4(buf, q); - done: - while (buf[-1] == '0') - --buf; - - return buf; -} - -#endif - -/* - * For strace, the following formats are not supported: - * %h[h]u, %zu, %tu - use [unsigned] int/long/long long fmt instead - * %8.4u - no precision field for integers allowed (ok for strings) - * %+d, % d - no forced sign or force "space positive" sign - * %-07u - use %-7u instead - * %X - works as %x - */ - -#define ZEROPAD 1 /* pad with zero */ -#define SIGN 2 /* unsigned/signed long */ -//#define PLUS 4 /* show plus */ -//#define SPACE 8 /* space if plus */ -#define LEFT 16 /* left justified */ -//#deefine SMALL 32 /* use lowercase in hex (must be 32 == 0x20) */ -#define SPECIAL 64 /* prefix hex with "0x", octal with "0" */ - -enum format_type { - FORMAT_TYPE_NONE, /* Just a string part */ - FORMAT_TYPE_WIDTH, - FORMAT_TYPE_PRECISION, - FORMAT_TYPE_CHAR, - FORMAT_TYPE_STR, - FORMAT_TYPE_PTR, - FORMAT_TYPE_PERCENT_CHAR, - FORMAT_TYPE_INVALID, - FORMAT_TYPE_LONG_LONG, - FORMAT_TYPE_ULONG, - FORMAT_TYPE_LONG, - FORMAT_TYPE_UINT, - FORMAT_TYPE_INT, -}; - -struct printf_spec { - uint8_t type; /* format_type enum */ - uint8_t flags; /* flags to number() */ - uint8_t base; /* number base, 8, 10 or 16 only */ - uint8_t qualifier; /* number qualifier, one of 'hHlLtzZ' */ - int field_width; /* width of output field */ - int precision; /* # of digits/chars */ -}; - -static noinline_for_stack -char *number(char *buf, char *end, unsigned long long num, - struct printf_spec spec) -{ - /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ - static const char digits[16] = "0123456789abcdef"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ - - char tmp[sizeof(long long)*3 + 4]; - char sign; - int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10); - int i; - - /* We may overflow the buf. Crudely check for it */ - i = sizeof(long long)*3 + 4; - if (i < spec.field_width) - i = spec.field_width; - if ((end - buf) <= i) - return buf + i; - -//we don't use formats like "%-07u" -// if (spec.flags & LEFT) -// spec.flags &= ~ZEROPAD; - sign = 0; - if (spec.flags & SIGN) { - if ((signed long long)num < 0) { - sign = '-'; - num = -(signed long long)num; - spec.field_width--; -// } else if (spec.flags & PLUS) { -// sign = '+'; -// spec.field_width--; -// } else if (spec.flags & SPACE) { -// sign = ' '; -// spec.field_width--; - } - } - if (need_pfx) { - spec.field_width--; - if (spec.base == 16) - spec.field_width--; - } - - /* generate full string in tmp[], in reverse order */ - i = 0; - if (num < spec.base) - tmp[i++] = digits[num]; - /* Generic code, for any base: - else do { - tmp[i++] = (digits[do_div(num,base)]); - } while (num != 0); - */ - else if (spec.base != 10) { /* 8 or 16 */ - int mask = spec.base - 1; - int shift = 3; - - if (spec.base == 16) - shift = 4; - do { - tmp[i++] = digits[((unsigned char)num) & mask]; - num >>= shift; - } while (num); - } else { /* base 10 */ - i = put_dec(tmp, num) - tmp; - } - -//spec.precision is assumed 0 ("not specified") -// /* printing 100 using %2d gives "100", not "00" */ -// if (i > spec.precision) -// spec.precision = i; -// /* leading space padding */ -// spec.field_width -= spec.precision; - spec.field_width -= i; - if (!(spec.flags & (ZEROPAD+LEFT))) { - while (--spec.field_width >= 0) { - ///if (buf < end) - *buf = ' '; - ++buf; - } - } - /* sign */ - if (sign) { - ///if (buf < end) - *buf = sign; - ++buf; - } - /* "0x" / "0" prefix */ - if (need_pfx) { - ///if (buf < end) - *buf = '0'; - ++buf; - if (spec.base == 16) { - ///if (buf < end) - *buf = 'x'; - ++buf; - } - } - /* zero or space padding */ - if (!(spec.flags & LEFT)) { - char c = (spec.flags & ZEROPAD) ? '0' : ' '; - while (--spec.field_width >= 0) { - ///if (buf < end) - *buf = c; - ++buf; - } - } -// /* hmm even more zero padding? */ -// while (i <= --spec.precision) { -// ///if (buf < end) -// *buf = '0'; -// ++buf; -// } - /* actual digits of result */ - while (--i >= 0) { - ///if (buf < end) - *buf = tmp[i]; - ++buf; - } - /* trailing space padding */ - while (--spec.field_width >= 0) { - ///if (buf < end) - *buf = ' '; - ++buf; - } - - return buf; -} - -static noinline_for_stack -char *string(char *buf, char *end, const char *s, struct printf_spec spec) -{ - int len, i; - - if (!s) - s = "(null)"; - - len = strnlen(s, spec.precision); - - /* We may overflow the buf. Crudely check for it */ - i = len; - if (i < spec.field_width) - i = spec.field_width; - if ((end - buf) <= i) - return buf + i; - - if (!(spec.flags & LEFT)) { - while (len < spec.field_width--) { - ///if (buf < end) - *buf = ' '; - ++buf; - } - } - for (i = 0; i < len; ++i) { - ///if (buf < end) - *buf = *s; - ++buf; ++s; - } - while (len < spec.field_width--) { - ///if (buf < end) - *buf = ' '; - ++buf; - } - - return buf; -} - -static noinline_for_stack -char *pointer(const char *fmt, char *buf, char *end, void *ptr, - struct printf_spec spec) -{ -// spec.flags |= SMALL; - if (spec.field_width == -1) { - spec.field_width = 2 * sizeof(void *); - spec.flags |= ZEROPAD; - } - spec.base = 16; - - return number(buf, end, (unsigned long) ptr, spec); -} - -/* - * Helper function to decode printf style format. - * Each call decode a token from the format and return the - * number of characters read (or likely the delta where it wants - * to go on the next call). - * The decoded token is returned through the parameters - * - * 'h', 'l', or 'L' for integer fields - * 'z' support added 23/7/1999 S.H. - * 'z' changed to 'Z' --davidm 1/25/99 - * 't' added for ptrdiff_t - * - * @fmt: the format string - * @type of the token returned - * @flags: various flags such as +, -, # tokens.. - * @field_width: overwritten width - * @base: base of the number (octal, hex, ...) - * @precision: precision of a number - * @qualifier: qualifier of a number (long, size_t, ...) - */ -static noinline_for_stack -int format_decode(const char *fmt, struct printf_spec *spec) -{ - const char *start = fmt; - - /* we finished early by reading the field width */ - if (spec->type == FORMAT_TYPE_WIDTH) { - if (spec->field_width < 0) { - spec->field_width = -spec->field_width; - spec->flags |= LEFT; - } - spec->type = FORMAT_TYPE_NONE; - goto precision; - } - - /* we finished early by reading the precision */ - if (spec->type == FORMAT_TYPE_PRECISION) { - if (spec->precision < 0) - spec->precision = 0; - - spec->type = FORMAT_TYPE_NONE; - goto qualifier; - } - - /* By default */ - spec->type = FORMAT_TYPE_NONE; - - for (;;) { - if (*fmt == '\0') - return fmt - start; - if (*fmt == '%') - break; - ++fmt; - } - - /* Return the current non-format string */ - if (fmt != start) - return fmt - start; - - /* Process flags */ - spec->flags = 0; - - while (1) { /* this also skips first '%' */ - bool found = true; - - ++fmt; - - switch (*fmt) { - case '-': spec->flags |= LEFT; break; -// case '+': spec->flags |= PLUS; break; -// case ' ': spec->flags |= SPACE; break; - case '#': spec->flags |= SPECIAL; break; - case '0': spec->flags |= ZEROPAD; break; - default: found = false; - } - - if (!found) - break; - } - - /* get field width */ - spec->field_width = -1; - - if (isdigit(*fmt)) - spec->field_width = skip_atoi(&fmt); - else if (*fmt == '*') { - /* it's the next argument */ - spec->type = FORMAT_TYPE_WIDTH; - return ++fmt - start; - } - -precision: - /* get the precision */ - spec->precision = -1; - if (*fmt == '.') { - ++fmt; - if (isdigit(*fmt)) { - spec->precision = skip_atoi(&fmt); -// if (spec->precision < 0) -// spec->precision = 0; - } else if (*fmt == '*') { - /* it's the next argument */ - spec->type = FORMAT_TYPE_PRECISION; - return ++fmt - start; - } - } - -qualifier: - /* get the conversion qualifier */ - spec->qualifier = -1; - if (*fmt == 'l') { - spec->qualifier = *fmt++; - if (unlikely(spec->qualifier == *fmt)) { - spec->qualifier = 'L'; - ++fmt; - } - } - - /* default base */ - spec->base = 10; - switch (*fmt) { - case 'c': - spec->type = FORMAT_TYPE_CHAR; - return ++fmt - start; - - case 's': - spec->type = FORMAT_TYPE_STR; - return ++fmt - start; - - case 'p': - spec->type = FORMAT_TYPE_PTR; - return ++fmt - start; - - case '%': - spec->type = FORMAT_TYPE_PERCENT_CHAR; - return ++fmt - start; - - /* integer number formats - set up the flags and "break" */ - case 'o': - spec->base = 8; - break; - - case 'x': -// spec->flags |= SMALL; - - case 'X': - spec->base = 16; - break; - - case 'd': - case 'i': - spec->flags |= SIGN; - case 'u': - break; - - default: - spec->type = FORMAT_TYPE_INVALID; - return fmt - start; - } - - if (spec->qualifier == 'L') - spec->type = FORMAT_TYPE_LONG_LONG; - else if (spec->qualifier == 'l') { - if (spec->flags & SIGN) - spec->type = FORMAT_TYPE_LONG; - else - spec->type = FORMAT_TYPE_ULONG; - } else { - if (spec->flags & SIGN) - spec->type = FORMAT_TYPE_INT; - else - spec->type = FORMAT_TYPE_UINT; - } - - return ++fmt - start; -} - -/** - * vsnprintf - Format a string and place it in a buffer - * @buf: The buffer to place the result into - * @size: The size of the buffer, including the trailing null space - * @fmt: The format string to use - * @args: Arguments for the format string - * - * The return value is the number of characters which would - * be generated for the given input, excluding the trailing - * '\0', as per ISO C99. If you want to have the exact - * number of characters written into @buf as return value - * (not including the trailing '\0'), use vscnprintf(). If the - * return is greater than or equal to @size, the resulting - * string is truncated. - * - * If you're not already dealing with a va_list consider using snprintf(). - */ -static -int kernel_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) -{ - unsigned long long num; - char *str, *end; - struct printf_spec spec = {0}; - - str = buf; - end = buf + size; - - while (*fmt) { - const char *old_fmt = fmt; - int read = format_decode(fmt, &spec); - - fmt += read; - - switch (spec.type) { - case FORMAT_TYPE_NONE: { - int copy = read; - if (str < end) { - if (copy > end - str) - copy = end - str; - memcpy(str, old_fmt, copy); - } - str += read; - break; - } - - case FORMAT_TYPE_WIDTH: - spec.field_width = va_arg(args, int); - break; - - case FORMAT_TYPE_PRECISION: - spec.precision = va_arg(args, int); - break; - - case FORMAT_TYPE_CHAR: { - char c; - - if (!(spec.flags & LEFT)) { - while (--spec.field_width > 0) { - if (str < end) - *str = ' '; - ++str; - - } - } - c = (unsigned char) va_arg(args, int); - if (str < end) - *str = c; - ++str; - while (--spec.field_width > 0) { - if (str < end) - *str = ' '; - ++str; - } - break; - } - - case FORMAT_TYPE_STR: - str = string(str, end, va_arg(args, char *), spec); - break; - - case FORMAT_TYPE_PTR: - str = pointer(fmt+1, str, end, va_arg(args, void *), - spec); -// while (isalnum(*fmt)) -// fmt++; - break; - - case FORMAT_TYPE_PERCENT_CHAR: - if (str < end) - *str = '%'; - ++str; - break; - - case FORMAT_TYPE_INVALID: - if (str < end) - *str = '%'; - ++str; - break; - - default: - switch (spec.type) { - case FORMAT_TYPE_LONG_LONG: - num = va_arg(args, long long); - break; - case FORMAT_TYPE_ULONG: - num = va_arg(args, unsigned long); - break; - case FORMAT_TYPE_LONG: - num = va_arg(args, long); - break; - case FORMAT_TYPE_INT: - num = (int) va_arg(args, int); - break; - default: - num = va_arg(args, unsigned int); - } - - str = number(str, end, num, spec); - } - } - -// if (size > 0) { - if (str < end) - *str = '\0'; -// else -// end[-1] = '\0'; -// } - - /* the trailing null byte doesn't count towards the total */ - return str-buf; - -} - -int strace_vfprintf(FILE *fp, const char *fmt, va_list args) -{ - static char *buf = NULL; - static unsigned buflen = 0; - - int r; - va_list a1; - - va_copy(a1, args); - unsigned len = kernel_vsnprintf(buf, buflen, fmt, a1); - va_end(a1); - - if (len >= buflen) { - buflen = len + 256; - free(buf); - buf = xmalloc(buflen); - /*len =*/ kernel_vsnprintf(buf, buflen, fmt, args); - } - - r = fputs_unlocked(buf, fp); - if (r < 0) return r; - return len; -} - -#endif /* USE_CUSTOM_PRINTF */ -- 2.40.0