From 18f280a478ae85307b4597f7ccd588c860edf42c Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 19 Nov 2025 04:46:25 +0900 Subject: [PATCH 1/3] test: fix tested function name The test tests STRERROR_OR_EOF(), but logged as STRERROR_OR_ELSE. --- src/test/test-errno-util.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/test-errno-util.c b/src/test/test-errno-util.c index 1a0154fb05..9eb729c2e4 100644 --- a/src/test/test-errno-util.c +++ b/src/test/test-errno-util.c @@ -40,10 +40,10 @@ TEST(STRERROR) { ASSERT_NOT_NULL(strstr(c, buf)); } -TEST(STRERROR_OR_ELSE) { - log_info("STRERROR_OR_ELSE(0, \"EOF\") → %s", STRERROR_OR_EOF(0)); - log_info("STRERROR_OR_ELSE(EPERM, \"EOF\") → %s", STRERROR_OR_EOF(EPERM)); - log_info("STRERROR_OR_ELSE(-EPERM, \"EOF\") → %s", STRERROR_OR_EOF(-EPERM)); +TEST(STRERROR_OR_EOF) { + log_info("STRERROR_OR_EOF(0, \"EOF\") → %s", STRERROR_OR_EOF(0)); + log_info("STRERROR_OR_EOF(EPERM, \"EOF\") → %s", STRERROR_OR_EOF(EPERM)); + log_info("STRERROR_OR_EOF(-EPERM, \"EOF\") → %s", STRERROR_OR_EOF(-EPERM)); } TEST(PROTECT_ERRNO) { From 459000e8c51b8979a8eb1dfa7f6b241ffe89f7a9 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 19 Nov 2025 05:09:02 +0900 Subject: [PATCH 2/3] errno-util: avoid double evaluation in STRERROR_OR_EOF() Follow-up for f69ae8585f5ce6cd8d1e6f3ccd6c9c2cf153e846. --- src/basic/errno-util.c | 10 ++++++++++ src/basic/errno-util.h | 7 +++---- src/basic/meson.build | 1 + 3 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 src/basic/errno-util.c diff --git a/src/basic/errno-util.c b/src/basic/errno-util.c new file mode 100644 index 0000000000..cc07276a27 --- /dev/null +++ b/src/basic/errno-util.c @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "errno-util.h" + +const char* strerror_or_eof(int errnum, char *buf, size_t buflen) { + if (errnum != 0) + return strerror_r(ABS(errnum), buf, buflen); + + return "Unexpected EOF"; +} diff --git a/src/basic/errno-util.h b/src/basic/errno-util.h index db13cd364a..eb2941253d 100644 --- a/src/basic/errno-util.h +++ b/src/basic/errno-util.h @@ -15,10 +15,9 @@ * Note that we use the GNU variant of strerror_r() here. */ #define STRERROR(errnum) strerror_r(ABS(errnum), (char[ERRNO_BUF_LEN]){}, ERRNO_BUF_LEN) -/* A helper to print an error message or message for functions that return 0 on EOF. - * Note that we can't use ({ … }) to define a temporary variable, so errnum is - * evaluated twice. */ -#define STRERROR_OR_EOF(errnum) ((errnum) != 0 ? STRERROR(errnum) : "Unexpected EOF") +/* A helper to print an error message or message for functions that return 0 on EOF. */ +const char* strerror_or_eof(int errnum, char *buf, size_t buflen); +#define STRERROR_OR_EOF(errnum) strerror_or_eof(errnum, (char[ERRNO_BUF_LEN]){}, ERRNO_BUF_LEN) static inline void _reset_errno_(int *saved_errno) { if (*saved_errno < 0) /* Invalidated by UNPROTECT_ERRNO? */ diff --git a/src/basic/meson.build b/src/basic/meson.build index c4427ee037..d05d9581f2 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -31,6 +31,7 @@ basic_sources = files( 'env-file.c', 'env-util.c', 'errno-list.c', + 'errno-util.c', 'escape.c', 'ether-addr-util.c', 'extract-word.c', From 5feb65c5b1f75d376fc032ccd1cb87766c5185a9 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 19 Nov 2025 05:10:44 +0900 Subject: [PATCH 3/3] user-util: avoid double evaluation in STRERROR_USER/GROUP() Follow-up for 6e6e96f628d352b56fd396cffb311f16839f78fb. --- src/basic/user-util.c | 20 ++++++++++++++++++++ src/basic/user-util.h | 10 +++++----- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/basic/user-util.c b/src/basic/user-util.c index 4b692076c8..5610abac94 100644 --- a/src/basic/user-util.c +++ b/src/basic/user-util.c @@ -28,6 +28,26 @@ #include "user-util.h" #include "utf8.h" +#define DEFINE_STRERROR_ACCOUNT(type) \ + const char* strerror_##type( \ + int errnum, \ + char *buf, \ + size_t buflen) { \ + \ + errnum = ABS(errnum); \ + switch (errnum) { \ + case ESRCH: \ + return "Unknown " STRINGIFY(type); \ + case ENOEXEC: \ + return "Not a system " STRINGIFY(type); \ + default: \ + return strerror_r(errnum, buf, buflen); \ + } \ + } + +DEFINE_STRERROR_ACCOUNT(user); +DEFINE_STRERROR_ACCOUNT(group); + bool uid_is_valid(uid_t uid) { /* Also see POSIX IEEE Std 1003.1-2008, 2016 Edition, 3.436. */ diff --git a/src/basic/user-util.h b/src/basic/user-util.h index b7e71720a5..e2486e5a69 100644 --- a/src/basic/user-util.h +++ b/src/basic/user-util.h @@ -20,11 +20,11 @@ #define MAP_UID_MIN ((uid_t) 60514) #define MAP_UID_MAX ((uid_t) 60577) -/* A helper to print an error message when user or group resolution fails. - * Note that we can't use ({ … }) to define a temporary variable, so errnum is - * evaluated multiple times. */ -#define STRERROR_USER(errnum) ((errnum) == -ESRCH ? "Unknown user" : (errnum) == -ENOEXEC ? "Not a system user" : STRERROR(errnum)) -#define STRERROR_GROUP(errnum) ((errnum) == -ESRCH ? "Unknown group" : (errnum) == -ENOEXEC ? "Not a system group" : STRERROR(errnum)) +/* A helper to print an error message when user or group resolution fails. */ +const char* strerror_user(int errnum, char *buf, size_t buflen); +#define STRERROR_USER(errnum) strerror_user(errnum, (char[ERRNO_BUF_LEN]){}, ERRNO_BUF_LEN) +const char* strerror_group(int errnum, char *buf, size_t buflen); +#define STRERROR_GROUP(errnum) strerror_group(errnum, (char[ERRNO_BUF_LEN]){}, ERRNO_BUF_LEN) static inline bool ERRNO_IS_NEG_BAD_ACCOUNT(intmax_t r) { return IN_SET(r,