summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/systemctl.c37
-rw-r--r--src/util.c57
-rw-r--r--src/util.h4
3 files changed, 96 insertions, 2 deletions
diff --git a/src/systemctl.c b/src/systemctl.c
index f9317ad18f..0c33abb307 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -1489,6 +1489,11 @@ typedef struct UnitStatusInfo {
const char *path;
const char *default_control_group;
+ usec_t inactive_exit_timestamp;
+ usec_t active_enter_timestamp;
+ usec_t active_exit_timestamp;
+ usec_t inactive_enter_timestamp;
+
bool need_daemon_reload;
/* Service */
@@ -1523,6 +1528,9 @@ typedef struct UnitStatusInfo {
static void print_status_info(UnitStatusInfo *i) {
ExecStatusInfo *p;
const char *on, *off, *ss;
+ usec_t timestamp;
+ char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
+ char since2[FORMAT_TIMESTAMP_MAX], *s2;
assert(i);
@@ -1559,17 +1567,34 @@ static void print_status_info(UnitStatusInfo *i) {
on = off = "";
if (ss)
- printf("\t Active: %s%s (%s)%s\n",
+ printf("\t Active: %s%s (%s)%s",
on,
strna(i->active_state),
ss,
off);
else
- printf("\t Active: %s%s%s\n",
+ printf("\t Active: %s%s%s",
on,
strna(i->active_state),
off);
+ timestamp = (streq_ptr(i->active_state, "active") ||
+ streq_ptr(i->active_state, "reloading")) ? i->active_enter_timestamp :
+ (streq_ptr(i->active_state, "inactive") ||
+ streq_ptr(i->active_state, "maintenance")) ? i->inactive_enter_timestamp :
+ streq_ptr(i->active_state, "activating") ? i->inactive_exit_timestamp :
+ i->active_exit_timestamp;
+
+ s1 = format_timestamp_pretty(since1, sizeof(since1), timestamp);
+ s2 = format_timestamp(since2, sizeof(since2), timestamp);
+
+ if (s1)
+ printf(" since [%s; %s]\n", s2, s1);
+ else if (s2)
+ printf(" since [%s]\n", s2);
+ else
+ printf("\n");
+
if (i->sysfs_path)
printf("\t Device: %s\n", i->sysfs_path);
else if (i->where)
@@ -1782,6 +1807,14 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn
i->start_timestamp = (usec_t) u;
else if (streq(name, "ExecMainExitTimestamp"))
i->exit_timestamp = (usec_t) u;
+ else if (streq(name, "ActiveEnterTimestamp"))
+ i->active_enter_timestamp = (usec_t) u;
+ else if (streq(name, "InactiveEnterTimestamp"))
+ i->inactive_enter_timestamp = (usec_t) u;
+ else if (streq(name, "InactiveExitTimestamp"))
+ i->inactive_exit_timestamp = (usec_t) u;
+ else if (streq(name, "ActiveExitTimestamp"))
+ i->active_exit_timestamp = (usec_t) u;
break;
}
diff --git a/src/util.c b/src/util.c
index f1a7bbdc71..a09b704ffe 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1659,6 +1659,63 @@ char *format_timestamp(char *buf, size_t l, usec_t t) {
return buf;
}
+char *format_timestamp_pretty(char *buf, size_t l, usec_t t) {
+ usec_t n, d;
+
+ n = now(CLOCK_REALTIME);
+
+ if (t <= 0 || t > n || t + USEC_PER_DAY*7 <= t)
+ return NULL;
+
+ d = n - t;
+
+ if (d >= USEC_PER_YEAR)
+ snprintf(buf, l, "%llu years and %llu months ago",
+ (unsigned long long) (d / USEC_PER_YEAR),
+ (unsigned long long) ((d % USEC_PER_YEAR) / USEC_PER_MONTH));
+ else if (d >= USEC_PER_MONTH)
+ snprintf(buf, l, "%llu months and %llu days ago",
+ (unsigned long long) (d / USEC_PER_MONTH),
+ (unsigned long long) ((d % USEC_PER_MONTH) / USEC_PER_DAY));
+ else if (d >= USEC_PER_WEEK)
+ snprintf(buf, l, "%llu weeks and %llu days ago",
+ (unsigned long long) (d / USEC_PER_WEEK),
+ (unsigned long long) ((d % USEC_PER_WEEK) / USEC_PER_DAY));
+ else if (d >= 2*USEC_PER_DAY)
+ snprintf(buf, l, "%llu days ago", (unsigned long long) (d / USEC_PER_DAY));
+ else if (d >= 25*USEC_PER_HOUR)
+ snprintf(buf, l, "1 day and %lluh ago",
+ (unsigned long long) ((d - USEC_PER_DAY) / USEC_PER_HOUR));
+ else if (d >= 6*USEC_PER_HOUR)
+ snprintf(buf, l, "%lluh ago",
+ (unsigned long long) (d / USEC_PER_HOUR));
+ else if (d >= USEC_PER_HOUR)
+ snprintf(buf, l, "%lluh %llumin ago",
+ (unsigned long long) (d / USEC_PER_HOUR),
+ (unsigned long long) ((d % USEC_PER_HOUR) / USEC_PER_MINUTE));
+ else if (d >= 5*USEC_PER_MINUTE)
+ snprintf(buf, l, "%llumin ago",
+ (unsigned long long) (d / USEC_PER_MINUTE));
+ else if (d >= USEC_PER_MINUTE)
+ snprintf(buf, l, "%llumin %llus ago",
+ (unsigned long long) (d / USEC_PER_MINUTE),
+ (unsigned long long) ((d % USEC_PER_MINUTE) / USEC_PER_SEC));
+ else if (d >= USEC_PER_SEC)
+ snprintf(buf, l, "%llus ago",
+ (unsigned long long) (d / USEC_PER_SEC));
+ else if (d >= USEC_PER_MSEC)
+ snprintf(buf, l, "%llums ago",
+ (unsigned long long) (d / USEC_PER_MSEC));
+ else if (d > 0)
+ snprintf(buf, l, "%lluus ago",
+ (unsigned long long) d);
+ else
+ snprintf(buf, l, "now");
+
+ buf[l-1] = 0;
+ return buf;
+}
+
char *format_timespan(char *buf, size_t l, usec_t t) {
static const struct {
const char *suffix;
diff --git a/src/util.h b/src/util.h
index 4063ee7ff2..3a7ac29fca 100644
--- a/src/util.h
+++ b/src/util.h
@@ -52,12 +52,15 @@ typedef struct dual_timestamp {
#define USEC_PER_HOUR (60ULL*USEC_PER_MINUTE)
#define USEC_PER_DAY (24ULL*USEC_PER_HOUR)
#define USEC_PER_WEEK (7ULL*USEC_PER_DAY)
+#define USEC_PER_MONTH (2629800ULL*USEC_PER_SEC)
+#define USEC_PER_YEAR (31557600ULL*USEC_PER_SEC)
/* What is interpreted as whitespace? */
#define WHITESPACE " \t\n\r"
#define NEWLINE "\n\r"
#define FORMAT_TIMESTAMP_MAX 64
+#define FORMAT_TIMESTAMP_PRETTY_MAX 256
#define FORMAT_TIMESPAN_MAX 64
#define ANSI_HIGHLIGHT_ON "\x1B[1;31m"
@@ -248,6 +251,7 @@ bool ignore_file(const char *filename);
bool chars_intersect(const char *a, const char *b);
char *format_timestamp(char *buf, size_t l, usec_t t);
+char *format_timestamp_pretty(char *buf, size_t l, usec_t t);
char *format_timespan(char *buf, size_t l, usec_t t);
int make_stdio(int fd);