NetworkManager/shared/nm-glib-aux/nm-errno.c
Thomas Haller cd31437024 shared: drop _STATIC variant of macros that define functions
Several macros are used to define function. They had a "_STATIC" variant,
to define the function as static.

I think those macros should not try to abstract entirely what they do.
They should not accept the function scope as argument (or have two
variants per scope). This also because it might make sense to add
additional __attribute__(()) to the function. That only works, if
the macro does not pretend to *not* define a plain function.

Instead, embrace what the function does and let the users place the
function scope as they see fit.

This also follows what is already done with

    static NM_CACHED_QUARK_FCN ("autoconnect-root", autoconnect_root_quark)
2020-02-13 17:17:07 +01:00

184 lines
5.5 KiB
C

// SPDX-License-Identifier: LGPL-2.1+
/*
* Copyright (C) 2018 Red Hat, Inc.
*/
#include "nm-default.h"
#include "nm-errno.h"
#include <pthread.h>
/*****************************************************************************/
static
NM_UTILS_LOOKUP_STR_DEFINE (_geterror,
#if 0
enum _NMErrno,
#else
int,
#endif
NM_UTILS_LOOKUP_DEFAULT (NULL),
NM_UTILS_LOOKUP_STR_ITEM (NME_ERRNO_SUCCESS, "NME_ERRNO_SUCCESS"),
NM_UTILS_LOOKUP_STR_ITEM (NME_ERRNO_OUT_OF_RANGE, "NME_ERRNO_OUT_OF_RANGE"),
NM_UTILS_LOOKUP_STR_ITEM (NME_UNSPEC, "NME_UNSPEC"),
NM_UTILS_LOOKUP_STR_ITEM (NME_BUG, "NME_BUG"),
NM_UTILS_LOOKUP_STR_ITEM (NME_NATIVE_ERRNO, "NME_NATIVE_ERRNO"),
NM_UTILS_LOOKUP_STR_ITEM (NME_NL_ATTRSIZE, "NME_NL_ATTRSIZE"),
NM_UTILS_LOOKUP_STR_ITEM (NME_NL_BAD_SOCK, "NME_NL_BAD_SOCK"),
NM_UTILS_LOOKUP_STR_ITEM (NME_NL_DUMP_INTR, "NME_NL_DUMP_INTR"),
NM_UTILS_LOOKUP_STR_ITEM (NME_NL_MSG_OVERFLOW, "NME_NL_MSG_OVERFLOW"),
NM_UTILS_LOOKUP_STR_ITEM (NME_NL_MSG_TOOSHORT, "NME_NL_MSG_TOOSHORT"),
NM_UTILS_LOOKUP_STR_ITEM (NME_NL_MSG_TRUNC, "NME_NL_MSG_TRUNC"),
NM_UTILS_LOOKUP_STR_ITEM (NME_NL_SEQ_MISMATCH, "NME_NL_SEQ_MISMATCH"),
NM_UTILS_LOOKUP_STR_ITEM (NME_NL_NOADDR, "NME_NL_NOADDR"),
NM_UTILS_LOOKUP_STR_ITEM (NME_PL_NOT_FOUND, "not-found"),
NM_UTILS_LOOKUP_STR_ITEM (NME_PL_EXISTS, "exists"),
NM_UTILS_LOOKUP_STR_ITEM (NME_PL_WRONG_TYPE, "wrong-type"),
NM_UTILS_LOOKUP_STR_ITEM (NME_PL_NOT_SLAVE, "not-slave"),
NM_UTILS_LOOKUP_STR_ITEM (NME_PL_NO_FIRMWARE, "no-firmware"),
NM_UTILS_LOOKUP_STR_ITEM (NME_PL_OPNOTSUPP, "not-supported"),
NM_UTILS_LOOKUP_STR_ITEM (NME_PL_NETLINK, "netlink"),
NM_UTILS_LOOKUP_STR_ITEM (NME_PL_CANT_SET_MTU, "cant-set-mtu"),
NM_UTILS_LOOKUP_ITEM_IGNORE (_NM_ERRNO_MININT),
NM_UTILS_LOOKUP_ITEM_IGNORE (_NM_ERRNO_RESERVED_LAST_PLUS_1),
);
/**
* nm_strerror():
* @nmerr: the NetworkManager specific errno to be converted
* to string.
*
* NetworkManager specific error numbers reserve a range in "errno.h" with
* our own defines. For numbers that don't fall into this range, the numbers
* are identical to the common error numbers.
*
* Idential to strerror(), g_strerror(), nm_strerror_native() for error numbers
* that are not in the reserved range of NetworkManager specific errors.
*
* Returns: (transfer none): the string representation of the error number.
*/
const char *
nm_strerror (int nmerr)
{
const char *s;
nmerr = nm_errno (nmerr);
if (nmerr >= _NM_ERRNO_RESERVED_FIRST) {
s = _geterror (nmerr);
if (s)
return s;
}
return nm_strerror_native (nmerr);
}
/*****************************************************************************/
/**
* nm_strerror_native_r:
* @errsv: the errno to convert to string.
* @buf: the output buffer where to write the string to.
* @buf_size: the length of buffer.
*
* This is like strerror_r(), with one difference: depending on the
* locale, the returned string is guaranteed to be valid UTF-8.
* Also, there is some confusion as to whether to use glibc's
* strerror_r() or the POXIX/XSI variant. This is abstracted
* by the function.
*
* Note that the returned buffer may also be a statically allocated
* buffer, and not the input buffer @buf. Consequently, the returned
* string may be longer than @buf_size.
*
* Returns: (transfer none): a NUL terminated error message. This is either a static
* string (that is never freed), or the provided @buf argumnt.
*/
const char *
nm_strerror_native_r (int errsv, char *buf, gsize buf_size)
{
char *buf2;
nm_assert (buf);
nm_assert (buf_size > 0);
#if (_POSIX_C_SOURCE >= 200112L) && ! _GNU_SOURCE
/* XSI-compliant */
{
int errno_saved = errno;
if (strerror_r (errsv, buf, buf_size) != 0) {
g_snprintf (buf, buf_size, "Unspecified errno %d", errsv);
errno = errno_saved;
}
buf2 = buf;
}
#else
/* GNU-specific */
buf2 = strerror_r (errsv, buf, buf_size);
#endif
/* like g_strerror(), ensure that the error message is UTF-8. */
if ( !g_get_charset (NULL)
&& !g_utf8_validate (buf2, -1, NULL)) {
gs_free char *msg = NULL;
msg = g_locale_to_utf8 (buf2, -1, NULL, NULL, NULL);
if (msg) {
g_strlcpy (buf, msg, buf_size);
buf2 = buf;
}
}
return buf2;
}
/**
* nm_strerror_native:
* @errsv: the errno integer from <errno.h>
*
* Like strerror(), but strerror() is not thread-safe and not guaranteed
* to be UTF-8.
*
* g_strerror() is a thread-safe variant of strerror(), however it caches
* all returned strings in a dictionary. That means, using this on untrusted
* error numbers can result in this cache to grow without limits.
*
* Instead, return a tread-local buffer. This way, it's thread-safe.
*
* There is a downside to this: subsequent calls of nm_strerror_native()
* overwrite the error message.
*
* Returns: (transfer none): the text representation of the error number.
*/
const char *
nm_strerror_native (int errsv)
{
static _nm_thread_local char *buf_static = NULL;
char *buf;
buf = buf_static;
if (G_UNLIKELY (!buf)) {
int errno_saved = errno;
pthread_key_t key;
buf = g_malloc (NM_STRERROR_BUFSIZE);
buf_static = buf;
if ( pthread_key_create (&key, g_free) != 0
|| pthread_setspecific (key, buf) != 0) {
/* Failure. We will leak the buffer when the thread exits.
*
* Nothing we can do about it really. For Debug builds we fail with an assertion. */
nm_assert_not_reached ();
}
errno = errno_saved;
}
return nm_strerror_native_r (errsv, buf, NM_STRERROR_BUFSIZE);
}