# This is always checked (library needs this)
AC_HEADER_STDC
AC_FUNC_MALLOC
-AC_FUNC_STRERROR_R
AC_CHECK_FUNC([ioctl], [], [FUNC_NOT_FOUND_LIB([ioctl])])
AC_CHECK_FUNC([asprintf], [], [FUNC_NOT_FOUND_LIB([asprintf])])
AC_CHECK_FUNC([readdir], [], [FUNC_NOT_FOUND_LIB([readdir])])
*/
#define GPIOD_BIT(nr) (1UL << (nr))
-/**
- * @}
- *
- * @defgroup __error__ Error handling
- * @{
- *
- * Error handling functions and macros. This library uses a combination of
- * system-wide errno numbers and internal GPIO-specific errors. The routines
- * in this section should be used to access the information about any error
- * conditions that may occur.
- *
- * With some noted exceptions, all libgpiod functions set the last error
- * variable if an error occurs. Internally, the last_error variable has a
- * separate instance per thread making the library thread-safe.
- */
-
-/**
- * @brief Private: offset for all libgpiod error numbers.
- */
-#define _GPIOD_ERRNO_OFFSET 10000
-
-/**
- * @brief libgpiod-specific error numbers.
- */
-enum {
- GPIOD_ESUCCESS = _GPIOD_ERRNO_OFFSET,
- /**< No error. */
- GPIOD_EREQUEST,
- /**< The caller has no ownership of this line. */
- GPIOD_EEVREQUEST,
- /**< The caller has not configured any events on this line. */
- GPIOD_EBULKINCOH,
- /**< Not all lines in bulk belong to the same GPIO chip. */
- GPIOD_ELINEBUSY,
- /**< This line is currently in use. */
- GPIOD_ELINEMAX,
- /**< Number of lines in the request exceeds limit. */
- _GPIOD_MAX_ERR,
- /**< Private: number of libgpiod-specific error numbers. */
-};
-
-/**
- * @brief Return last error.
- * @return Number of the last error inside libgpiod.
- */
-int gpiod_errno(void) GPIOD_API;
-
-/**
- * @brief Convert error number to a human-readable string.
- * @param errnum Error number to convert.
- * @return Pointer to a null-terminated error description.
- */
-const char * gpiod_strerror(int errnum) GPIOD_API;
-
-/**
- * @brief Convert the last libgpiod error number to a human-readable string.
- * @return Pointer to a null-terminated error description.
- */
-const char * gpiod_last_strerror(void) GPIOD_API;
-
/**
* @}
*
static const char dev_dir[] = "/dev/";
static const char cdev_prefix[] = "gpiochip";
-/*
- * The longest error message in glibc is about 50 characters long so 64 should
- * be enough to store every error message in the future too.
- */
-#define ERRSTR_MAX 64
-
-static __thread int last_error;
-static __thread char errmsg[ERRSTR_MAX];
-
-static const char *const error_descr[] = {
- "success",
- "GPIO line not reserved",
- "no events configured on GPIO line",
- "GPIO lines in bulk don't belong to the same gpiochip",
- "GPIO line currently in use",
- "number of lines in the request exceeds limit",
-};
-
-static void set_last_error(int errnum)
-{
- last_error = errnum;
-}
-
-static void last_error_from_errno(void)
-{
- last_error = errno;
-}
-
static MALLOC void * zalloc(size_t size)
{
void *ptr;
ptr = malloc(size);
- if (!ptr) {
- set_last_error(ENOMEM);
- return NULL;
- }
-
- memset(ptr, 0, size);
+ if (ptr)
+ memset(ptr, 0, size);
return ptr;
}
static int gpio_ioctl(int fd, unsigned long request, void *data)
{
- int status;
-
- status = ioctl(fd, request, data);
- if (status < 0) {
- last_error_from_errno();
- return -1;
- }
-
- return 0;
-}
-
-int gpiod_errno(void)
-{
- return last_error;
-}
-
-static const char * strerror_r_wrapper(int errnum, char *buf, size_t buflen)
-{
-#ifdef STRERROR_R_CHAR_P
- return strerror_r(errnum, buf, buflen);
-#else
- int status;
-
- status = strerror_r(errnum, buf, buflen);
- if (status != 0)
- snprintf(buf, buflen, "error in strerror_r(): %d", status);
-
- return buf;
-#endif
-}
-
-const char * gpiod_strerror(int errnum)
-{
- if (errnum < _GPIOD_ERRNO_OFFSET)
- return strerror_r_wrapper(errnum, errmsg, sizeof(errmsg));
- else if (errnum > _GPIOD_MAX_ERR)
- return "invalid error number";
- else
- return error_descr[errnum - _GPIOD_ERRNO_OFFSET];
-}
-
-const char * gpiod_last_strerror(void)
-{
- return gpiod_strerror(gpiod_errno());
+ return ioctl(fd, request, data);
}
int gpiod_simple_get_value_multiple(const char *consumer, const char *device,
int status;
if (num_lines > GPIOD_REQUEST_MAX_LINES) {
- set_last_error(GPIOD_ELINEMAX);
+ errno = EINVAL;
return -1;
}
int status;
if (num_lines > GPIOD_REQUEST_MAX_LINES) {
- set_last_error(GPIOD_ELINEMAX);
+ errno = EINVAL;
return -1;
}
for (;;) {
status = gpiod_line_event_wait(line, timeout);
if (status < 0) {
- if (gpiod_errno() == EINTR)
+ if (errno == EINTR)
return evtype = GPIOD_EVENT_CB_TIMEOUT;
else
goto out;
line = bulk->lines[i];
if (i > 0 && chip != gpiod_line_get_chip(line)) {
- set_last_error(GPIOD_EBULKINCOH);
+ errno = EINVAL;
return false;
}
if (!gpiod_line_is_free(line)) {
- set_last_error(GPIOD_ELINEBUSY);
+ errno = EBUSY;
return false;
}
}
if (!line_bulk_is_reserved(bulk) &&
!line_bulk_is_event_configured(bulk)) {
- set_last_error(GPIOD_EREQUEST);
+ errno = EPERM;
return -1;
}
int status;
if (!line_bulk_is_reserved(bulk)) {
- set_last_error(GPIOD_EREQUEST);
+ errno = EPERM;
return -1;
}
int status, fd;
if (!gpiod_line_is_free(line)) {
- set_last_error(GPIOD_ELINEBUSY);
+ errno = EBUSY;
return -1;
}
int status;
if (!line_bulk_is_event_configured(bulk)) {
- set_last_error(GPIOD_EEVREQUEST);
+ errno = EPERM;
return -1;
}
}
status = ppoll(fds, bulk->num_lines, timeout, NULL);
- if (status < 0) {
- last_error_from_errno();
+ if (status < 0)
return -1;
- } else if (status == 0) {
+ else if (status == 0)
return 0;
- }
for (i = 0; !fds[i].revents; i++);
if (line)
int fd;
if (!gpiod_line_event_configured(line)) {
- set_last_error(GPIOD_EEVREQUEST);
+ errno = EPERM;
return -1;
}
rd = read(fd, &evdata, sizeof(evdata));
if (rd < 0) {
- last_error_from_errno();
return -1;
} else if (rd != sizeof(evdata)) {
- set_last_error(EIO);
+ errno = EIO;
return -1;
}
int status, fd;
fd = open(path, O_RDWR | O_CLOEXEC);
- if (fd < 0) {
- last_error_from_errno();
+ if (fd < 0)
return NULL;
- }
chip = zalloc(sizeof(*chip));
if (!chip) {
int status;
status = asprintf(&path, "%s%s", dev_dir, name);
- if (status < 0) {
- last_error_from_errno();
+ if (status < 0)
return NULL;
- }
chip = gpiod_chip_open(path);
free(path);
int status;
status = asprintf(&path, "%s%s%u", dev_dir, cdev_prefix, num);
- if (!status) {
- last_error_from_errno();
+ if (!status)
return NULL;
- }
chip = gpiod_chip_open(path);
free(path);
int status;
if (offset >= chip->cinfo.lines) {
- set_last_error(EINVAL);
+ errno = EINVAL;
return NULL;
}
return NULL;
new->dir = opendir(dev_dir);
- if (!new->dir) {
- last_error_from_errno();
+ if (!new->dir)
return NULL;
- }
new->state = CHIP_ITER_INIT;
#include <string.h>
#include <stdarg.h>
#include <libgen.h>
+#include <errno.h>
#define NORETURN __attribute__((noreturn))
va_start(va, fmt);
fprintf(stderr, "%s: ", progname);
vfprintf(stderr, fmt, va);
- fprintf(stderr, ": %s\n", gpiod_last_strerror());
+ fprintf(stderr, ": %s\n", strerror(errno));
va_end(va);
exit(EXIT_FAILURE);
chip = gpiod_chip_open("/dev/nonexistent_gpiochip");
TEST_ASSERT_NULL(chip);
- TEST_ASSERT_EQ(gpiod_errno(), ENOENT);
+ TEST_ASSERT_EQ(errno, ENOENT);
}
TEST_DEFINE(chip_open_nonexistent,
"gpiod_chip_open() - nonexistent chip",
chip = gpiod_chip_open("/dev/null");
TEST_ASSERT_NULL(chip);
- TEST_ASSERT_EQ(gpiod_errno(), ENOTTY);
+ TEST_ASSERT_EQ(errno, ENOTTY);
}
TEST_DEFINE(chip_open_notty,
"gpiod_chip_open() - notty",
#include "gpiod-test.h"
+#include <errno.h>
+
static void line_request_output(void)
{
TEST_CLEANUP(test_close_chip) struct gpiod_chip *chip = NULL;
status = gpiod_line_request_input(line, TEST_CONSUMER, false);
TEST_ASSERT_NOTEQ(status, 0);
- TEST_ASSERT_EQ(gpiod_errno(), GPIOD_ELINEBUSY);
+ TEST_ASSERT_EQ(errno, EBUSY);
}
TEST_DEFINE(line_request_already_requested,
"gpiod_line_request() - already requested",
status = gpiod_line_request_bulk(&bulk, &req, NULL);
TEST_ASSERT_NOTEQ(status, 0);
- TEST_ASSERT_EQ(gpiod_errno(), GPIOD_EBULKINCOH);
+ TEST_ASSERT_EQ(errno, EINVAL);
}
TEST_DEFINE(line_request_bulk_different_chips,
"gpiod_line_request_bulk() - different chips",
TEST_DEFINE(version_string,
"gpiod_version_string()",
0, { });
-
-static void error_handling(void)
-{
- struct gpiod_chip *chip;
- int err;
-
- chip = gpiod_chip_open("/dev/nonexistent_gpiochip");
- TEST_ASSERT_NULL(chip);
-
- err = gpiod_errno();
- TEST_ASSERT_EQ(err, ENOENT);
-
- TEST_ASSERT_NOT_NULL(gpiod_strerror(err));
- TEST_ASSERT(strlen(gpiod_strerror(err)) > 0);
- TEST_ASSERT_STR_EQ(gpiod_strerror(err), gpiod_last_strerror());
-}
-TEST_DEFINE(error_handling,
- "error handling",
- 0, { });
#include "gpiod-test.h"
+#include <errno.h>
+
static void simple_set_get_value(void)
{
int ret;
GPIOD_REQUEST_MAX_LINES + 1,
false);
TEST_ASSERT_NOTEQ(ret, 0);
- TEST_ASSERT_EQ(gpiod_errno(), GPIOD_ELINEMAX);
+ TEST_ASSERT_EQ(errno, EINVAL);
}
TEST_DEFINE(simple_get_value_multiple_max_lines,
"gpiod_simple_get_value_multiple() exceed max lines",
GPIOD_REQUEST_MAX_LINES + 1,
false, NULL, NULL);
TEST_ASSERT_NOTEQ(ret, 0);
- TEST_ASSERT_EQ(gpiod_errno(), GPIOD_ELINEMAX);
+ TEST_ASSERT_EQ(errno, EINVAL);
}
TEST_DEFINE(simple_set_value_multiple_max_lines,
"gpiod_simple_set_value_multiple() exceed max lines",