chiark / gitweb /
various cleanups
[elogind.git] / util.c
diff --git a/util.c b/util.c
index 4bec220f7a1dbfad1c1868d8228d973bb77863df..b4b07e9d1b827ac34bbc397d36c59abf57e3f7ff 100644 (file)
--- a/util.c
+++ b/util.c
@@ -5,6 +5,8 @@
 #include <unistd.h>
 #include <errno.h>
 #include <stdlib.h>
+#include <signal.h>
+#include <stdio.h>
 
 #include "macro.h"
 #include "util.h"
@@ -81,7 +83,7 @@ bool startswith(const char *s, const char *prefix) {
         return memcmp(s, prefix, pl) == 0;
 }
 
-int nointr_close(int fd) {
+int close_nointr(int fd) {
         assert(fd >= 0);
 
         for (;;) {
@@ -98,9 +100,9 @@ int nointr_close(int fd) {
 int parse_boolean(const char *v) {
         assert(v);
 
-        if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
+        if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
                 return 1;
-        else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
+        else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
                 return 0;
 
         return -EINVAL;
@@ -108,7 +110,7 @@ int parse_boolean(const char *v) {
 
 int safe_atou(const char *s, unsigned *ret_u) {
         char *x = NULL;
-        unsigned l;
+        unsigned long l;
 
         assert(s);
         assert(ret_u);
@@ -119,7 +121,7 @@ int safe_atou(const char *s, unsigned *ret_u) {
         if (!x || *x || errno)
                 return errno ? -errno : -EINVAL;
 
-        if ((unsigned) l != l)
+        if ((unsigned long) (unsigned) l != l)
                 return -ERANGE;
 
         *ret_u = (unsigned) l;
@@ -128,7 +130,7 @@ int safe_atou(const char *s, unsigned *ret_u) {
 
 int safe_atoi(const char *s, int *ret_i) {
         char *x = NULL;
-        int l;
+        long l;
 
         assert(s);
         assert(ret_i);
@@ -139,15 +141,80 @@ int safe_atoi(const char *s, int *ret_i) {
         if (!x || *x || errno)
                 return errno ? -errno : -EINVAL;
 
-        if ((int) l != l)
+        if ((long) (int) l != l)
                 return -ERANGE;
 
-        *ret_i = (unsigned) l;
+        *ret_i = (int) l;
         return 0;
 }
 
-/* What is interpreted as whitespace? */
-#define WHITESPACE " \t\n"
+int safe_atolu(const char *s, long unsigned *ret_lu) {
+        char *x = NULL;
+        unsigned long l;
+
+        assert(s);
+        assert(ret_lu);
+
+        errno = 0;
+        l = strtoul(s, &x, 0);
+
+        if (!x || *x || errno)
+                return errno ? -errno : -EINVAL;
+
+        *ret_lu = l;
+        return 0;
+}
+
+int safe_atoli(const char *s, long int *ret_li) {
+        char *x = NULL;
+        long l;
+
+        assert(s);
+        assert(ret_li);
+
+        errno = 0;
+        l = strtol(s, &x, 0);
+
+        if (!x || *x || errno)
+                return errno ? -errno : -EINVAL;
+
+        *ret_li = l;
+        return 0;
+}
+
+int safe_atollu(const char *s, long long unsigned *ret_llu) {
+        char *x = NULL;
+        unsigned long long l;
+
+        assert(s);
+        assert(ret_llu);
+
+        errno = 0;
+        l = strtoull(s, &x, 0);
+
+        if (!x || *x || errno)
+                return errno ? -errno : -EINVAL;
+
+        *ret_llu = l;
+        return 0;
+}
+
+int safe_atolli(const char *s, long long int *ret_lli) {
+        char *x = NULL;
+        long long l;
+
+        assert(s);
+        assert(ret_lli);
+
+        errno = 0;
+        l = strtoll(s, &x, 0);
+
+        if (!x || *x || errno)
+                return errno ? -errno : -EINVAL;
+
+        *ret_lli = l;
+        return 0;
+}
 
 /* Split a string into words. */
 char *split_spaces(const char *c, size_t *l, char **state) {
@@ -164,3 +231,174 @@ char *split_spaces(const char *c, size_t *l, char **state) {
 
         return (char*) current;
 }
+
+/* Split a string into words, but consider strings enclosed in '' and
+ * "" as words even if they include spaces. */
+char *split_quoted(const char *c, size_t *l, char **state) {
+        char *current;
+
+        current = *state ? *state : (char*) c;
+
+        if (!*current || *c == 0)
+                return NULL;
+
+        current += strspn(current, WHITESPACE);
+
+        if (*current == '\'') {
+                current ++;
+                *l = strcspn(current, "'");
+                *state = current+*l;
+
+                if (**state == '\'')
+                        (*state)++;
+        } else if (*current == '\"') {
+                current ++;
+                *l = strcspn(current+1, "\"");
+                *state = current+*l;
+
+                if (**state == '\"')
+                        (*state)++;
+        } else {
+                *l = strcspn(current, WHITESPACE);
+                *state = current+*l;
+        }
+
+        /* FIXME: Cannot deal with strings that have spaces AND ticks
+         * in them */
+
+        return (char*) current;
+}
+
+const char *sigchld_code(int code) {
+
+        if (code == CLD_EXITED)
+                return "exited";
+        else if (code == CLD_KILLED)
+                return "killed";
+        else if (code == CLD_DUMPED)
+                return "dumped";
+        else if (code == CLD_TRAPPED)
+                return "trapped";
+        else if (code == CLD_STOPPED)
+                return "stopped";
+        else if (code == CLD_CONTINUED)
+                return "continued";
+
+        return "unknown";
+}
+
+int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
+        int r;
+        FILE *f;
+        char fn[132], line[256], *p;
+        long long unsigned ppid;
+
+        assert(pid >= 0);
+        assert(_ppid);
+
+        assert_se(snprintf(fn, sizeof(fn)-1, "/proc/%llu/stat", (unsigned long long) pid) < (int) (sizeof(fn)-1));
+        fn[sizeof(fn)-1] = 0;
+
+        if (!(f = fopen(fn, "r")))
+                return -errno;
+
+        if (!(fgets(line, sizeof(line), f))) {
+                r = -errno;
+                fclose(f);
+                return r;
+        }
+
+        fclose(f);
+
+        /* Let's skip the pid and comm fields. The latter is enclosed
+         * in () but does not escape any () in its value, so let's
+         * skip over it manually */
+
+        if (!(p = strrchr(line, ')')))
+                return -EIO;
+
+        p++;
+
+        if (sscanf(p, " "
+                   "%*c "  /* state */
+                   "%llu ", /* ppid */
+                   &ppid) != 1)
+                return -EIO;
+
+        if ((long long unsigned) (pid_t) ppid != ppid)
+                return -ERANGE;
+
+        *_ppid = (pid_t) ppid;
+
+        return 0;
+}
+
+int write_one_line_file(const char *fn, const char *line) {
+        FILE *f;
+        int r;
+
+        assert(fn);
+        assert(line);
+
+        if (!(f = fopen(fn, "we")))
+                return -errno;
+
+        if (fputs(line, f) < 0) {
+                r = -errno;
+                goto finish;
+        }
+
+        r = 0;
+finish:
+        fclose(f);
+        return r;
+}
+
+int read_one_line_file(const char *fn, char **line) {
+        FILE *f;
+        int r;
+        char t[64], *c;
+
+        assert(fn);
+        assert(line);
+
+        if (!(f = fopen(fn, "re")))
+                return -errno;
+
+        if (!(fgets(t, sizeof(t), f))) {
+                r = -errno;
+                goto finish;
+        }
+
+        if (!(c = strdup(t))) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        *line = c;
+        r = 0;
+
+finish:
+        fclose(f);
+        return r;
+}
+
+char *strappend(const char *s, const char *suffix) {
+        size_t a, b;
+        char *r;
+
+        assert(s);
+        assert(suffix);
+
+        a = strlen(s);
+        b = strlen(suffix);
+
+        if (!(r = new(char, a+b+1)))
+                return NULL;
+
+        memcpy(r, s, a);
+        memcpy(r+a, suffix, b);
+        r[a+b] = 0;
+
+        return r;
+}