btrfs-progs: add musl compatibility for printf format %pV

Glibc provides an interface to extend the printf formats but this is not
standardized and does not work on musl. The code brought from kernel
uses %pV for varargs and also has own implementation of printk.

As a workaround for musl expand the pV value to a string and then
simply print it. The details are hidden behind macros:

- DECLARE_PV(vaf)
- PV_ASSIGN(vaf, format, args)
- PV_FMT in printf string
- PV_VAL in arguments

Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
David Sterba 2023-05-03 23:54:30 +02:00
parent 762dbd6d70
commit 164bc10dfc
4 changed files with 42 additions and 21 deletions

View File

@ -16,7 +16,6 @@
#include <stdio.h>
#include <stdarg.h>
#include <printf.h>
#include "common/messages.h"
#include "common/utils.h"
@ -26,8 +25,6 @@ static const char *common_error_string[] = {
[ERROR_MSG_COMMIT_TRANS] = "failed to commit transaction",
};
static int va_modifier = -1;
__attribute__ ((format (printf, 1, 2)))
void __btrfs_printf(const char *fmt, ...)
{
@ -38,6 +35,10 @@ void __btrfs_printf(const char *fmt, ...)
va_end(args);
}
#ifndef PV_WORKAROUND
static int va_modifier = -1;
static int print_va_format(FILE *stream, const struct printf_info *info,
const void *const *args)
{
@ -58,18 +59,21 @@ static int print_va_format_arginfo(const struct printf_info *info,
size[0] = sizeof(struct va_format *);
}
return 1;
}
}
#endif
__attribute__ ((format (printf, 2, 3)))
void btrfs_no_printk(const void *fs_info, const char *fmt, ...)
{
va_list args;
#ifndef PV_WORKAROUND
if (va_modifier == -1) {
register_printf_specifier('V', print_va_format,
print_va_format_arginfo);
va_modifier = register_printf_modifier(L"p");
}
#endif
va_start(args, fmt);
vfprintf(stderr, fmt, args);

View File

@ -22,6 +22,23 @@
#include <stdio.h>
#include <errno.h>
/*
* Workaround for custom format %pV that may not be supported on all libcs.
*/
#ifdef HAVE_PRINTF_H
#define DECLARE_PV(name) struct va_format name
#define PV_FMT "%pV"
#define PV_VAL(va) &va
#define PV_ASSIGN(_va, _fmt, _args) ({ _va.fmt = (_fmt); _va.va = &(_args); })
#include <printf.h>
#else
#define PV_WORKAROUND
#define DECLARE_PV(name) char name[1024]
#define PV_FMT "%s"
#define PV_VAL(va) va
#define PV_ASSIGN(_va, _fmt, _args) vsnprintf(_va, 1024, _fmt, _args)
#endif
#ifdef DEBUG_VERBOSE_ERROR
#define PRINT_VERBOSE_ERROR fprintf(stderr, "%s:%d:", __FILE__, __LINE__)
#else

View File

@ -85,6 +85,7 @@ AX_GCC_BUILTIN([__builtin_mul_overflow])
AC_CHECK_HEADERS([linux/perf_event.h])
AC_CHECK_HEADERS([linux/hw_breakpoint.h])
AC_CHECK_HEADERS([linux/fsverity.h])
AC_CHECK_HEADERS([printf.h])
if grep -q 'HAVE_LINUX_FSVERITY_H.*1' confdefs.h; then
have_fsverity='yes'

View File

@ -134,15 +134,14 @@ void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function
errstr = btrfs_decode_error(error);
btrfs_state_to_string(fs_info, statestr);
if (fmt) {
struct va_format vaf;
DECLARE_PV(vaf);
va_list args;
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
PV_ASSIGN(vaf, fmt, args);
pr_crit("BTRFS: error (device %s%s) in %s:%d: error=%d %s (%pV)\n",
sb->s_id, statestr, function, line, error, errstr, &vaf);
pr_crit("BTRFS: error (device %s%s) in %s:%d: error=%d %s (" PV_FMT ")\n",
sb->s_id, statestr, function, line, error, errstr, PV_VAL(vaf));
va_end(args);
} else {
pr_crit("BTRFS: error (device %s%s) in %s:%d: error=%d %s\n",
@ -215,7 +214,7 @@ static struct ratelimit_state printk_limits[] = {
void __cold _btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...)
{
char lvl[PRINTK_MAX_SINGLE_HEADER_LEN + 1] = "\0";
struct va_format vaf;
DECLARE_PV(vaf);
va_list args;
int kern_level;
const char *type = logtypes[4];
@ -239,18 +238,17 @@ void __cold _btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt,
fmt += size;
}
vaf.fmt = fmt;
vaf.va = &args;
PV_ASSIGN(vaf, fmt, args);
if (__ratelimit(ratelimit)) {
if (fs_info) {
char statestr[STATE_STRING_BUF_LEN];
btrfs_state_to_string(fs_info, statestr);
_printk("%sBTRFS %s (device %s%s): %pV\n", lvl, type,
fs_info->sb->s_id, statestr, &vaf);
_printk("%sBTRFS %s (device %s%s): " PV_FMT "\n", lvl, type,
fs_info->sb->s_id, statestr, PV_VAL(vaf));
} else {
_printk("%sBTRFS %s: %pV\n", lvl, type, &vaf);
_printk("%sBTRFS %s: " PV_FMT "\n", lvl, type, PV_VAL(vaf));
}
}
@ -310,7 +308,7 @@ void __btrfs_panic(struct btrfs_fs_info *fs_info, const char *function,
unsigned int line, int error, const char *fmt, ...)
{
const char *errstr;
struct va_format vaf = { .fmt = fmt };
DECLARE_PV(vaf);
va_list args;
#if 0
char *s_id = "<unknown>";
@ -320,17 +318,18 @@ void __btrfs_panic(struct btrfs_fs_info *fs_info, const char *function,
#endif
va_start(args, fmt);
vaf.va = &args;
PV_ASSIGN(vaf, fmt, args);
errstr = btrfs_decode_error(error);
#if 0
if (fs_info && (btrfs_test_opt(fs_info, PANIC_ON_FATAL_ERROR)))
panic(KERN_CRIT "BTRFS panic (device %s) in %s:%d: %pV (error=%d %s)\n",
s_id, function, line, &vaf, error, errstr);
panic(KERN_CRIT "BTRFS panic (device %s) in %s:%d: " PV_FMT " (error=%d %s)\n",
s_id, function, line, PV_VAL(vaf), error, errstr);
#endif
btrfs_crit(fs_info, "panic in %s:%d: %pV (error=%d %s)",
function, line, &vaf, error, errstr);
btrfs_crit(fs_info, "panic in %s:%d: " PV_FMT " (error=%d %s)",
function, line, PV_VAL(vaf), error, errstr);
va_end(args);
/* Caller calls BUG() */
}