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.
This commit is contained in:
@@ -24,9 +24,17 @@
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
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_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"),
|
||||
@@ -38,6 +46,7 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_geterror, int,
|
||||
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"),
|
||||
@@ -47,6 +56,9 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_geterror, int,
|
||||
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,43 +80,64 @@ 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);
|
||||
}
|
||||
|
||||
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
|
||||
@@ -113,20 +146,28 @@ nm_errno_from_native (int errsv)
|
||||
* 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;
|
||||
}
|
||||
* 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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)); \
|
||||
})))
|
||||
|
Reference in New Issue
Block a user