Commit 67130e67 authored by Thomas Haller's avatar Thomas Haller

shared: cleanup separation and transition between errno and nmerr numbers

The native error numbers (from <errno.h>) and our nmerr extention on top
of them are almost the same. But there are peculiarities.

Both errno and nmerr must be positive values. That is because some API
(systemd) like to return negative error codes. So, a positive errno and
its negative counter part indicate the same error. We need normalization
functions that make an error number positive (these are nm_errno() and
nm_errno_native()).

This means, G_MININT needs special treatment, because it cannot be
represented as a positive integer. Also, zero needs special
treatment, because we want to encode an error, and zero already encodes
no-error. Take care of these special cases.

On top of that, nmerr reserves a range within native error numbers for
NetworkManager specific failure codes. So we need to transition from native
numbers to nmerr numbers via nm_errno_from_native().

Take better care of some special cases and clean them up.

Also add NM_ERRNO_NATIVE() macro. While nm_errno_native() coerces a
value in the suitable range, NM_ERRNO_NATIVE() asserts that the number
is already positive (and returns it as-is). It's use is only for
asserting and implicitly documenting the requirements we have on the
number passed to it.
parent 89d3c524
......@@ -24,29 +24,41 @@
/*****************************************************************************/
NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_geterror, int,
NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_geterror,
#if 0
enum _NMErrno,
#else
int,
#endif
NM_UTILS_LOOKUP_DEFAULT (NULL),
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_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_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_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_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_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),
);
const char *
......
......@@ -25,11 +25,23 @@
/*****************************************************************************/
enum {
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,
......@@ -68,64 +80,93 @@ enum {
/*****************************************************************************/
/* 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)
{
/* several API returns negative errno values as errors. Normalize
* negative values to positive values.
*
* As a special case, map G_MININT to G_MAXINT. If you care about the
* distinction, then check for G_MININT before.
*
* Basically, this normalizes a plain errno to be non-negative. */
return errsv >= 0
? errsv
: ((errsv == G_MININT) ? G_MAXINT : -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)
{
/* Normalizes an nm-error to be positive. Various API returns negative
* error codes, and this function converts the negative value to its
* positive.
*
* It's very similar to nm_errno_native(), but not exactly. The difference is that
* nm_errno_native() is for plain errno, while nm_errno() is for nm-error numbers.
* Yes, nm-error number are ~almost~ the same as errno, except that a particular
* range (_NM_ERRNO_RESERVED_FIRST, _NM_ERRNO_RESERVED_LAST) is reserved. The difference
* between the two functions is only how G_MININT is mapped.
*
* See also nm_errno_from_native() below. */
return nmerr >= 0
? nmerr
: ((nmerr == G_MININT) ? NME_BUG : -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
nm_errno_from_native (int errsv)
{
/* 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 (negative values are normalized
* to be positive). Only values G_MININT and [_NM_ERRNO_RESERVED_FIRST, _NM_ERRNO_RESERVED_LAST]
* are coerced to the special value NME_NATIVE_ERRNO, as they cannot
* otherwise be represented in nm-error number domain. */
if (errsv < 0) {
if (G_UNLIKELY (errsv == G_MININT))
return NME_NATIVE_ERRNO;
errsv = -errsv;
switch (errsv) {
case 0: return NME_ERRNO_SUCCESS;
case G_MININT: return NME_ERRNO_OUT_OF_RANGE;
default:
return G_UNLIKELY ( errsv >= _NM_ERRNO_RESERVED_FIRST
&& errsv <= _NM_ERRNO_RESERVED_LAST)
? NME_NATIVE_ERRNO
: errsv;
}
return G_UNLIKELY ( errsv >= _NM_ERRNO_RESERVED_FIRST
&& errsv <= _NM_ERRNO_RESERVED_LAST)
? NME_NATIVE_ERRNO
: errsv;
}
const char *nm_strerror (int nmerr);
......
......@@ -710,7 +710,7 @@ nm_utils_error_set_literal (GError **error, int error_code, const char *literal)
\
( _errsv >= 0 \
? _errsv \
: ( (_errsv == G_MININT) \
: ( G_UNLIKELY (_errsv == G_MININT) \
? G_MAXINT \
: -errsv)); \
})))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment