diff --git a/src/basic/util.c b/src/basic/util.c index cd75529cfe..00052c5e1d 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -165,6 +165,28 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, return NULL; } +bool memeqzero(const void *data, size_t length) { + /* Does the buffer consist entirely of NULs? + * Copied from https://github.com/systemd/casync/, copied in turn from + * https://github.com/rustyrussell/ccan/blob/master/ccan/mem/mem.c#L92, + * which is licensed CC-0. + */ + + const uint8_t *p = data; + size_t i; + + /* Check first 16 bytes manually */ + for (i = 0; i < 16; i++, length--) { + if (length == 0) + return true; + if (p[i]) + return false; + } + + /* Now we know first 16 bytes are NUL, memcmp with self. */ + return memcmp(data, p + i, length) == 0; +} + int on_ac_power(void) { bool found_offline = false, found_online = false; _cleanup_closedir_ DIR *d = NULL; diff --git a/src/basic/util.h b/src/basic/util.h index 8cba4ed726..fd180cb787 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -159,6 +159,10 @@ int on_ac_power(void); #define zero(x) (memzero(&(x), sizeof(x))) +bool memeqzero(const void *data, size_t length); + +#define eqzero(x) memeqzero(x, sizeof(x)) + static inline void *mempset(void *s, int c, size_t n) { memset(s, c, n); return (uint8_t*)s + n; diff --git a/src/test/test-util.c b/src/test/test-util.c index 80856e6388..eeee09a7d2 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -237,6 +237,20 @@ static void test_log2i(void) { assert_se(log2i(INT_MAX) == sizeof(int)*8-2); } +static void test_eqzero(void) { + const uint32_t zeros[] = {0, 0, 0}; + const uint32_t ones[] = {1, 1}; + const uint32_t mixed[] = {0, 1, 0, 0, 0}; + const uint8_t longer[] = {[55] = 255}; + + log_info("/* %s */", __func__); + + assert_se(eqzero(zeros)); + assert_se(!eqzero(ones)); + assert_se(!eqzero(mixed)); + assert_se(!eqzero(longer)); +} + static void test_raw_clone(void) { pid_t parent, pid, pid2; @@ -370,6 +384,7 @@ int main(int argc, char *argv[]) { test_protect_errno(); test_in_set(); test_log2i(); + test_eqzero(); test_raw_clone(); test_physical_memory(); test_physical_memory_scale();