chiark / gitweb /
logind: add support for automatic suspend/hibernate/shutdown on idle
[elogind.git] / src / shared / util.c
index 6d826b6f5eafbf185bc0191d850a176ff3aff6a3..d01c2061b423c6b60a4dc422a1d358e46eb5dad5 100644 (file)
@@ -108,105 +108,6 @@ bool streq_ptr(const char *a, const char *b) {
         return false;
 }
 
-usec_t now(clockid_t clock_id) {
-        struct timespec ts;
-
-        assert_se(clock_gettime(clock_id, &ts) == 0);
-
-        return timespec_load(&ts);
-}
-
-dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
-        assert(ts);
-
-        ts->realtime = now(CLOCK_REALTIME);
-        ts->monotonic = now(CLOCK_MONOTONIC);
-
-        return ts;
-}
-
-dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
-        int64_t delta;
-        assert(ts);
-
-        ts->realtime = u;
-
-        if (u == 0)
-                ts->monotonic = 0;
-        else {
-                delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
-
-                ts->monotonic = now(CLOCK_MONOTONIC);
-
-                if ((int64_t) ts->monotonic > delta)
-                        ts->monotonic -= delta;
-                else
-                        ts->monotonic = 0;
-        }
-
-        return ts;
-}
-
-usec_t timespec_load(const struct timespec *ts) {
-        assert(ts);
-
-        if (ts->tv_sec == (time_t) -1 &&
-            ts->tv_nsec == (long) -1)
-                return (usec_t) -1;
-
-        if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC)
-                return (usec_t) -1;
-
-        return
-                (usec_t) ts->tv_sec * USEC_PER_SEC +
-                (usec_t) ts->tv_nsec / NSEC_PER_USEC;
-}
-
-struct timespec *timespec_store(struct timespec *ts, usec_t u)  {
-        assert(ts);
-
-        if (u == (usec_t) -1) {
-                ts->tv_sec = (time_t) -1;
-                ts->tv_nsec = (long) -1;
-                return ts;
-        }
-
-        ts->tv_sec = (time_t) (u / USEC_PER_SEC);
-        ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
-
-        return ts;
-}
-
-usec_t timeval_load(const struct timeval *tv) {
-        assert(tv);
-
-        if (tv->tv_sec == (time_t) -1 &&
-            tv->tv_usec == (suseconds_t) -1)
-                return (usec_t) -1;
-
-        if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC)
-                return (usec_t) -1;
-
-        return
-                (usec_t) tv->tv_sec * USEC_PER_SEC +
-                (usec_t) tv->tv_usec;
-}
-
-struct timeval *timeval_store(struct timeval *tv, usec_t u) {
-        assert(tv);
-
-        if (u == (usec_t) -1) {
-                tv->tv_sec = (time_t) -1;
-                tv->tv_usec = (suseconds_t) -1;
-                return tv;
-        }
-
-        tv->tv_sec = (time_t) (u / USEC_PER_SEC);
-        tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
-
-        return tv;
-}
-
 char* endswith(const char *s, const char *postfix) {
         size_t sl, pl;
 
@@ -1956,136 +1857,6 @@ bool chars_intersect(const char *a, const char *b) {
         return false;
 }
 
-char *format_timestamp(char *buf, size_t l, usec_t t) {
-        struct tm tm;
-        time_t sec;
-
-        assert(buf);
-        assert(l > 0);
-
-        if (t <= 0)
-                return NULL;
-
-        sec = (time_t) (t / USEC_PER_SEC);
-
-        if (strftime(buf, l, "%a, %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm)) <= 0)
-                return NULL;
-
-        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;
-                usec_t usec;
-        } table[] = {
-                { "w", USEC_PER_WEEK },
-                { "d", USEC_PER_DAY },
-                { "h", USEC_PER_HOUR },
-                { "min", USEC_PER_MINUTE },
-                { "s", USEC_PER_SEC },
-                { "ms", USEC_PER_MSEC },
-                { "us", 1 },
-        };
-
-        unsigned i;
-        char *p = buf;
-
-        assert(buf);
-        assert(l > 0);
-
-        if (t == (usec_t) -1)
-                return NULL;
-
-        if (t == 0) {
-                snprintf(p, l, "0");
-                p[l-1] = 0;
-                return p;
-        }
-
-        /* The result of this function can be parsed with parse_usec */
-
-        for (i = 0; i < ELEMENTSOF(table); i++) {
-                int k;
-                size_t n;
-
-                if (t < table[i].usec)
-                        continue;
-
-                if (l <= 1)
-                        break;
-
-                k = snprintf(p, l, "%s%llu%s", p > buf ? " " : "", (unsigned long long) (t / table[i].usec), table[i].suffix);
-                n = MIN((size_t) k, l);
-
-                l -= n;
-                p += n;
-
-                t %= table[i].usec;
-        }
-
-        *p = 0;
-
-        return buf;
-}
-
 bool fstype_is_network(const char *fstype) {
         static const char table[] =
                 "cifs\0"
@@ -2754,164 +2525,6 @@ ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
         return n;
 }
 
-int parse_usec(const char *t, usec_t *usec) {
-        static const struct {
-                const char *suffix;
-                usec_t usec;
-        } table[] = {
-                { "seconds", USEC_PER_SEC },
-                { "second", USEC_PER_SEC },
-                { "sec", USEC_PER_SEC },
-                { "s", USEC_PER_SEC },
-                { "minutes", USEC_PER_MINUTE },
-                { "minute", USEC_PER_MINUTE },
-                { "min", USEC_PER_MINUTE },
-                { "months", USEC_PER_MONTH },
-                { "month", USEC_PER_MONTH },
-                { "msec", USEC_PER_MSEC },
-                { "ms", USEC_PER_MSEC },
-                { "m", USEC_PER_MINUTE },
-                { "hours", USEC_PER_HOUR },
-                { "hour", USEC_PER_HOUR },
-                { "hr", USEC_PER_HOUR },
-                { "h", USEC_PER_HOUR },
-                { "days", USEC_PER_DAY },
-                { "day", USEC_PER_DAY },
-                { "d", USEC_PER_DAY },
-                { "weeks", USEC_PER_WEEK },
-                { "week", USEC_PER_WEEK },
-                { "w", USEC_PER_WEEK },
-                { "years", USEC_PER_YEAR },
-                { "year", USEC_PER_YEAR },
-                { "y", USEC_PER_YEAR },
-                { "usec", 1ULL },
-                { "us", 1ULL },
-                { "", USEC_PER_SEC }, /* default is sec */
-        };
-
-        const char *p;
-        usec_t r = 0;
-
-        assert(t);
-        assert(usec);
-
-        p = t;
-        do {
-                long long l;
-                char *e;
-                unsigned i;
-
-                errno = 0;
-                l = strtoll(p, &e, 10);
-
-                if (errno != 0)
-                        return -errno;
-
-                if (l < 0)
-                        return -ERANGE;
-
-                if (e == p)
-                        return -EINVAL;
-
-                e += strspn(e, WHITESPACE);
-
-                for (i = 0; i < ELEMENTSOF(table); i++)
-                        if (startswith(e, table[i].suffix)) {
-                                r += (usec_t) l * table[i].usec;
-                                p = e + strlen(table[i].suffix);
-                                break;
-                        }
-
-                if (i >= ELEMENTSOF(table))
-                        return -EINVAL;
-
-        } while (*p != 0);
-
-        *usec = r;
-
-        return 0;
-}
-
-int parse_nsec(const char *t, nsec_t *nsec) {
-        static const struct {
-                const char *suffix;
-                nsec_t nsec;
-        } table[] = {
-                { "seconds", NSEC_PER_SEC },
-                { "second", NSEC_PER_SEC },
-                { "sec", NSEC_PER_SEC },
-                { "s", NSEC_PER_SEC },
-                { "minutes", NSEC_PER_MINUTE },
-                { "minute", NSEC_PER_MINUTE },
-                { "min", NSEC_PER_MINUTE },
-                { "months", NSEC_PER_MONTH },
-                { "month", NSEC_PER_MONTH },
-                { "msec", NSEC_PER_MSEC },
-                { "ms", NSEC_PER_MSEC },
-                { "m", NSEC_PER_MINUTE },
-                { "hours", NSEC_PER_HOUR },
-                { "hour", NSEC_PER_HOUR },
-                { "hr", NSEC_PER_HOUR },
-                { "h", NSEC_PER_HOUR },
-                { "days", NSEC_PER_DAY },
-                { "day", NSEC_PER_DAY },
-                { "d", NSEC_PER_DAY },
-                { "weeks", NSEC_PER_WEEK },
-                { "week", NSEC_PER_WEEK },
-                { "w", NSEC_PER_WEEK },
-                { "years", NSEC_PER_YEAR },
-                { "year", NSEC_PER_YEAR },
-                { "y", NSEC_PER_YEAR },
-                { "usec", NSEC_PER_USEC },
-                { "us", NSEC_PER_USEC },
-                { "nsec", 1ULL },
-                { "ns", 1ULL },
-                { "", 1ULL }, /* default is nsec */
-        };
-
-        const char *p;
-        nsec_t r = 0;
-
-        assert(t);
-        assert(nsec);
-
-        p = t;
-        do {
-                long long l;
-                char *e;
-                unsigned i;
-
-                errno = 0;
-                l = strtoll(p, &e, 10);
-
-                if (errno != 0)
-                        return -errno;
-
-                if (l < 0)
-                        return -ERANGE;
-
-                if (e == p)
-                        return -EINVAL;
-
-                e += strspn(e, WHITESPACE);
-
-                for (i = 0; i < ELEMENTSOF(table); i++)
-                        if (startswith(e, table[i].suffix)) {
-                                r += (nsec_t) l * table[i].nsec;
-                                p = e + strlen(table[i].suffix);
-                                break;
-                        }
-
-                if (i >= ELEMENTSOF(table))
-                        return -EINVAL;
-
-        } while (*p != 0);
-
-        *nsec = r;
-
-        return 0;
-}
-
 int parse_bytes(const char *t, off_t *bytes) {
         static const struct {
                 const char *suffix;
@@ -3256,7 +2869,8 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
         snprintf(fn, sizeof(fn), "/dev/char/%u:%u", major(devnr), minor(devnr));
         char_array_0(fn);
 
-        if ((k = readlink_malloc(fn, &s)) < 0) {
+        k = readlink_malloc(fn, &s);
+        if (k < 0) {
 
                 if (k != -ENOENT)
                         return k;
@@ -3277,7 +2891,8 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
                  * symlink in /dev/char. Let's return something
                  * vaguely useful. */
 
-                if (!(b = strdup(fn + 5)))
+                b = strdup(fn + 5);
+                if (!b)
                         return -ENOMEM;
 
                 *r = b;
@@ -3400,6 +3015,12 @@ int rm_rf_children_dangerous(int fd, bool only_dirs, bool honour_sticky, struct
         return ret;
 }
 
+static int is_temporary_fs(struct statfs *s) {
+        assert(s);
+        return s->f_type == TMPFS_MAGIC ||
+                (long)s->f_type == (long)RAMFS_MAGIC;
+}
+
 int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) {
         struct statfs s;
 
@@ -3413,9 +3034,7 @@ int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root
         /* We refuse to clean disk file systems with this call. This
          * is extra paranoia just to be sure we never ever remove
          * non-state data */
-
-        if (s.f_type != TMPFS_MAGIC &&
-            s.f_type != RAMFS_MAGIC) {
+        if (!is_temporary_fs(&s)) {
                 log_error("Attempted to remove disk file system, and we can't allow that.");
                 close_nointr_nofail(fd);
                 return -EPERM;
@@ -3448,8 +3067,7 @@ static int rm_rf_internal(const char *path, bool only_dirs, bool delete_root, bo
                         if (statfs(path, &s) < 0)
                                 return -errno;
 
-                        if (s.f_type != TMPFS_MAGIC &&
-                            s.f_type != RAMFS_MAGIC) {
+                        if (!is_temporary_fs(&s)) {
                                 log_error("Attempted to remove disk file system, and we can't allow that.");
                                 return -EPERM;
                         }
@@ -3468,8 +3086,7 @@ static int rm_rf_internal(const char *path, bool only_dirs, bool delete_root, bo
                         return -errno;
                 }
 
-                if (s.f_type != TMPFS_MAGIC &&
-                    s.f_type != RAMFS_MAGIC) {
+                if (!is_temporary_fs(&s)) {
                         log_error("Attempted to remove disk file system, and we can't allow that.");
                         close_nointr_nofail(fd);
                         return -EPERM;
@@ -3801,7 +3418,7 @@ int fd_columns(int fd) {
 
 unsigned columns(void) {
         const char *e;
-        unsigned c;
+        int c;
 
         if (_likely_(cached_columns > 0))
                 return cached_columns;
@@ -3809,7 +3426,7 @@ unsigned columns(void) {
         c = 0;
         e = getenv("COLUMNS");
         if (e)
-                safe_atou(e, &c);
+                safe_atoi(e, &c);
 
         if (c <= 0)
                 c = fd_columns(STDOUT_FILENO);
@@ -4118,35 +3735,6 @@ int signal_from_string_try_harder(const char *s) {
         return signo;
 }
 
-void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
-
-        assert(f);
-        assert(name);
-        assert(t);
-
-        if (!dual_timestamp_is_set(t))
-                return;
-
-        fprintf(f, "%s=%llu %llu\n",
-                name,
-                (unsigned long long) t->realtime,
-                (unsigned long long) t->monotonic);
-}
-
-void dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
-        unsigned long long a, b;
-
-        assert(value);
-        assert(t);
-
-        if (sscanf(value, "%lli %llu", &a, &b) != 2)
-                log_debug("Failed to parse finish timestamp value %s", value);
-        else {
-                t->realtime = a;
-                t->monotonic = b;
-        }
-}
-
 static char *tag_to_udev_node(const char *tagvalue, const char *by) {
         char *dn, *t, *u;
         int r;
@@ -5767,7 +5355,7 @@ bool in_initrd(void) {
 
         saved = access("/etc/initrd-release", F_OK) >= 0 &&
                 statfs("/", &s) >= 0 &&
-                (s.f_type == TMPFS_MAGIC || s.f_type == RAMFS_MAGIC);
+                is_temporary_fs(&s);
 
         return saved;
 }
@@ -5966,139 +5554,6 @@ bool string_is_safe(const char *p) {
         return true;
 }
 
-int parse_timestamp(const char *t, usec_t *usec) {
-        const char *k;
-        struct tm tm, copy;
-        time_t x;
-        usec_t plus = 0, minus = 0, ret;
-        int r;
-
-        /*
-         * Allowed syntaxes:
-         *
-         *   2012-09-22 16:34:22
-         *   2012-09-22 16:34     (seconds will be set to 0)
-         *   2012-09-22           (time will be set to 00:00:00)
-         *   16:34:22             (date will be set to today)
-         *   16:34                (date will be set to today, seconds to 0)
-         *   now
-         *   yesterday            (time is set to 00:00:00)
-         *   today                (time is set to 00:00:00)
-         *   tomorrow             (time is set to 00:00:00)
-         *   +5min
-         *   -5days
-         *
-         */
-
-        assert(t);
-        assert(usec);
-
-        x = time(NULL);
-        assert_se(localtime_r(&x, &tm));
-
-        if (streq(t, "now"))
-                goto finish;
-
-        else if (streq(t, "today")) {
-                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
-                goto finish;
-
-        } else if (streq(t, "yesterday")) {
-                tm.tm_mday --;
-                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
-                goto finish;
-
-        } else if (streq(t, "tomorrow")) {
-                tm.tm_mday ++;
-                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
-                goto finish;
-
-        } else if (t[0] == '+') {
-
-                r = parse_usec(t+1, &plus);
-                if (r < 0)
-                        return r;
-
-                goto finish;
-        } else if (t[0] == '-') {
-
-                r = parse_usec(t+1, &minus);
-                if (r < 0)
-                        return r;
-
-                goto finish;
-        }
-
-        copy = tm;
-        k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
-        if (k && *k == 0)
-                goto finish;
-
-        tm = copy;
-        k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
-        if (k && *k == 0)
-                goto finish;
-
-        tm = copy;
-        k = strptime(t, "%y-%m-%d %H:%M", &tm);
-        if (k && *k == 0) {
-                tm.tm_sec = 0;
-                goto finish;
-        }
-
-        tm = copy;
-        k = strptime(t, "%Y-%m-%d %H:%M", &tm);
-        if (k && *k == 0) {
-                tm.tm_sec = 0;
-                goto finish;
-        }
-
-        tm = copy;
-        k = strptime(t, "%y-%m-%d", &tm);
-        if (k && *k == 0) {
-                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
-                goto finish;
-        }
-
-        tm = copy;
-        k = strptime(t, "%Y-%m-%d", &tm);
-        if (k && *k == 0) {
-                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
-                goto finish;
-        }
-
-        tm = copy;
-        k = strptime(t, "%H:%M:%S", &tm);
-        if (k && *k == 0)
-                goto finish;
-
-        tm = copy;
-        k = strptime(t, "%H:%M", &tm);
-        if (k && *k == 0) {
-                tm.tm_sec = 0;
-                goto finish;
-        }
-
-        return -EINVAL;
-
-finish:
-        x = mktime(&tm);
-        if (x == (time_t) -1)
-                return -EINVAL;
-
-        ret = (usec_t) x * USEC_PER_SEC;
-
-        ret += plus;
-        if (ret > minus)
-                ret -= minus;
-        else
-                ret = 0;
-
-        *usec = ret;
-
-        return 0;
-}
-
 /* hey glibc, APIs with callbacks without a user pointer are so useless */
 void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
                  int (*compar) (const void *, const void *, void *), void *arg) {
@@ -6213,3 +5668,86 @@ oom:
         free(r);
         return NULL;
 }
+
+char *strip_tab_ansi(char **ibuf, size_t *_isz) {
+        const char *i, *begin;
+        enum {
+                STATE_OTHER,
+                STATE_ESCAPE,
+                STATE_BRACKET
+        } state = STATE_OTHER;
+        char *obuf = NULL;
+        size_t osz = 0, isz;
+        FILE *f;
+
+        assert(ibuf);
+        assert(*ibuf);
+
+        /* Strips ANSI color and replaces TABs by 8 spaces */
+
+        isz = _isz ? *_isz : strlen(*ibuf);
+
+        f = open_memstream(&obuf, &osz);
+        if (!f)
+                return NULL;
+
+        for (i = *ibuf; i < *ibuf + isz + 1; i++) {
+
+                switch (state) {
+
+                case STATE_OTHER:
+                        if (i >= *ibuf + isz) /* EOT */
+                                break;
+                        else if (*i == '\x1B')
+                                state = STATE_ESCAPE;
+                        else if (*i == '\t')
+                                fputs("        ", f);
+                        else
+                                fputc(*i, f);
+                        break;
+
+                case STATE_ESCAPE:
+                        if (i >= *ibuf + isz) { /* EOT */
+                                fputc('\x1B', f);
+                                break;
+                        } else if (*i == '[') {
+                                state = STATE_BRACKET;
+                                begin = i + 1;
+                        } else {
+                                fputc('\x1B', f);
+                                fputc(*i, f);
+                                state = STATE_OTHER;
+                        }
+
+                        break;
+
+                case STATE_BRACKET:
+
+                        if (i >= *ibuf + isz || /* EOT */
+                            (!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) {
+                                fputc('\x1B', f);
+                                fputc('[', f);
+                                state = STATE_OTHER;
+                                i = begin-1;
+                        } else if (*i == 'm')
+                                state = STATE_OTHER;
+                        break;
+                }
+        }
+
+        if (ferror(f)) {
+                fclose(f);
+                free(obuf);
+                return NULL;
+        }
+
+        fclose(f);
+
+        free(*ibuf);
+        *ibuf = obuf;
+
+        if (_isz)
+                *_isz = osz;
+
+        return obuf;
+}