nuttx/libs/libc/string/lib_strerror.c
Zhe Weng d8da8dcc44 libc: Print error code for unknown errors in strerror/gai_strerror
Ref: Linux print unknown errors like "Unknown error nnn"
https://man7.org/linux/man-pages/man3/strerror.3.html#RETURN_VALUE

Note:
These interfaces are called at low freq, so a static buffer may be enough.

Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
2023-04-22 01:46:39 +08:00

412 lines
17 KiB
C

/****************************************************************************
* libs/libc/string/lib_strerror.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define STRERROR_UNKNOWN "Unknown error"
#define STRERROR_BUFSIZE sizeof(STRERROR_UNKNOWN " 2000")
/****************************************************************************
* Private Types
****************************************************************************/
struct errno_strmap_s
{
uint8_t errnum;
FAR char *str;
};
/****************************************************************************
* Private Data
****************************************************************************/
#ifdef CONFIG_LIBC_STRERROR
/* This table maps all error numbers to descriptive strings.
* The only assumption that the code makes with regard to this
* this table is that it is ordered by error number.
*
* The size of this table is quite large. Its size can be
* reduced by eliminating some of the more obscure error
* strings.
*/
#ifndef CONFIG_LIBC_STRERROR_SHORT
static const struct errno_strmap_s g_errnomap[] =
{
{ 0, "Success" },
{ EPERM, EPERM_STR },
{ ENOENT, ENOENT_STR },
{ ESRCH, ESRCH_STR },
{ EINTR, EINTR_STR },
{ EIO, EIO_STR },
{ ENXIO, ENXIO_STR },
{ E2BIG, E2BIG_STR },
{ ENOEXEC, ENOEXEC_STR },
{ EBADF, EBADF_STR },
{ ECHILD, ECHILD_STR },
{ EAGAIN, EAGAIN_STR },
{ ENOMEM, ENOMEM_STR },
{ EACCES, EACCES_STR },
{ EFAULT, EFAULT_STR },
{ ENOTBLK, ENOTBLK_STR },
{ EBUSY, EBUSY_STR },
{ EEXIST, EEXIST_STR },
{ EXDEV, EXDEV_STR },
{ ENODEV, ENODEV_STR },
{ ENOTDIR, ENOTDIR_STR },
{ EISDIR, EISDIR_STR },
{ EINVAL, EINVAL_STR },
{ ENFILE, ENFILE_STR },
{ EMFILE, EMFILE_STR },
{ ENOTTY, ENOTTY_STR },
{ ETXTBSY, ETXTBSY_STR },
{ EFBIG, EFBIG_STR },
{ ENOSPC, ENOSPC_STR },
{ ESPIPE, ESPIPE_STR },
{ EROFS, EROFS_STR },
{ EMLINK, EMLINK_STR },
{ EPIPE, EPIPE_STR },
{ EDOM, EDOM_STR },
{ ERANGE, ERANGE_STR },
{ EDEADLK, EDEADLK_STR },
{ ENAMETOOLONG, ENAMETOOLONG_STR },
{ ENOLCK, ENOLCK_STR },
{ ENOSYS, ENOSYS_STR },
{ ENOTEMPTY, ENOTEMPTY_STR },
{ ELOOP, ELOOP_STR },
{ ENOMSG, ENOMSG_STR },
{ EIDRM, EIDRM_STR },
{ ECHRNG, ECHRNG_STR },
{ EL2NSYNC, EL2NSYNC_STR },
{ EL3HLT, EL3HLT_STR },
{ EL3RST, EL3RST_STR },
{ ELNRNG, ELNRNG_STR },
{ EUNATCH, EUNATCH_STR },
{ ENOCSI, ENOCSI_STR },
{ EL2HLT, EL2HLT_STR },
{ EBADE, EBADE_STR },
{ EBADR, EBADR_STR },
{ EXFULL, EXFULL_STR },
{ ENOANO, ENOANO_STR },
{ EBADRQC, EBADRQC_STR },
{ EBADSLT, EBADSLT_STR },
{ EBFONT, EBFONT_STR },
{ ENOSTR, ENOSTR_STR },
{ ENODATA, ENODATA_STR },
{ ETIME, ETIME_STR },
{ ENOSR, ENOSR_STR },
{ ENONET, ENONET_STR },
{ ENOPKG, ENOPKG_STR },
{ EREMOTE, EREMOTE_STR },
{ ENOLINK, ENOLINK_STR },
{ EADV, EADV_STR },
{ ESRMNT, ESRMNT_STR },
{ ECOMM, ECOMM_STR },
{ EPROTO, EPROTO_STR },
{ EMULTIHOP, EMULTIHOP_STR },
{ EDOTDOT, EDOTDOT_STR },
{ EBADMSG, EBADMSG_STR },
{ EOVERFLOW, EOVERFLOW_STR },
{ ENOTUNIQ, ENOTUNIQ_STR },
{ EBADFD, EBADFD_STR },
{ EREMCHG, EREMCHG_STR },
{ ELIBACC, ELIBACC_STR },
{ ELIBBAD, ELIBBAD_STR },
{ ELIBSCN, ELIBSCN_STR },
{ ELIBMAX, ELIBMAX_STR },
{ ELIBEXEC, ELIBEXEC_STR },
{ EILSEQ, EILSEQ_STR },
{ ERESTART, ERESTART_STR },
{ ESTRPIPE, ESTRPIPE_STR },
{ EUSERS, EUSERS_STR },
{ ENOTSOCK, ENOTSOCK_STR },
{ EDESTADDRREQ, EDESTADDRREQ_STR },
{ EMSGSIZE, EMSGSIZE_STR },
{ EPROTOTYPE, EPROTOTYPE_STR },
{ ENOPROTOOPT, ENOPROTOOPT_STR },
{ EPROTONOSUPPORT, EPROTONOSUPPORT_STR },
{ ESOCKTNOSUPPORT, ESOCKTNOSUPPORT_STR },
{ EOPNOTSUPP, EOPNOTSUPP_STR },
{ EPFNOSUPPORT, EPFNOSUPPORT_STR },
{ EAFNOSUPPORT, EAFNOSUPPORT_STR },
{ EADDRINUSE, EADDRINUSE_STR },
{ EADDRNOTAVAIL, EADDRNOTAVAIL_STR },
{ ENETDOWN, ENETDOWN_STR },
{ ENETUNREACH, ENETUNREACH_STR },
{ ENETRESET, ENETRESET_STR },
{ ECONNABORTED, ECONNABORTED_STR },
{ ECONNRESET, ECONNRESET_STR },
{ ENOBUFS, ENOBUFS_STR },
{ EISCONN, EISCONN_STR },
{ ENOTCONN, ENOTCONN_STR },
{ ESHUTDOWN, ESHUTDOWN_STR },
{ ETOOMANYREFS, ETOOMANYREFS_STR },
{ ETIMEDOUT, ETIMEDOUT_STR },
{ ECONNREFUSED, ECONNREFUSED_STR },
{ EHOSTDOWN, EHOSTDOWN_STR },
{ EHOSTUNREACH, EHOSTUNREACH_STR },
{ EALREADY, EALREADY_STR },
{ EINPROGRESS, EINPROGRESS_STR },
{ ESTALE, ESTALE_STR },
{ EUCLEAN, EUCLEAN_STR },
{ ENOTNAM, ENOTNAM_STR },
{ ENAVAIL, ENAVAIL_STR },
{ EISNAM, EISNAM_STR },
{ EREMOTEIO, EREMOTEIO_STR },
{ EDQUOT, EDQUOT_STR },
{ ENOMEDIUM, ENOMEDIUM_STR },
{ EMEDIUMTYPE, EMEDIUMTYPE_STR },
{ ECANCELED, ECANCELED_STR },
{ ENOKEY, ENOKEY_STR },
{ EKEYEXPIRED, EKEYEXPIRED_STR },
{ EKEYREVOKED, EKEYREVOKED_STR },
{ EKEYREJECTED, EKEYREJECTED_STR },
{ EOWNERDEAD, EOWNERDEAD_STR },
{ ENOTRECOVERABLE, ENOTRECOVERABLE_STR },
{ ERFKILL, ERFKILL_STR },
{ EHWPOISON, EHWPOISON_STR },
{ ELBIN, ELBIN_STR },
{ EFTYPE, EFTYPE_STR },
{ ENMFILE, ENMFILE_STR },
{ EPROCLIM, EPROCLIM_STR },
{ ENOTSUP, ENOTSUP_STR },
{ ENOSHARE, ENOSHARE_STR },
{ ECASECLASH, ECASECLASH_STR },
};
#else /* CONFIG_LIBC_STRERROR_SHORT */
static const struct errno_strmap_s g_errnomap[] =
{
{ 0, "OK" },
{ EPERM, "EPERM" },
{ ENOENT, "ENOENT" },
{ ESRCH, "ESRCH" },
{ EINTR, "EINTR" },
{ EIO, "EIO" },
{ ENXIO, "ENXIO" },
{ E2BIG, "E2BIG" },
{ ENOEXEC, "ENOEXEC" },
{ EBADF, "EBADF" },
{ ECHILD, "ECHILD" },
{ EAGAIN, "EAGAIN" },
{ ENOMEM, "ENOMEM" },
{ EACCES, "EACCES" },
{ EFAULT, "EFAULT" },
{ ENOTBLK, "ENOTBLK" },
{ EBUSY, "EBUSY" },
{ EEXIST, "EEXIST" },
{ EXDEV, "EXDEV" },
{ ENODEV, "ENODEV" },
{ ENOTDIR, "ENOTDIR" },
{ EISDIR, "EISDIR" },
{ EINVAL, "EINVAL" },
{ ENFILE, "ENFILE" },
{ EMFILE, "EMFILE" },
{ ENOTTY, "ENOTTY" },
{ ETXTBSY, "ETXTBSY" },
{ EFBIG, "EFBIG" },
{ ENOSPC, "ENOSPC" },
{ ESPIPE, "ESPIPE" },
{ EROFS, "EROFS" },
{ EMLINK, "EMLINK" },
{ EPIPE, "EPIPE" },
{ EDOM, "EDOM" },
{ ERANGE, "ERANGE" },
{ EDEADLK, "EDEADLK" },
{ ENAMETOOLONG, "ENAMETOOLONG" },
{ ENOLCK, "ENOLCK" },
{ ENOSYS, "ENOSYS" },
{ ENOTEMPTY, "ENOTEMPTY" },
{ ELOOP, "ELOOP" },
{ ENOMSG, "ENOMSG" },
{ EIDRM, "EIDRM" },
{ ECHRNG, "ECHRNG" },
{ EL2NSYNC, "EL2NSYNC" },
{ EL3HLT, "EL3HLT" },
{ EL3RST, "EL3RST" },
{ ELNRNG, "ELNRNG" },
{ EUNATCH, "EUNATCH" },
{ ENOCSI, "ENOCSI" },
{ EL2HLT, "EL2HLT" },
{ EBADE, "EBADE" },
{ EBADR, "EBADR" },
{ EXFULL, "EXFULL" },
{ ENOANO, "ENOANO" },
{ EBADRQC, "EBADRQC" },
{ EBADSLT, "EBADSLT" },
{ EBFONT, "EBFONT" },
{ ENOSTR, "ENOSTR" },
{ ENODATA, "ENODATA" },
{ ETIME, "ETIME" },
{ ENOSR, "ENOSR" },
{ ENONET, "ENONET" },
{ ENOPKG, "ENOPKG" },
{ EREMOTE, "EREMOTE" },
{ ENOLINK, "ENOLINK" },
{ EADV, "EADV" },
{ ESRMNT, "ESRMNT" },
{ ECOMM, "ECOMM" },
{ EPROTO, "EPROTO" },
{ EMULTIHOP, "EMULTIHOP" },
{ EDOTDOT, "EDOTDOT" },
{ EBADMSG, "EBADMSG" },
{ EOVERFLOW, "EOVERFLOW" },
{ ENOTUNIQ, "ENOTUNIQ" },
{ EBADFD, "EBADFD" },
{ EREMCHG, "EREMCHG" },
{ ELIBACC, "ELIBACC" },
{ ELIBBAD, "ELIBBAD" },
{ ELIBSCN, "ELIBSCN" },
{ ELIBMAX, "ELIBMAX" },
{ ELIBEXEC, "ELIBEXEC" },
{ EILSEQ, "EILSEQ" },
{ ERESTART, "ERESTART" },
{ ESTRPIPE, "ESTRPIPE" },
{ EUSERS, "EUSERS" },
{ ENOTSOCK, "ENOTSOCK" },
{ EDESTADDRREQ, "EDESTADDRREQ" },
{ EMSGSIZE, "EMSGSIZE" },
{ EPROTOTYPE, "EPROTOTYPE" },
{ ENOPROTOOPT, "ENOPROTOOPT" },
{ EPROTONOSUPPORT, "EPROTONOSUPPORT" },
{ ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT" },
{ EOPNOTSUPP, "EOPNOTSUPP" },
{ EPFNOSUPPORT, "EPFNOSUPPORT" },
{ EAFNOSUPPORT, "EAFNOSUPPORT" },
{ EADDRINUSE, "EADDRINUSE" },
{ EADDRNOTAVAIL, "EADDRNOTAVAIL" },
{ ENETDOWN, "ENETDOWN" },
{ ENETUNREACH, "ENETUNREACH" },
{ ENETRESET, "ENETRESET" },
{ ECONNABORTED, "ECONNABORTED" },
{ ECONNRESET, "ECONNRESET" },
{ ENOBUFS, "ENOBUFS" },
{ EISCONN, "EISCONN" },
{ ENOTCONN, "ENOTCONN" },
{ ESHUTDOWN, "ESHUTDOWN" },
{ ETOOMANYREFS, "ETOOMANYREFS" },
{ ETIMEDOUT, "ETIMEDOUT" },
{ ECONNREFUSED, "ECONNREFUSED" },
{ EHOSTDOWN, "EHOSTDOWN" },
{ EHOSTUNREACH, "EHOSTUNREACH" },
{ EALREADY, "EALREADY" },
{ EINPROGRESS, "EINPROGRESS" },
{ ESTALE, "ESTALE" },
{ EUCLEAN, "EUCLEAN" },
{ ENOTNAM, "ENOTNAM" },
{ ENAVAIL, "ENAVAIL" },
{ EISNAM, "EISNAM" },
{ EREMOTEIO, "EREMOTEIO" },
{ EDQUOT, "EDQUOT" },
{ ENOMEDIUM, "ENOMEDIUM" },
{ EMEDIUMTYPE, "EMEDIUMTYPE" },
{ ECANCELED, "ECANCELED" },
{ ENOKEY, "ENOKEY" },
{ EKEYEXPIRED, "EKEYEXPIRED" },
{ EKEYREVOKED, "EKEYREVOKED" },
{ EKEYREJECTED, "EKEYREJECTED" },
{ EOWNERDEAD, "EOWNERDEAD" },
{ ENOTRECOVERABLE, "ENOTRECOVERABLE" },
{ ERFKILL, "ERFKILL" },
{ EHWPOISON, "EHWPOISON" },
{ ELBIN, "ELBIN" },
{ EFTYPE, "EFTYPE" },
{ ENMFILE, "ENMFILE" },
{ EPROCLIM, "EPROCLIM" },
{ ENOTSUP, "ENOTSUP" },
{ ENOSHARE, "ENOSHARE" },
{ ECASECLASH, "ECASECLASH" }
};
#endif /* CONFIG_LIBC_STRERROR_SHORT */
#define NERRNO_STRS (sizeof(g_errnomap) / sizeof(struct errno_strmap_s))
#endif /* CONFIG_LIBC_STRERROR */
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: strerror
****************************************************************************/
FAR char *strerror(int errnum)
{
#ifdef CONFIG_LIBC_STRERROR_ERRNUM
static char s_err[STRERROR_BUFSIZE];
#endif
#ifdef CONFIG_LIBC_STRERROR
int ndxlow = 0;
int ndxhi = NERRNO_STRS - 1;
int ndxmid;
do
{
ndxmid = (ndxlow + ndxhi) >> 1;
if (errnum > g_errnomap[ndxmid].errnum)
{
ndxlow = ndxmid + 1;
}
else if (errnum < g_errnomap[ndxmid].errnum)
{
ndxhi = ndxmid - 1;
}
else
{
return g_errnomap[ndxmid].str;
}
}
while (ndxlow <= ndxhi);
#endif
#ifdef CONFIG_LIBC_STRERROR_ERRNUM
if (snprintf(s_err, sizeof(s_err), STRERROR_UNKNOWN " %d", errnum)
< sizeof(s_err))
{
return s_err;
}
#elif !defined(CONFIG_LIBC_STRERROR)
UNUSED(errnum);
#endif
return STRERROR_UNKNOWN;
}