Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751371AbdFYRMk (ORCPT ); Sun, 25 Jun 2017 13:12:40 -0400 Received: from zimbra.gr13.net ([46.4.151.110]:58134 "EHLO zimbra.gr13.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751186AbdFYRMi (ORCPT ); Sun, 25 Jun 2017 13:12:38 -0400 From: "Enrico Weigelt, metux IT consult" To: linux-kernel@vger.kernel.org Subject: [PATCH] lib: vsprintf: add printf format conversion %M for errno strings Date: Sun, 25 Jun 2017 19:12:30 +0200 Message-Id: <20170625171230.7613-1-enrico.weigelt@gr13.net> X-Mailer: git-send-email 2.11.0.rc0.7.gbe5a750 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 9962 Lines: 252 Adding a new format conversion for *printf() and friends. If CONFIG_ERRNO_PRINTF_VERBOSE is enabled, prints human-readable strerror()-like texts, otherwise just the number. --- lib/Kconfig | 19 +++++++ lib/vsprintf.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 189 insertions(+), 2 deletions(-) diff --git a/lib/Kconfig b/lib/Kconfig index 0c8b78a9ae2e..b28ab2162435 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -7,6 +7,25 @@ config BINARY_PRINTF menu "Library routines" +config ERRNO_PRINTF + bool "printf conversion %M for errno codes" + default n + help + This option adds an %M modifier for *printf() for errno values. + (and callers like printk() etc) + + In conjunction with ERRNO_PRINTF_VERBOSE, it prints human readable + strerror()-like textsm, otherwise just numeric values + +config ERRNO_PRINTF_VERBOSE + bool "Verbose errno strings" + default y + depends on ERRNO_PRINTF + help + Enable verbose error strings for ERRNO_PRINTF. + + Small embedded systems might disable it for reducing kernel size. + config RAID6_PQ tristate diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 2d41de3f98a1..9778e17fc178 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -382,7 +382,8 @@ enum format_type { FORMAT_TYPE_UINT, FORMAT_TYPE_INT, FORMAT_TYPE_SIZE_T, - FORMAT_TYPE_PTRDIFF + FORMAT_TYPE_PTRDIFF, + FORMAT_TYPE_ERRNO, }; struct printf_spec { @@ -600,6 +601,164 @@ char *string(char *buf, char *end, const char *s, struct printf_spec spec) return widen_string(buf, len, end, spec); } +#if IS_ENABLED(CONFIG_ERRNO_PRINTF_VERBOSE) +static noinline_for_stack +const char *errno_to_str(int no) +{ + switch (no) { + case 0: return "Success"; + case EPERM: return "Operation not permitted"; + case ENOENT: return "No such file or directory"; + case ESRCH: return "No such process"; + case EINTR: return "Interrupted system call"; + case EIO: return "I/O error"; + case ENXIO: return "No such device or address"; + case E2BIG: return "Argument list too long"; + case ENOEXEC: return "Exec format error"; + case EBADF: return "Bad file number"; + case ECHILD: return "No child processes"; + case EAGAIN: return "Try again"; + case ENOMEM: return "Out of memory"; + case EACCES: return "Permission denied"; + case EFAULT: return "Bad address"; + case ENOTBLK: return "Block device required"; + case EBUSY: return "Device or resource busy"; + case EEXIST: return "File exists"; + case EXDEV: return "Cross-device link"; + case ENODEV: return "No such device"; + case ENOTDIR: return "Not a directory"; + case EISDIR: return "Is a directory"; + case EINVAL: return "Invalid argument"; + case ENFILE: return "File table overflow"; + case EMFILE: return "Too many open files"; + case ENOTTY: return "Not a typewriter"; + case ETXTBSY: return "Text file busy"; + case EFBIG: return "File too large"; + case ENOSPC: return "No space left on device"; + case ESPIPE: return "Illegal seek"; + case EROFS: return "Read-only file system"; + case EMLINK: return "Too many links"; + case EPIPE: return "Broken pipe"; + case EDOM: return "Math argument out of domain of func"; + case ERANGE: return "Math result not representable"; + case EDEADLK: return "Resource deadlock would occur"; + case ENAMETOOLONG: return "File name too long"; + case ENOLCK: return "No record locks available"; + case ENOSYS: return "Invalid system call number"; + case ENOTEMPTY: return "Directory not empty"; + case ELOOP: return "Too many symbolic links encountered"; + case ENOMSG: return "No message of desired type"; + case EIDRM: return "Identifier removed"; + case ECHRNG: return "Channel number out of range"; + case EL2NSYNC: return "Level 2 not synchronized"; + case EL3HLT: return "Level 3 halted"; + case EL3RST: return "Level 3 reset"; + case ELNRNG: return "Link number out of range"; + case EUNATCH: return "Protocol driver not attached"; + case ENOCSI: return "No CSI structure available"; + case EL2HLT: return "Level 2 halted"; + case EBADE: return "Invalid exchange"; + case EBADR: return "Invalid request descriptor"; + case EXFULL: return "Exchange full"; + case ENOANO: return "No anode"; + case EBADRQC: return "Invalid request code"; + case EBADSLT: return "Invalid slot"; + case EBFONT: return "Bad font file format"; + case ENOSTR: return "Device not a stream"; + case ENODATA: return "No data available"; + case ETIME: return "Timer expired"; + case ENOSR: return "Out of streams resources"; + case ENONET: return "Machine is not on the network"; + case ENOPKG: return "Package not installed"; + case EREMOTE: return "Object is remote"; + case ENOLINK: return "Link has been severed"; + case EADV: return "Advertise error"; + case ESRMNT: return "Srmount error"; + case ECOMM: return "Communication error on send"; + case EPROTO: return "Protocol error"; + case EMULTIHOP: return "Multihop attempted"; + case EDOTDOT: return "RFS specific error"; + case EBADMSG: return "Not a data message"; + case EOVERFLOW: return "Value too large for defined data type"; + case ENOTUNIQ: return "Name not unique on network"; + case EBADFD: return "File descriptor in bad state"; + case EREMCHG: return "Remote address changed"; + case ELIBACC: return "Can not access a needed shared library"; + case ELIBBAD: return "Accessing a corrupted shared library"; + case ELIBSCN: return ".lib section in a.out corrupted"; + case ELIBMAX: return "Attempting to link in too many shared libraries"; + case ELIBEXEC: return "Cannot exec a shared library directly"; + case EILSEQ: return "Illegal byte sequence"; + case ERESTART: return "Interrupted system call should be restarted"; + case ESTRPIPE: return "Streams pipe error"; + case EUSERS: return "Too many users"; + case EDESTADDRREQ: return "Destination address required"; + case EMSGSIZE: return "Message too long"; + case EPROTOTYPE: return "Protocol wrong type for socket"; + case ENOPROTOOPT: return "Protocol not available"; + case EPROTONOSUPPORT: return "Protocol not supported"; + case ESOCKTNOSUPPORT: return "Socket type not supported"; + case EOPNOTSUPP: return "Operation not supported on transport endpoint"; + case EPFNOSUPPORT: return "Protocol family not supported"; + case EAFNOSUPPORT: return "Address family not supported by protocol"; + case EADDRINUSE: return "Address already in use"; + case EADDRNOTAVAIL: return "Cannot assign requested address"; + case ENETDOWN: return "Network is down"; + case ENETUNREACH: return "Network is unreachable"; + case ENETRESET: return "Network dropped connection because of reset"; + case ECONNABORTED: return "Software caused connection abort"; + case ECONNRESET: return "Connection reset by peer"; + case ENOBUFS: return "No buffer space available"; + case EISCONN: return "Transport endpoint is already connected"; + case ENOTCONN: return "Transport endpoint is not connected"; + case ESHUTDOWN: return "Cannot send after transport endpoint shutdown"; + case ETOOMANYREFS: return "Too many references: cannot splice"; + case ETIMEDOUT: return "Connection timed out"; + case ECONNREFUSED: return "Connection refused"; + case EHOSTDOWN: return "Host is down"; + case EHOSTUNREACH: return "No route to host"; + case EALREADY: return "Operation already in progress"; + case EINPROGRESS: return "Operation now in progress"; + case ESTALE: return "Stale file handle"; + case EUCLEAN: return "Structure needs cleaning"; + case ENOTNAM: return "Not a XENIX named type file"; + case ENAVAIL: return "No XENIX semaphores available"; + case EISNAM: return "Is a named type file"; + case EREMOTEIO: return "Remote I/O error"; + case EDQUOT: return "Quota exceeded"; + case ENOMEDIUM: return "No medium found"; + case EMEDIUMTYPE: return "Wrong medium type"; + case ECANCELED: return "Operation Canceled"; + case ENOKEY: return "Required key not available"; + case EKEYEXPIRED: return "Key has expired"; + case EKEYREVOKED: return "Key has been revoked"; + case EKEYREJECTED: return "Key was rejected by service"; + case EOWNERDEAD: return "Owner died"; + case ENOTRECOVERABLE: return "State not recoverable"; + case ERFKILL: return "Operation not possible due to RF-kill"; + case EHWPOISON: return "Memory page has hardware error"; + } + return NULL; +} +#endif + +#if IS_ENABLED(CONFIG_ERRNO_PRINTF) +static noinline_for_stack +char *errno_string(char *buf, char *end, int errcode, struct printf_spec spec) +{ + char buffer[32]; + +#if IS_ENABLED(CONFIG_ERRNO_PRINTF_VERBOSE) + const char *estr = errno_to_str(errcode); + if (estr != NULL) + return string(buf, end, estr, spec); +#endif + + snprintf(buffer, sizeof(buffer), "error %d", errcode); + return string(buf, end, buffer, spec); +} +#endif + static noinline_for_stack char *dentry_name(char *buf, char *end, const struct dentry *d, struct printf_spec spec, const char *fmt) @@ -1744,6 +1903,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, * 'z' changed to 'Z' --davidm 1/25/99 * 'Z' changed to 'z' --adobriyan 2017-01-25 * 't' added for ptrdiff_t + * 'M' added for strerror()-like output --mtx 2017-06-25 * * @fmt: the format string * @type of the token returned @@ -1866,6 +2026,10 @@ int format_decode(const char *fmt, struct printf_spec *spec) spec->type = FORMAT_TYPE_STR; return ++fmt - start; + case 'M': + spec->type = FORMAT_TYPE_ERRNO; + return ++fmt - start; + case 'p': spec->type = FORMAT_TYPE_PTR; return ++fmt - start; @@ -2047,7 +2211,11 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) case FORMAT_TYPE_STR: str = string(str, end, va_arg(args, char *), spec); break; - +#if IS_ENABLED(CONFIG_ERRNO_PRINTF) + case FORMAT_TYPE_ERRNO: + str = errno_string(str, end, va_arg(args, int), spec); + break; +#endif case FORMAT_TYPE_PTR: str = pointer(fmt, str, end, va_arg(args, void *), spec); -- 2.11.0.rc0.7.gbe5a750