NetworkManager/shared/nm-utils/nm-errno.h

186 lines
5.9 KiB
C
Raw Normal View History

/* NetworkManager -- Network link manager
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright 2018 Red Hat, Inc.
*/
#ifndef __NM_ERRNO_H__
#define __NM_ERRNO_H__
#include <errno.h>
/*****************************************************************************/
enum _NMErrno {
_NM_ERRNO_MININT = G_MININT,
_NM_ERRNO_MAXINT = G_MAXINT,
_NM_ERRNO_RESERVED_FIRST = 100000,
/* when we cannot represent a number as positive number, we resort to this
* number. Basically, the values G_MININT, -NME_ERRNO_SUCCESS, NME_ERRNO_SUCCESS
* and G_MAXINT all map to the same value. */
NME_ERRNO_OUT_OF_RANGE = G_MAXINT,
/* Indicate that the original errno was zero. Zero denotes *no error*, but we know something
* went wrong and we want to report some error. This is a placeholder to mean, something
* was wrong, but errno was zero. */
NME_ERRNO_SUCCESS = G_MAXINT - 1,
/* an unspecified error. */
NME_UNSPEC = _NM_ERRNO_RESERVED_FIRST,
/* A bug, for example when an assertion failed.
* Should never happen. */
NME_BUG,
/* a native error number (from <errno.h>) cannot be mapped as
* an nm-error, because it is in the range [_NM_ERRNO_RESERVED_FIRST,
* _NM_ERRNO_RESERVED_LAST]. */
NME_NATIVE_ERRNO,
/* netlink errors. */
NME_NL_SEQ_MISMATCH,
NME_NL_MSG_TRUNC,
NME_NL_MSG_TOOSHORT,
NME_NL_DUMP_INTR,
NME_NL_ATTRSIZE,
NME_NL_BAD_SOCK,
NME_NL_NOADDR,
NME_NL_MSG_OVERFLOW,
/* platform errors. */
NME_PL_NOT_FOUND,
NME_PL_EXISTS,
NME_PL_WRONG_TYPE,
NME_PL_NOT_SLAVE,
NME_PL_NO_FIRMWARE,
NME_PL_OPNOTSUPP,
NME_PL_NETLINK,
NME_PL_CANT_SET_MTU,
_NM_ERRNO_RESERVED_LAST_PLUS_1,
_NM_ERRNO_RESERVED_LAST = _NM_ERRNO_RESERVED_LAST_PLUS_1 - 1,
};
/*****************************************************************************/
/* When we receive an errno from a system function, we can safely assume
* that the error number is not negative. We rely on that, and possibly just
* "return -errsv;" to signal an error. We also rely on that, because libc
* is our trusted base: meaning, if it cannot even succeed at setting errno
* according to specification, all bets are off.
*
* This macro returns the input argument, and asserts that the error variable
* is positive.
*
* In a sense, the macro is related to nm_errno_native() function, but the difference
* is that this macro asserts that @errsv is positive, while nm_errno_native() coerces
* negative values to be non-negative. */
#define NM_ERRNO_NATIVE(errsv) \
({ \
const int _errsv_x = (errsv); \
\
nm_assert (_errsv_x > 0); \
_errsv_x; \
})
/* Normalize native errno.
*
* Our API may return native error codes (<errno.h>) as negative values. This function
* takes such an errno, and normalizes it to their positive value.
*
* The special values G_MININT and zero are coerced to NME_ERRNO_OUT_OF_RANGE and NME_ERRNO_SUCCESS
* respectively.
* Other values are coerced to their inverse.
* Other positive values are returned unchanged.
*
* Basically, this normalizes errsv to be positive (taking care of two pathological cases).
*/
static inline int
nm_errno_native (int errsv)
{
switch (errsv) {
case 0: return NME_ERRNO_SUCCESS;
case G_MININT: return NME_ERRNO_OUT_OF_RANGE;
default:
return errsv >= 0 ? errsv : -errsv;
}
}
/* Normalizes an nm-error to be positive.
*
* Various API returns negative error codes, and this function converts the negative
* value to its positive.
*
* Note that @nmerr is on the domain of NetworkManager specific error numbers,
* which is not the same as the native error numbers (errsv from <errno.h>). But
* as far as normalizing goes, nm_errno() does exactly the same remapping as
* nm_errno_native(). */
static inline int
nm_errno (int nmerr)
{
return nm_errno_native (nmerr);
}
/* this maps a native errno to a (always non-negative) nm-error number.
*
* Note that nm-error numbers are embedded into the range of regular
* errno. The only difference is, that nm-error numbers reserve a
* range (_NM_ERRNO_RESERVED_FIRST, _NM_ERRNO_RESERVED_LAST) for their
* own purpose.
*
* That means, converting an errno to nm-error number means in
* most cases just returning itself.
* Only pathological cases need special handling:
*
* - 0 is mapped to NME_ERRNO_SUCCESS;
* - G_MININT is mapped to NME_ERRNO_OUT_OF_RANGE;
* - values in the range of (+/-) [_NM_ERRNO_RESERVED_FIRST, _NM_ERRNO_RESERVED_LAST]
* are mapped to NME_NATIVE_ERRNO
* - all other values are their (positive) absolute value.
*/
static inline int
2018-12-22 13:35:57 +01:00
nm_errno_from_native (int errsv)
{
switch (errsv) {
case 0: return NME_ERRNO_SUCCESS;
case G_MININT: return NME_ERRNO_OUT_OF_RANGE;
default:
if (errsv < 0)
errsv = -errsv;
return G_UNLIKELY ( errsv >= _NM_ERRNO_RESERVED_FIRST
&& errsv <= _NM_ERRNO_RESERVED_LAST)
? NME_NATIVE_ERRNO
: errsv;
}
}
2018-12-22 13:35:57 +01:00
const char *nm_strerror (int nmerr);
/*****************************************************************************/
shared: add nm_strerror_native() to replace strerror() and g_strerror() We have various options for strerror(), with ups and downsides: - strerror() - returns pointer that is overwritten on next call. It's convenient to use, but dangerous. - not thread-safe. - not guaranteed to be UTF-8. - strerror_r() - takes input buffer and is less convenient to use. At least, we are in control of when the buffer gets overwritten. - there is a Posix/XSI and a glibc variant, making it sligthly inconvenient to used. This could be solved by a wrapper we implement. - thread-safe. - not guaranteed to be UTF-8. - g_strerror() - convenient and safe to use. Also the buffer is never released for the remainder of the program. - passing untrusted error numbers to g_strerror() can result in a denial of service, as the internal buffer grows until out-of-memory. - thread-safe. - guaranteed to be UTF-8 (depending on locale). Add our own wrapper nm_strerror_native(). It is: - convenient to use (returning a buffer that does not require management). - slightly dangerous as the buffer gets overwritten on the next call (like strerror()). - thread-safe. - guaranteed to be UTF-8 (depending on locale). - doesn't keep an unlimited cache of strings, unlike g_strerror(). You can't have it all. g_strerror() is leaking all generated error messages. I think that is unacceptable, because it would mean we need to keep track where our error numbers come from (and trust libraries we use to only set a restricted set of known error numbers).
2019-01-31 13:17:26 +01:00
#define NM_STRERROR_BUFSIZE 1024
const char *nm_strerror_native_r (int errsv, char *buf, gsize buf_size);
const char *nm_strerror_native (int errsv);
/*****************************************************************************/
#endif /* __NM_ERRNO_H__ */