printf: add support for printing symbolic error names
It has been suggested several times to extend vsnprintf() to be able
to convert the numeric value of ENOSPC to print "ENOSPC". This
implements that as a %p extension: With %pe, one can do
if (IS_ERR(foo)) {
pr_err("Sorry, can't do that: %pe\n", foo);
return PTR_ERR(foo);
}
instead of what is seen in quite a few places in the kernel:
if (IS_ERR(foo)) {
pr_err("Sorry, can't do that: %ld\n", PTR_ERR(foo));
return PTR_ERR(foo);
}
If the value passed to %pe is an ERR_PTR, but the library function
errname() added here doesn't know about the value, the value is simply
printed in decimal. If the value passed to %pe is not an ERR_PTR, we
treat it as an ordinary %p and thus print the hashed value (passing
non-ERR_PTR values to %pe indicates a bug in the caller, but we can't
do much about that).
With my embedded hat on, and because it's not very invasive to do,
I've made it possible to remove this. The errname() function and
associated lookup tables take up about 3K. For most, that's probably
quite acceptable and a price worth paying for more readable
dmesg (once this starts getting used), while for those that disable
printk() it's of very little use - I don't see a
procfs/sysfs/seq_printf() file reasonably making use of this - and
they clearly want to squeeze vmlinux as much as possible. Hence the
default y if PRINTK.
The symbols to include have been found by massaging the output of
find arch include -iname 'errno*.h' | xargs grep -E 'define\s*E'
In the cases where some common aliasing exists
(e.g. EAGAIN=EWOULDBLOCK on all platforms, EDEADLOCK=EDEADLK on most),
I've moved the more popular one (in terms of 'git grep -w Efoo | wc)
to the bottom so that one takes precedence.
Link: http://lkml.kernel.org/r/20191015190706.15989-1-linux@rasmusvillemoes.dk
To: "Jonathan Corbet" <corbet@lwn.net>
To: linux-kernel@vger.kernel.org
Cc: "Andy Shevchenko" <andy.shevchenko@gmail.com>
Cc: "Andrew Morton" <akpm@linux-foundation.org>
Cc: "Joe Perches" <joe@perches.com>
Cc: linux-doc@vger.kernel.org
Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Acked-by: Uwe Kleine-König <uwe@kleine-koenig.org>
Reviewed-by: Petr Mladek <pmladek@suse.com>
[andy.shevchenko@gmail.com: use abs()]
Acked-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Petr Mladek <pmladek@suse.com>
2019-10-16 03:07:05 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
#include <linux/build_bug.h>
|
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/errname.h>
|
|
|
|
#include <linux/kernel.h>
|
2020-12-16 12:42:48 +08:00
|
|
|
#include <linux/math.h>
|
printf: add support for printing symbolic error names
It has been suggested several times to extend vsnprintf() to be able
to convert the numeric value of ENOSPC to print "ENOSPC". This
implements that as a %p extension: With %pe, one can do
if (IS_ERR(foo)) {
pr_err("Sorry, can't do that: %pe\n", foo);
return PTR_ERR(foo);
}
instead of what is seen in quite a few places in the kernel:
if (IS_ERR(foo)) {
pr_err("Sorry, can't do that: %ld\n", PTR_ERR(foo));
return PTR_ERR(foo);
}
If the value passed to %pe is an ERR_PTR, but the library function
errname() added here doesn't know about the value, the value is simply
printed in decimal. If the value passed to %pe is not an ERR_PTR, we
treat it as an ordinary %p and thus print the hashed value (passing
non-ERR_PTR values to %pe indicates a bug in the caller, but we can't
do much about that).
With my embedded hat on, and because it's not very invasive to do,
I've made it possible to remove this. The errname() function and
associated lookup tables take up about 3K. For most, that's probably
quite acceptable and a price worth paying for more readable
dmesg (once this starts getting used), while for those that disable
printk() it's of very little use - I don't see a
procfs/sysfs/seq_printf() file reasonably making use of this - and
they clearly want to squeeze vmlinux as much as possible. Hence the
default y if PRINTK.
The symbols to include have been found by massaging the output of
find arch include -iname 'errno*.h' | xargs grep -E 'define\s*E'
In the cases where some common aliasing exists
(e.g. EAGAIN=EWOULDBLOCK on all platforms, EDEADLOCK=EDEADLK on most),
I've moved the more popular one (in terms of 'git grep -w Efoo | wc)
to the bottom so that one takes precedence.
Link: http://lkml.kernel.org/r/20191015190706.15989-1-linux@rasmusvillemoes.dk
To: "Jonathan Corbet" <corbet@lwn.net>
To: linux-kernel@vger.kernel.org
Cc: "Andy Shevchenko" <andy.shevchenko@gmail.com>
Cc: "Andrew Morton" <akpm@linux-foundation.org>
Cc: "Joe Perches" <joe@perches.com>
Cc: linux-doc@vger.kernel.org
Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Acked-by: Uwe Kleine-König <uwe@kleine-koenig.org>
Reviewed-by: Petr Mladek <pmladek@suse.com>
[andy.shevchenko@gmail.com: use abs()]
Acked-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Petr Mladek <pmladek@suse.com>
2019-10-16 03:07:05 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Ensure these tables do not accidentally become gigantic if some
|
|
|
|
* huge errno makes it in. On most architectures, the first table will
|
|
|
|
* only have about 140 entries, but mips and parisc have more sparsely
|
|
|
|
* allocated errnos (with EHWPOISON = 257 on parisc, and EDQUOT = 1133
|
|
|
|
* on mips), so this wastes a bit of space on those - though we
|
|
|
|
* special case the EDQUOT case.
|
|
|
|
*/
|
|
|
|
#define E(err) [err + BUILD_BUG_ON_ZERO(err <= 0 || err > 300)] = "-" #err
|
|
|
|
static const char *names_0[] = {
|
|
|
|
E(E2BIG),
|
|
|
|
E(EACCES),
|
|
|
|
E(EADDRINUSE),
|
|
|
|
E(EADDRNOTAVAIL),
|
|
|
|
E(EADV),
|
|
|
|
E(EAFNOSUPPORT),
|
|
|
|
E(EALREADY),
|
|
|
|
E(EBADE),
|
|
|
|
E(EBADF),
|
|
|
|
E(EBADFD),
|
|
|
|
E(EBADMSG),
|
|
|
|
E(EBADR),
|
|
|
|
E(EBADRQC),
|
|
|
|
E(EBADSLT),
|
|
|
|
E(EBFONT),
|
|
|
|
E(EBUSY),
|
|
|
|
#ifdef ECANCELLED
|
|
|
|
E(ECANCELLED),
|
|
|
|
#endif
|
|
|
|
E(ECHILD),
|
|
|
|
E(ECHRNG),
|
|
|
|
E(ECOMM),
|
|
|
|
E(ECONNABORTED),
|
|
|
|
E(ECONNRESET),
|
|
|
|
E(EDEADLOCK),
|
|
|
|
E(EDESTADDRREQ),
|
|
|
|
E(EDOM),
|
|
|
|
E(EDOTDOT),
|
|
|
|
#ifndef CONFIG_MIPS
|
|
|
|
E(EDQUOT),
|
|
|
|
#endif
|
|
|
|
E(EEXIST),
|
|
|
|
E(EFAULT),
|
|
|
|
E(EFBIG),
|
|
|
|
E(EHOSTDOWN),
|
|
|
|
E(EHOSTUNREACH),
|
|
|
|
E(EHWPOISON),
|
|
|
|
E(EIDRM),
|
|
|
|
E(EILSEQ),
|
|
|
|
#ifdef EINIT
|
|
|
|
E(EINIT),
|
|
|
|
#endif
|
|
|
|
E(EINPROGRESS),
|
|
|
|
E(EINTR),
|
|
|
|
E(EINVAL),
|
|
|
|
E(EIO),
|
|
|
|
E(EISCONN),
|
|
|
|
E(EISDIR),
|
|
|
|
E(EISNAM),
|
|
|
|
E(EKEYEXPIRED),
|
|
|
|
E(EKEYREJECTED),
|
|
|
|
E(EKEYREVOKED),
|
|
|
|
E(EL2HLT),
|
|
|
|
E(EL2NSYNC),
|
|
|
|
E(EL3HLT),
|
|
|
|
E(EL3RST),
|
|
|
|
E(ELIBACC),
|
|
|
|
E(ELIBBAD),
|
|
|
|
E(ELIBEXEC),
|
|
|
|
E(ELIBMAX),
|
|
|
|
E(ELIBSCN),
|
|
|
|
E(ELNRNG),
|
|
|
|
E(ELOOP),
|
|
|
|
E(EMEDIUMTYPE),
|
|
|
|
E(EMFILE),
|
|
|
|
E(EMLINK),
|
|
|
|
E(EMSGSIZE),
|
|
|
|
E(EMULTIHOP),
|
|
|
|
E(ENAMETOOLONG),
|
|
|
|
E(ENAVAIL),
|
|
|
|
E(ENETDOWN),
|
|
|
|
E(ENETRESET),
|
|
|
|
E(ENETUNREACH),
|
|
|
|
E(ENFILE),
|
|
|
|
E(ENOANO),
|
|
|
|
E(ENOBUFS),
|
|
|
|
E(ENOCSI),
|
|
|
|
E(ENODATA),
|
|
|
|
E(ENODEV),
|
|
|
|
E(ENOENT),
|
|
|
|
E(ENOEXEC),
|
|
|
|
E(ENOKEY),
|
|
|
|
E(ENOLCK),
|
|
|
|
E(ENOLINK),
|
|
|
|
E(ENOMEDIUM),
|
|
|
|
E(ENOMEM),
|
|
|
|
E(ENOMSG),
|
|
|
|
E(ENONET),
|
|
|
|
E(ENOPKG),
|
|
|
|
E(ENOPROTOOPT),
|
|
|
|
E(ENOSPC),
|
|
|
|
E(ENOSR),
|
|
|
|
E(ENOSTR),
|
|
|
|
#ifdef ENOSYM
|
|
|
|
E(ENOSYM),
|
|
|
|
#endif
|
|
|
|
E(ENOSYS),
|
|
|
|
E(ENOTBLK),
|
|
|
|
E(ENOTCONN),
|
|
|
|
E(ENOTDIR),
|
|
|
|
E(ENOTEMPTY),
|
|
|
|
E(ENOTNAM),
|
|
|
|
E(ENOTRECOVERABLE),
|
|
|
|
E(ENOTSOCK),
|
|
|
|
E(ENOTTY),
|
|
|
|
E(ENOTUNIQ),
|
|
|
|
E(ENXIO),
|
|
|
|
E(EOPNOTSUPP),
|
|
|
|
E(EOVERFLOW),
|
|
|
|
E(EOWNERDEAD),
|
|
|
|
E(EPERM),
|
|
|
|
E(EPFNOSUPPORT),
|
|
|
|
E(EPIPE),
|
|
|
|
#ifdef EPROCLIM
|
|
|
|
E(EPROCLIM),
|
|
|
|
#endif
|
|
|
|
E(EPROTO),
|
|
|
|
E(EPROTONOSUPPORT),
|
|
|
|
E(EPROTOTYPE),
|
|
|
|
E(ERANGE),
|
|
|
|
E(EREMCHG),
|
|
|
|
#ifdef EREMDEV
|
|
|
|
E(EREMDEV),
|
|
|
|
#endif
|
|
|
|
E(EREMOTE),
|
|
|
|
E(EREMOTEIO),
|
|
|
|
#ifdef EREMOTERELEASE
|
|
|
|
E(EREMOTERELEASE),
|
|
|
|
#endif
|
|
|
|
E(ERESTART),
|
|
|
|
E(ERFKILL),
|
|
|
|
E(EROFS),
|
|
|
|
#ifdef ERREMOTE
|
|
|
|
E(ERREMOTE),
|
|
|
|
#endif
|
|
|
|
E(ESHUTDOWN),
|
|
|
|
E(ESOCKTNOSUPPORT),
|
|
|
|
E(ESPIPE),
|
|
|
|
E(ESRCH),
|
|
|
|
E(ESRMNT),
|
|
|
|
E(ESTALE),
|
|
|
|
E(ESTRPIPE),
|
|
|
|
E(ETIME),
|
|
|
|
E(ETIMEDOUT),
|
|
|
|
E(ETOOMANYREFS),
|
|
|
|
E(ETXTBSY),
|
|
|
|
E(EUCLEAN),
|
|
|
|
E(EUNATCH),
|
|
|
|
E(EUSERS),
|
|
|
|
E(EXDEV),
|
|
|
|
E(EXFULL),
|
|
|
|
|
|
|
|
E(ECANCELED), /* ECANCELLED */
|
|
|
|
E(EAGAIN), /* EWOULDBLOCK */
|
|
|
|
E(ECONNREFUSED), /* EREFUSED */
|
|
|
|
E(EDEADLK), /* EDEADLOCK */
|
|
|
|
};
|
|
|
|
#undef E
|
|
|
|
|
|
|
|
#define E(err) [err - 512 + BUILD_BUG_ON_ZERO(err < 512 || err > 550)] = "-" #err
|
|
|
|
static const char *names_512[] = {
|
|
|
|
E(ERESTARTSYS),
|
|
|
|
E(ERESTARTNOINTR),
|
|
|
|
E(ERESTARTNOHAND),
|
|
|
|
E(ENOIOCTLCMD),
|
|
|
|
E(ERESTART_RESTARTBLOCK),
|
|
|
|
E(EPROBE_DEFER),
|
|
|
|
E(EOPENSTALE),
|
|
|
|
E(ENOPARAM),
|
|
|
|
|
|
|
|
E(EBADHANDLE),
|
|
|
|
E(ENOTSYNC),
|
|
|
|
E(EBADCOOKIE),
|
|
|
|
E(ENOTSUPP),
|
|
|
|
E(ETOOSMALL),
|
|
|
|
E(ESERVERFAULT),
|
|
|
|
E(EBADTYPE),
|
|
|
|
E(EJUKEBOX),
|
|
|
|
E(EIOCBQUEUED),
|
|
|
|
E(ERECALLCONFLICT),
|
|
|
|
};
|
|
|
|
#undef E
|
|
|
|
|
|
|
|
static const char *__errname(unsigned err)
|
|
|
|
{
|
|
|
|
if (err < ARRAY_SIZE(names_0))
|
|
|
|
return names_0[err];
|
|
|
|
if (err >= 512 && err - 512 < ARRAY_SIZE(names_512))
|
|
|
|
return names_512[err - 512];
|
|
|
|
/* But why? */
|
|
|
|
if (IS_ENABLED(CONFIG_MIPS) && err == EDQUOT) /* 1133 */
|
|
|
|
return "-EDQUOT";
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* errname(EIO) -> "EIO"
|
|
|
|
* errname(-EIO) -> "-EIO"
|
|
|
|
*/
|
|
|
|
const char *errname(int err)
|
|
|
|
{
|
|
|
|
const char *name = __errname(abs(err));
|
|
|
|
if (!name)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return err > 0 ? name + 1 : name;
|
|
|
|
}
|