Blame src/libnm-systemd-shared/src/basic/errno-util.h

Packit Service dff8e4
/* SPDX-License-Identifier: LGPL-2.1-or-later */
Packit Service dff8e4
#pragma once
Packit Service dff8e4
Packit Service dff8e4
#include <stdlib.h>
Packit Service dff8e4
#include <string.h>
Packit Service dff8e4
Packit Service dff8e4
#include "macro.h"
Packit Service dff8e4
Packit Service dff8e4
static inline void _reset_errno_(int *saved_errno) {
Packit Service dff8e4
        if (*saved_errno < 0) /* Invalidated by UNPROTECT_ERRNO? */
Packit Service dff8e4
                return;
Packit Service dff8e4
Packit Service dff8e4
        errno = *saved_errno;
Packit Service dff8e4
}
Packit Service dff8e4
Packit Service dff8e4
#define PROTECT_ERRNO                                                   \
Packit Service dff8e4
        _cleanup_(_reset_errno_) _unused_ int _saved_errno_ = errno
Packit Service dff8e4
Packit Service dff8e4
#define UNPROTECT_ERRNO                         \
Packit Service dff8e4
        do {                                    \
Packit Service dff8e4
                errno = _saved_errno_;          \
Packit Service dff8e4
                _saved_errno_ = -1;             \
Packit Service dff8e4
        } while (false)
Packit Service dff8e4
Packit Service dff8e4
static inline int negative_errno(void) {
Packit Service dff8e4
        /* This helper should be used to shut up gcc if you know 'errno' is
Packit Service dff8e4
         * negative. Instead of "return -errno;", use "return negative_errno();"
Packit Service dff8e4
         * It will suppress bogus gcc warnings in case it assumes 'errno' might
Packit Service dff8e4
         * be 0 and thus the caller's error-handling might not be triggered. */
Packit Service dff8e4
        assert_return(errno > 0, -EINVAL);
Packit Service dff8e4
        return -errno;
Packit Service dff8e4
}
Packit Service dff8e4
Packit Service dff8e4
static inline const char *strerror_safe(int error) {
Packit Service dff8e4
        /* 'safe' here does NOT mean thread safety. */
Packit Service dff8e4
        return strerror(abs(error));
Packit Service dff8e4
}
Packit Service dff8e4
Packit Service dff8e4
static inline int errno_or_else(int fallback) {
Packit Service dff8e4
        /* To be used when invoking library calls where errno handling is not defined clearly: we return
Packit Service dff8e4
         * errno if it is set, and the specified error otherwise. The idea is that the caller initializes
Packit Service dff8e4
         * errno to zero before doing an API call, and then uses this helper to retrieve a somewhat useful
Packit Service dff8e4
         * error code */
Packit Service dff8e4
        if (errno > 0)
Packit Service dff8e4
                return -errno;
Packit Service dff8e4
Packit Service dff8e4
        return -abs(fallback);
Packit Service dff8e4
}
Packit Service dff8e4
Packit Service dff8e4
/* Hint #1: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5.
Packit Service dff8e4
 *
Packit Service dff8e4
 * Hint #2: The kernel sends e.g., EHOSTUNREACH or ENONET to userspace in some ICMP error cases.  See the
Packit Service dff8e4
 *          icmp_err_convert[] in net/ipv4/icmp.c in the kernel sources.
Packit Service dff8e4
 *
Packit Service dff8e4
 * Hint #3: When asynchronous connect() on TCP fails because the host never acknowledges a single packet,
Packit Service dff8e4
 *          kernel tells us that with ETIMEDOUT, see tcp(7). */
Packit Service dff8e4
static inline bool ERRNO_IS_DISCONNECT(int r) {
Packit Service dff8e4
        return IN_SET(abs(r),
Packit Service dff8e4
                      ECONNABORTED,
Packit Service dff8e4
                      ECONNREFUSED,
Packit Service dff8e4
                      ECONNRESET,
Packit Service dff8e4
                      EHOSTDOWN,
Packit Service dff8e4
                      EHOSTUNREACH,
Packit Service dff8e4
                      ENETDOWN,
Packit Service dff8e4
                      ENETRESET,
Packit Service dff8e4
                      ENETUNREACH,
Packit Service dff8e4
                      ENONET,
Packit Service dff8e4
                      ENOPROTOOPT,
Packit Service dff8e4
                      ENOTCONN,
Packit Service dff8e4
                      EPIPE,
Packit Service dff8e4
                      EPROTO,
Packit Service dff8e4
                      ESHUTDOWN,
Packit Service dff8e4
                      ETIMEDOUT);
Packit Service dff8e4
}
Packit Service dff8e4
Packit Service dff8e4
/* Transient errors we might get on accept() that we should ignore. As per error handling comment in
Packit Service dff8e4
 * the accept(2) man page. */
Packit Service dff8e4
static inline bool ERRNO_IS_ACCEPT_AGAIN(int r) {
Packit Service dff8e4
        return ERRNO_IS_DISCONNECT(r) ||
Packit Service dff8e4
                IN_SET(abs(r),
Packit Service dff8e4
                       EAGAIN,
Packit Service dff8e4
                       EINTR,
Packit Service dff8e4
                       EOPNOTSUPP);
Packit Service dff8e4
}
Packit Service dff8e4
Packit Service dff8e4
/* Resource exhaustion, could be our fault or general system trouble */
Packit Service dff8e4
static inline bool ERRNO_IS_RESOURCE(int r) {
Packit Service dff8e4
        return IN_SET(abs(r),
Packit Service dff8e4
                      EMFILE,
Packit Service dff8e4
                      ENFILE,
Packit Service dff8e4
                      ENOMEM);
Packit Service dff8e4
}
Packit Service dff8e4
Packit Service dff8e4
/* Seven different errors for "operation/system call/ioctl/socket feature not supported" */
Packit Service dff8e4
static inline bool ERRNO_IS_NOT_SUPPORTED(int r) {
Packit Service dff8e4
        return IN_SET(abs(r),
Packit Service dff8e4
                      EOPNOTSUPP,
Packit Service dff8e4
                      ENOTTY,
Packit Service dff8e4
                      ENOSYS,
Packit Service dff8e4
                      EAFNOSUPPORT,
Packit Service dff8e4
                      EPFNOSUPPORT,
Packit Service dff8e4
                      EPROTONOSUPPORT,
Packit Service dff8e4
                      ESOCKTNOSUPPORT);
Packit Service dff8e4
}
Packit Service dff8e4
Packit Service dff8e4
/* Two different errors for access problems */
Packit Service dff8e4
static inline bool ERRNO_IS_PRIVILEGE(int r) {
Packit Service dff8e4
        return IN_SET(abs(r),
Packit Service dff8e4
                      EACCES,
Packit Service dff8e4
                      EPERM);
Packit Service dff8e4
}
Packit Service dff8e4
Packit Service dff8e4
/* Three difference errors for "not enough disk space" */
Packit Service dff8e4
static inline bool ERRNO_IS_DISK_SPACE(int r) {
Packit Service dff8e4
        return IN_SET(abs(r),
Packit Service dff8e4
                      ENOSPC,
Packit Service dff8e4
                      EDQUOT,
Packit Service dff8e4
                      EFBIG);
Packit Service dff8e4
}