]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
systemctl: Support --timestamp for otherwise named properties
authorChris Down <chris@chrisdown.name>
Wed, 5 Nov 2025 09:46:40 +0000 (17:46 +0800)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 5 Nov 2025 22:45:06 +0000 (07:45 +0900)
`systemctl show`'s `--timestamp` flag is supposed to reformat all
timestamp-based properties. However, the logic for detecting these
properties was incomplete and only checked if the name ended in
Timestamp.

Expand the check to explicitly include some non-"timestamp" named
properties that really are timestamps.

Fixes: https://github.com/systemd/systemd/issues/39282
src/shared/bus-print-properties.c
src/shared/bus-print-properties.h
src/systemctl/systemctl-show.c
test/units/TEST-26-SYSTEMCTL.sh

index 09986a607af336d4793fcd7de2beb7ff2544840f..431b33c100cdfa1208e1ef75352d50cfcab4e036 100644 (file)
 #include "strv.h"
 #include "time-util.h"
 
+bool bus_property_is_timestamp(const char *name) {
+        assert(name);
+
+        /* Trust me, this naming convention is ironclad. Except for these three. Okay four. Well... */
+        return endswith(name, "Timestamp") ||
+                        STR_IN_SET(name, "NextElapseUSecRealtime", "LastTriggerUSec", "TimeUSec", "RTCTimeUSec");
+}
+
 int bus_print_property_value(const char *name, const char *expected_value, BusPrintPropertyFlags flags, const char *value) {
         assert(name);
 
@@ -104,12 +112,7 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b
                 if (r < 0)
                         return r;
 
-                /* Yes, heuristics! But we can change this check
-                 * should it turn out to not be sufficient */
-
-                if (endswith(name, "Timestamp") ||
-                    STR_IN_SET(name, "NextElapseUSecRealtime", "LastTriggerUSec", "TimeUSec", "RTCTimeUSec"))
-
+                if (bus_property_is_timestamp(name))
                         bus_print_property_value(name, expected_value, flags, FORMAT_TIMESTAMP(u));
 
                 /* Managed OOM pressure default implies "unset" and use the default set in oomd.conf. Without
index 507188771ef1b030ea44c9ec5a84a6f9bb0509e7..be0063a9ed1e2af68b94359c0e5983c155426e32 100644 (file)
@@ -10,6 +10,8 @@ typedef enum BusPrintPropertyFlags {
 
 typedef int (*bus_message_print_t) (const char *name, const char *expected_value, sd_bus_message *m, BusPrintPropertyFlags flags);
 
+bool bus_property_is_timestamp(const char *name);
+
 int bus_print_property_value(const char *name, const char *expected_value, BusPrintPropertyFlags flags, const char *value);
 int bus_print_property_valuef(const char *name, const char *expected_value, BusPrintPropertyFlags flags, const char *fmt, ...) _printf_(4,5);
 int bus_message_print_all_properties(sd_bus_message *m, bus_message_print_t func, char **filter, BusPrintPropertyFlags flags, Set **found_properties);
index f1c1ab0eff01a43e1d5098f1bab71ae53818d030..2e7d3ffe75341908bdd20cfaf4a16791dbd126dd 100644 (file)
@@ -1215,7 +1215,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
                 break;
 
         case SD_BUS_TYPE_UINT64:
-                if (endswith(name, "Timestamp")) {
+                if (bus_property_is_timestamp(name)) {
                         uint64_t timestamp;
 
                         r = sd_bus_message_read_basic(m, bus_type, &timestamp);
index d5f9c02a03c7a9d25f31d43a30f7de185bb7bdc7..0bfffa54350597787e3c99f468eb269a8a0f0f53 100755 (executable)
@@ -287,6 +287,59 @@ for value in pretty us µs utc us+utc µs+utc; do
     systemctl show -P KernelTimestamp --timestamp="$value"
 done
 
+# --timestamp with timer properties (issue #39282)
+TIMER1="timestamp-test1-$RANDOM.timer"
+SERVICE1="${TIMER1%.timer}.service"
+cat >"/run/systemd/system/$SERVICE1" <<EOF
+[Service]
+Type=oneshot
+ExecStart=true
+EOF
+
+cat >"/run/systemd/system/$TIMER1" <<EOF
+[Timer]
+OnCalendar=*-*-* 00:00:00
+EOF
+
+systemctl daemon-reload
+systemctl start "$TIMER1"
+
+output=$(systemctl show -P NextElapseUSecRealtime --timestamp=unix "$TIMER1")
+if [[ ! "$output" =~ ^@[0-9]+$ ]]; then
+    echo "NextElapseUSecRealtime: expected @<number> with --timestamp=unix, got: $output" >&2
+    exit 1
+fi
+
+systemctl stop "$TIMER1"
+rm -f "/run/systemd/system/$TIMER1" "/run/systemd/system/$SERVICE1"
+
+TIMER2="timestamp-test2-$RANDOM.timer"
+SERVICE2="${TIMER2%.timer}.service"
+cat >"/run/systemd/system/$SERVICE2" <<EOF
+[Service]
+Type=oneshot
+ExecStart=true
+EOF
+
+cat >"/run/systemd/system/$TIMER2" <<EOF
+[Timer]
+OnActiveSec=100ms
+EOF
+
+systemctl daemon-reload
+systemctl start "$TIMER2"
+sleep 0.5
+
+output=$(systemctl show -P LastTriggerUSec --timestamp=unix "$TIMER2")
+if [[ ! "$output" =~ ^@[0-9]+$ ]]; then
+    echo "LastTriggerUSec: expected @<number> with --timestamp=unix, got: $output" >&2
+    exit 1
+fi
+
+systemctl stop "$TIMER2"
+rm -f "/run/systemd/system/$TIMER2" "/run/systemd/system/$SERVICE2"
+systemctl daemon-reload
+
 # set-default/get-default
 test_get_set_default() {
     target="$(systemctl get-default "$@")"