[systemd-commits] 3 commits - TODO man/systemctl.xml src/shared src/systemctl
Lennart Poettering
lennart at kemper.freedesktop.org
Mon Nov 11 06:59:46 PST 2013
TODO | 2
man/systemctl.xml | 11 +
src/shared/time-util.c | 73 ++++++++-----
src/shared/time-util.h | 5
src/systemctl/systemctl.c | 258 ++++++++++++++++++++++++++++++++++++++++++----
5 files changed, 303 insertions(+), 46 deletions(-)
New commits:
commit cbb76c29ccd1a639ada00425fa7cc408507f171d
Author: Lennart Poettering <lennart at poettering.net>
Date: Mon Nov 11 03:06:14 2013 +0100
systemctl: add new "list-timers" command
diff --git a/man/systemctl.xml b/man/systemctl.xml
index d842b78..33a2935 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -555,6 +555,17 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
</varlistentry>
<varlistentry>
+ <term><command>list-timers</command></term>
+
+ <listitem>
+ <para>List timer units ordered by the time they elapse next.</para>
+
+ <para>See also the options <option>--all</option> and
+ <option>--failed</option>.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><command>start <replaceable>NAME</replaceable>...</command></term>
<listitem>
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index df4bd21..c5166d5 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -532,13 +532,12 @@ static int get_triggered_units(
static int get_listening(
sd_bus *bus,
const char* unit_path,
- char*** listening,
- unsigned *c) {
+ char*** listening) {
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
const char *type, *path;
- int r;
+ int r, n = 0;
r = sd_bus_get_property(
bus,
@@ -568,7 +567,7 @@ static int get_listening(
if (r < 0)
return log_oom();
- (*c)++;
+ n++;
}
if (r < 0)
return bus_log_parse_error(r);
@@ -577,7 +576,7 @@ static int get_listening(
if (r < 0)
return bus_log_parse_error(r);
- return 0;
+ return n;
}
struct socket_info {
@@ -595,9 +594,12 @@ struct socket_info {
bool own_triggered;
};
-static int socket_info_compare(struct socket_info *a, struct socket_info *b) {
+static int socket_info_compare(const struct socket_info *a, const struct socket_info *b) {
int o;
+ assert(a);
+ assert(b);
+
o = strcmp(a->path, b->path);
if (o == 0)
o = strcmp(a->type, b->type);
@@ -674,21 +676,19 @@ static int list_sockets(sd_bus *bus, char **args) {
struct socket_info *socket_infos = NULL;
const UnitInfo *u;
struct socket_info *s;
- unsigned cu = 0, cs = 0;
+ unsigned cs = 0;
size_t size = 0;
- int r;
+ int r, n;
pager_open_if_enabled();
- r = get_unit_list(bus, &reply, &unit_infos);
- if (r < 0)
- return r;
+ n = get_unit_list(bus, &reply, &unit_infos);
+ if (n < 0)
+ return n;
- cu = (unsigned) r;
-
- for (u = unit_infos; u < unit_infos + cu; u++) {
+ for (u = unit_infos; u < unit_infos + n; u++) {
_cleanup_strv_free_ char **listening = NULL, **triggered = NULL;
- unsigned c = 0, i;
+ int i, c;
if (!output_show_unit(u))
continue;
@@ -700,9 +700,11 @@ static int list_sockets(sd_bus *bus, char **args) {
if (r < 0)
goto cleanup;
- r = get_listening(bus, u->unit_path, &listening, &c);
- if (r < 0)
+ c = get_listening(bus, u->unit_path, &listening);
+ if (c < 0) {
+ r = c;
goto cleanup;
+ }
if (!GREEDY_REALLOC(socket_infos, size, cs + c)) {
r = log_oom();
@@ -742,6 +744,224 @@ static int list_sockets(sd_bus *bus, char **args) {
return r;
}
+static int get_next_elapse(
+ sd_bus *bus,
+ const char *path,
+ dual_timestamp *next) {
+
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ dual_timestamp t;
+ int r;
+
+ assert(bus);
+ assert(path);
+ assert(next);
+
+ r = sd_bus_get_property_trivial(
+ bus,
+ "org.freedesktop.systemd1",
+ path,
+ "org.freedesktop.systemd1.Timer",
+ "NextElapseUSecMonotonic",
+ &error,
+ 't',
+ &t.monotonic);
+ if (r < 0) {
+ log_error("Failed to get next elapsation time: %s", bus_error_message(&error, r));
+ return r;
+ }
+
+ r = sd_bus_get_property_trivial(
+ bus,
+ "org.freedesktop.systemd1",
+ path,
+ "org.freedesktop.systemd1.Timer",
+ "NextElapseUSecRealtime",
+ &error,
+ 't',
+ &t.realtime);
+ if (r < 0) {
+ log_error("Failed to get next elapsation time: %s", bus_error_message(&error, r));
+ return r;
+ }
+
+ *next = t;
+ return 0;
+}
+
+struct timer_info {
+ const char* id;
+ usec_t next_elapse;
+ char** triggered;
+};
+
+static int timer_info_compare(const struct timer_info *a, const struct timer_info *b) {
+ assert(a);
+ assert(b);
+
+ if (a->next_elapse < b->next_elapse)
+ return -1;
+ if (a->next_elapse > b->next_elapse)
+ return 1;
+
+ return strcmp(a->id, b->id);
+}
+
+static int output_timers_list(struct timer_info *timer_infos, unsigned n) {
+ struct timer_info *t;
+ unsigned
+ nextlen = sizeof("NEXT") - 1,
+ leftlen = sizeof("LEFT") - 1,
+ unitlen = sizeof("UNIT") - 1,
+ activatelen = sizeof("ACTIVATES") - 1;
+
+ const char *on, *off;
+
+ assert(timer_infos || n == 0);
+
+ for (t = timer_infos; t < timer_infos + n; t++) {
+ unsigned ul = 0;
+ char **a;
+
+ if (t->next_elapse > 0) {
+ char tstamp[FORMAT_TIMESTAMP_MAX] = "", trel[FORMAT_TIMESTAMP_RELATIVE_MAX] = "";
+
+ format_timestamp(tstamp, sizeof(tstamp), t->next_elapse);
+ nextlen = MAX(nextlen, strlen(tstamp) + 1);
+
+ format_timestamp_relative(trel, sizeof(trel), t->next_elapse);
+ leftlen = MAX(leftlen, strlen(trel));
+ }
+
+ unitlen = MAX(unitlen, strlen(t->id));
+
+ STRV_FOREACH(a, t->triggered)
+ ul += strlen(*a) + 2*(a != t->triggered);
+ activatelen = MAX(activatelen, ul);
+ }
+
+ if (n > 0) {
+ if (!arg_no_legend)
+ printf("%-*s %-*s %-*s %s\n",
+ nextlen, "NEXT",
+ leftlen, "LEFT",
+ unitlen, "UNIT",
+ "ACTIVATES");
+
+ for (t = timer_infos; t < timer_infos + n; t++) {
+ char tstamp[FORMAT_TIMESTAMP_MAX] = "n/a", trel[FORMAT_TIMESTAMP_RELATIVE_MAX] = "n/a";
+ char **a;
+
+ format_timestamp(tstamp, sizeof(tstamp), t->next_elapse);
+ format_timestamp_relative(trel, sizeof(trel), t->next_elapse);
+
+ printf("%-*s %-*s %-*s",
+ nextlen, tstamp, leftlen, trel, unitlen, t->id);
+
+ STRV_FOREACH(a, t->triggered)
+ printf("%s %s",
+ a == t->triggered ? "" : ",", *a);
+ printf("\n");
+ }
+
+ on = ansi_highlight();
+ off = ansi_highlight_off();
+ if (!arg_no_legend)
+ printf("\n");
+ } else {
+ on = ansi_highlight_red();
+ off = ansi_highlight_off();
+ }
+
+ if (!arg_no_legend) {
+ printf("%s%u timers listed.%s\n", on, n, off);
+ if (!arg_all)
+ printf("Pass --all to see loaded but inactive timers, too.\n");
+ }
+
+ return 0;
+}
+
+static int list_timers(sd_bus *bus, char **args) {
+
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ _cleanup_free_ struct timer_info *timer_infos = NULL;
+ _cleanup_free_ UnitInfo *unit_infos = NULL;
+ struct timer_info *t;
+ const UnitInfo *u;
+ size_t size = 0;
+ int n, r, c = 0;
+ dual_timestamp nw;
+
+ pager_open_if_enabled();
+
+ n = get_unit_list(bus, &reply, &unit_infos);
+ if (n < 0)
+ return n;
+
+ dual_timestamp_get(&nw);
+
+ for (u = unit_infos; u < unit_infos + n; u++) {
+ _cleanup_strv_free_ char **triggered = NULL;
+ dual_timestamp next;
+ usec_t m;
+
+ if (!output_show_unit(u))
+ continue;
+
+ if (!endswith(u->id, ".timer"))
+ continue;
+
+ r = get_triggered_units(bus, u->unit_path, &triggered);
+ if (r < 0)
+ goto cleanup;
+
+ r = get_next_elapse(bus, u->unit_path, &next);
+ if (r < 0)
+ goto cleanup;
+
+ if (next.monotonic != (usec_t) -1 && next.monotonic > 0) {
+ usec_t converted;
+
+ if (next.monotonic > nw.monotonic)
+ converted = nw.realtime + (next.monotonic - nw.monotonic);
+ else
+ converted = nw.realtime - (nw.monotonic - next.monotonic);
+
+ if (next.realtime != (usec_t) -1 && next.realtime > 0)
+ m = MIN(converted, next.realtime);
+ else
+ m = converted;
+ } else
+ m = next.realtime;
+
+ if (!GREEDY_REALLOC(timer_infos, size, c+1)) {
+ r = log_oom();
+ goto cleanup;
+ }
+
+ timer_infos[c++] = (struct timer_info) {
+ .id = u->id,
+ .next_elapse = m,
+ .triggered = triggered,
+ };
+
+ triggered = NULL; /* avoid cleanup */
+ }
+
+ qsort_safe(timer_infos, c, sizeof(struct timer_info),
+ (__compar_fn_t) timer_info_compare);
+
+ output_timers_list(timer_infos, c);
+
+ cleanup:
+ for (t = timer_infos; t < timer_infos + c; t++)
+ strv_free(t->triggered);
+
+ return r;
+}
+
static int compare_unit_file_list(const void *a, const void *b) {
const char *d1, *d2;
const UnitFileList *u = a, *v = b;
@@ -4404,6 +4624,7 @@ static int systemctl_help(void) {
"Unit Commands:\n"
" list-units List loaded units\n"
" list-sockets List loaded sockets ordered by address\n"
+ " list-timers List loaded timers ordered by next elapse\n"
" start [NAME...] Start (activate) one or more units\n"
" stop [NAME...] Stop (deactivate) one or more units\n"
" reload [NAME...] Reload one or more units\n"
@@ -5376,6 +5597,7 @@ static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
{ "list-units", LESS, 1, list_units },
{ "list-unit-files", EQUAL, 1, list_unit_files },
{ "list-sockets", LESS, 1, list_sockets },
+ { "list-timers", LESS, 1, list_timers },
{ "list-jobs", EQUAL, 1, list_jobs },
{ "clear-jobs", EQUAL, 1, daemon_reload },
{ "cancel", MORE, 2, cancel_job },
commit 966204e010ed432a1d7a0481d41a326d8ec7b0c8
Author: Lennart Poettering <lennart at poettering.net>
Date: Mon Nov 11 03:03:17 2013 +0100
timer: consider (usec_t) -1 an invalid timestamp
diff --git a/TODO b/TODO
index fe5d2f5..efc7e2a 100644
--- a/TODO
+++ b/TODO
@@ -43,6 +43,8 @@ CGroup Rework Completion:
Features:
+* be more careful what we export on the bus as (usec_t) 0 and (usec_t) -1
+
* check :no-sender logic after PID 1 conversion
* increase journal files by a few MB each time, instead of piecemeal
diff --git a/src/shared/time-util.c b/src/shared/time-util.c
index b29d8c6..55428c4 100644
--- a/src/shared/time-util.c
+++ b/src/shared/time-util.c
@@ -158,7 +158,7 @@ char *format_timestamp(char *buf, size_t l, usec_t t) {
assert(buf);
assert(l > 0);
- if (t <= 0)
+ if (t <= 0 || t == (usec_t) -1)
return NULL;
sec = (time_t) (t / USEC_PER_SEC);
@@ -176,7 +176,7 @@ char *format_timestamp_us(char *buf, size_t l, usec_t t) {
assert(buf);
assert(l > 0);
- if (t <= 0)
+ if (t <= 0 || t == (usec_t) -1)
return NULL;
sec = (time_t) (t / USEC_PER_SEC);
diff --git a/src/shared/time-util.h b/src/shared/time-util.h
index a51317d..0a3a98b 100644
--- a/src/shared/time-util.h
+++ b/src/shared/time-util.h
@@ -64,7 +64,10 @@ dual_timestamp* dual_timestamp_get(dual_timestamp *ts);
dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u);
dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u);
-#define dual_timestamp_is_set(ts) ((ts)->realtime > 0)
+static inline bool dual_timestamp_is_set(dual_timestamp *ts) {
+ return ((ts->realtime > 0 && ts->realtime != (usec_t) -1) ||
+ (ts->monotonic > 0 && ts->monotonic != (usec_t) -1));
+}
usec_t timespec_load(const struct timespec *ts) _pure_;
struct timespec *timespec_store(struct timespec *ts, usec_t u);
commit 1fcf71f562a83a59f853f982306fca7d009bb30d
Author: Lennart Poettering <lennart at poettering.net>
Date: Mon Nov 11 03:02:52 2013 +0100
timer: properly format relative timestamps in the future
diff --git a/src/shared/time-util.c b/src/shared/time-util.c
index 7bb7d4e..b29d8c6 100644
--- a/src/shared/time-util.c
+++ b/src/shared/time-util.c
@@ -192,55 +192,62 @@ char *format_timestamp_us(char *buf, size_t l, usec_t t) {
}
char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
+ const char *s;
usec_t n, d;
n = now(CLOCK_REALTIME);
- if (t <= 0 || t > n || t + USEC_PER_DAY*7 <= t)
+ if (t <= 0 || (t == (usec_t) -1))
return NULL;
- d = n - t;
+ if (n > t) {
+ d = n - t;
+ s = "ago";
+ } else {
+ d = t - n;
+ s = "left";
+ }
if (d >= USEC_PER_YEAR)
- snprintf(buf, l, "%llu years %llu months ago",
+ snprintf(buf, l, "%llu years %llu months %s",
(unsigned long long) (d / USEC_PER_YEAR),
- (unsigned long long) ((d % USEC_PER_YEAR) / USEC_PER_MONTH));
+ (unsigned long long) ((d % USEC_PER_YEAR) / USEC_PER_MONTH), s);
else if (d >= USEC_PER_MONTH)
- snprintf(buf, l, "%llu months %llu days ago",
+ snprintf(buf, l, "%llu months %llu days %s",
(unsigned long long) (d / USEC_PER_MONTH),
- (unsigned long long) ((d % USEC_PER_MONTH) / USEC_PER_DAY));
+ (unsigned long long) ((d % USEC_PER_MONTH) / USEC_PER_DAY), s);
else if (d >= USEC_PER_WEEK)
- snprintf(buf, l, "%llu weeks %llu days ago",
+ snprintf(buf, l, "%llu weeks %llu days %s",
(unsigned long long) (d / USEC_PER_WEEK),
- (unsigned long long) ((d % USEC_PER_WEEK) / USEC_PER_DAY));
+ (unsigned long long) ((d % USEC_PER_WEEK) / USEC_PER_DAY), s);
else if (d >= 2*USEC_PER_DAY)
- snprintf(buf, l, "%llu days ago", (unsigned long long) (d / USEC_PER_DAY));
+ snprintf(buf, l, "%llu days %s", (unsigned long long) (d / USEC_PER_DAY), s);
else if (d >= 25*USEC_PER_HOUR)
- snprintf(buf, l, "1 day %lluh ago",
- (unsigned long long) ((d - USEC_PER_DAY) / USEC_PER_HOUR));
+ snprintf(buf, l, "1 day %lluh %s",
+ (unsigned long long) ((d - USEC_PER_DAY) / USEC_PER_HOUR), s);
else if (d >= 6*USEC_PER_HOUR)
- snprintf(buf, l, "%lluh ago",
- (unsigned long long) (d / USEC_PER_HOUR));
+ snprintf(buf, l, "%lluh %s",
+ (unsigned long long) (d / USEC_PER_HOUR), s);
else if (d >= USEC_PER_HOUR)
- snprintf(buf, l, "%lluh %llumin ago",
+ snprintf(buf, l, "%lluh %llumin %s",
(unsigned long long) (d / USEC_PER_HOUR),
- (unsigned long long) ((d % USEC_PER_HOUR) / USEC_PER_MINUTE));
+ (unsigned long long) ((d % USEC_PER_HOUR) / USEC_PER_MINUTE), s);
else if (d >= 5*USEC_PER_MINUTE)
- snprintf(buf, l, "%llumin ago",
- (unsigned long long) (d / USEC_PER_MINUTE));
+ snprintf(buf, l, "%llumin %s",
+ (unsigned long long) (d / USEC_PER_MINUTE), s);
else if (d >= USEC_PER_MINUTE)
- snprintf(buf, l, "%llumin %llus ago",
+ snprintf(buf, l, "%llumin %llus %s",
(unsigned long long) (d / USEC_PER_MINUTE),
- (unsigned long long) ((d % USEC_PER_MINUTE) / USEC_PER_SEC));
+ (unsigned long long) ((d % USEC_PER_MINUTE) / USEC_PER_SEC), s);
else if (d >= USEC_PER_SEC)
- snprintf(buf, l, "%llus ago",
- (unsigned long long) (d / USEC_PER_SEC));
+ snprintf(buf, l, "%llus %s",
+ (unsigned long long) (d / USEC_PER_SEC), s);
else if (d >= USEC_PER_MSEC)
- snprintf(buf, l, "%llums ago",
- (unsigned long long) (d / USEC_PER_MSEC));
+ snprintf(buf, l, "%llums %s",
+ (unsigned long long) (d / USEC_PER_MSEC), s);
else if (d > 0)
- snprintf(buf, l, "%lluus ago",
- (unsigned long long) d);
+ snprintf(buf, l, "%lluus %s",
+ (unsigned long long) d, s);
else
snprintf(buf, l, "now");
@@ -480,6 +487,18 @@ int parse_timestamp(const char *t, usec_t *usec) {
return r;
goto finish;
+ } else if (endswith(t, " left")) {
+ _cleanup_free_ char *z;
+
+ z = strndup(t, strlen(t) - 4);
+ if (!z)
+ return -ENOMEM;
+
+ r = parse_sec(z, &plus);
+ if (r < 0)
+ return r;
+
+ goto finish;
}
for (i = 0; i < ELEMENTSOF(day_nr); i++) {
More information about the systemd-commits
mailing list