]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
networkd: fix and simplify format_lifetime()
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Mon, 19 Jul 2021 17:40:41 +0000 (19:40 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Mon, 19 Jul 2021 17:43:57 +0000 (19:43 +0200)
We would copy "forever" into the buffer. This is a fairly common case, so let's
do a microoptimization and return a static string. (All callers use the return
pointer, so this works just as well.)

The prefix "for " was not displayed, because the pointer to the part of the
buffer after "for " was returned. (Maybe it's just me, but I find strpcpy()
and associated functions really hard to use… I always have to look up what the
do exactly and what the return value is.)

A simple test is added.

src/network/meson.build
src/network/networkd-address.c
src/network/networkd-address.h
src/network/test-networkd-address.c [new file with mode: 0644]

index 4e137d7b9e2e93f81f859b5d637cbb86685221f5..2ea12c8d030e8f683d232c8d84ba4e22fe2a7325 100644 (file)
@@ -268,6 +268,12 @@ fuzzers += [
 ]
 
 tests += [
+        [['src/network/test-networkd-address.c'],
+         [libnetworkd_core,
+          libsystemd_network],
+         [],
+         network_includes],
+
         [['src/network/test-networkd-conf.c'],
          [libnetworkd_core,
           libsystemd_network],
index 2d3f8ece2d27461e86b4f86f57441b013d6b56ef..2f1dcfc62bdce205a3664643cb788ced9ba8d580 100644 (file)
@@ -621,19 +621,17 @@ int manager_has_address(Manager *manager, int family, const union in_addr_union
         return false;
 }
 
-char *format_lifetime(char *buf, size_t l, uint32_t lifetime) {
-        char *p = buf;
-
+const char* format_lifetime(char *buf, size_t l, uint32_t lifetime) {
         assert(buf);
-        assert(l > 0);
+        assert(l > 4);
 
-        if (lifetime == CACHE_INFO_INFINITY_LIFE_TIME) {
-                strscpy(buf, l, "forever");
-                return buf;
-        }
+        if (lifetime == CACHE_INFO_INFINITY_LIFE_TIME)
+                return "forever";
 
-        l -= strpcpy(&p, l, "for ");
-        return format_timespan(p, l, lifetime * USEC_PER_SEC, USEC_PER_SEC);
+        sprintf(buf, "for ");
+        /* format_timespan() never fails */
+        assert_se(format_timespan(buf + 4, l - 4, lifetime * USEC_PER_SEC, USEC_PER_SEC));
+        return buf;
 }
 
 static void log_address_debug(const Address *address, const char *str, const Link *link) {
index 1569b588a024e64b6f547e221649fbaee217c1de..811940c12611f622091585adced0c77f3be78acb 100644 (file)
@@ -50,7 +50,7 @@ typedef struct Address {
         address_ready_callback_t callback;
 } Address;
 
-char *format_lifetime(char *buf, size_t l, uint32_t lifetime) _warn_unused_result_;
+const char* format_lifetime(char *buf, size_t l, uint32_t lifetime) _warn_unused_result_;
 /* Note: the lifetime of the compound literal is the immediately surrounding block,
  * see C11 §6.5.2.5, and
  * https://stackoverflow.com/questions/34880638/compound-literal-lifetime-and-if-blocks */
@@ -58,7 +58,7 @@ char *format_lifetime(char *buf, size_t l, uint32_t lifetime) _warn_unused_resul
         format_lifetime((char[FORMAT_TIMESPAN_MAX+STRLEN("for ")]){}, FORMAT_TIMESPAN_MAX+STRLEN("for "), lifetime)
 
 int address_new(Address **ret);
-Address *address_free(Address *address);
+Addressaddress_free(Address *address);
 int address_get(Link *link, const Address *in, Address **ret);
 int address_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg);
 int address_remove(const Address *address, Link *link);
diff --git a/src/network/test-networkd-address.c b/src/network/test-networkd-address.c
new file mode 100644 (file)
index 0000000..7c1d65a
--- /dev/null
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "networkd-address.h"
+#include "tests.h"
+
+static void test_FORMAT_LIFETIME_one(uint32_t lifetime, const char *expected) {
+        const char *t = FORMAT_LIFETIME(lifetime);
+
+        log_debug("%"PRIu32 " → \"%s\" (expected \"%s\")", lifetime, t, expected);
+        assert_se(streq(t, expected));
+}
+
+static void test_FORMAT_LIFETIME(void) {
+        log_info("/* %s */", __func__);
+
+        test_FORMAT_LIFETIME_one(0, "for 0");
+        test_FORMAT_LIFETIME_one(1, "for 1s");
+        test_FORMAT_LIFETIME_one(3 * (USEC_PER_WEEK/USEC_PER_SEC), "for 3w");
+        test_FORMAT_LIFETIME_one(CACHE_INFO_INFINITY_LIFE_TIME, "forever");
+}
+
+int main(int argc, char *argv[]) {
+        test_setup_logging(LOG_INFO);
+
+        test_FORMAT_LIFETIME();
+
+        return 0;
+}