chiark / gitweb /
Get rid of some more unused defines and dirs
[elogind.git] / src / shared / util.c
index 845c7ea..7298473 100644 (file)
@@ -94,6 +94,9 @@
 #include "def.h"
 #include "sparse-endian.h"
 
+/* Put this test here for a lack of better place */
+assert_cc(EAGAIN == EWOULDBLOCK);
+
 int saved_argc = 0;
 char **saved_argv = NULL;
 
@@ -1344,6 +1347,125 @@ char *cescape(const char *s) {
         return r;
 }
 
+static int cunescape_one(const char *p, size_t length, char *ret) {
+        int r = 1;
+
+        assert(p);
+        assert(*p);
+        assert(ret);
+
+        if (length != (size_t) -1 && length < 1)
+                return -EINVAL;
+
+        switch (p[0]) {
+
+        case 'a':
+                *ret = '\a';
+                break;
+        case 'b':
+                *ret = '\b';
+                break;
+        case 'f':
+                *ret = '\f';
+                break;
+        case 'n':
+                *ret = '\n';
+                break;
+        case 'r':
+                *ret = '\r';
+                break;
+        case 't':
+                *ret = '\t';
+                break;
+        case 'v':
+                *ret = '\v';
+                break;
+        case '\\':
+                *ret = '\\';
+                break;
+        case '"':
+                *ret = '"';
+                break;
+        case '\'':
+                *ret = '\'';
+                break;
+
+        case 's':
+                /* This is an extension of the XDG syntax files */
+                *ret = ' ';
+                break;
+
+        case 'x': {
+                /* hexadecimal encoding */
+                int a, b;
+
+                if (length != (size_t) -1 && length < 3)
+                        return -EINVAL;
+
+                a = unhexchar(p[1]);
+                if (a < 0)
+                        return -EINVAL;
+
+                b = unhexchar(p[2]);
+                if (b < 0)
+                        return -EINVAL;
+
+                /* don't allow NUL bytes */
+                if (a == 0 && b == 0)
+                        return -EINVAL;
+
+                *ret = (char) ((a << 4) | b);
+                r = 3;
+                break;
+        }
+
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7': {
+                /* octal encoding */
+                int a, b, c, m;
+
+                if (length != (size_t) -1 && length < 4)
+                        return -EINVAL;
+
+                a = unoctchar(p[0]);
+                if (a < 0)
+                        return -EINVAL;
+
+                b = unoctchar(p[1]);
+                if (b < 0)
+                        return -EINVAL;
+
+                c = unoctchar(p[2]);
+                if (c < 0)
+                        return -EINVAL;
+
+                /* don't allow NUL bytes */
+                if (a == 0 && b == 0 && c == 0)
+                        return -EINVAL;
+
+                /* Don't allow bytes above 255 */
+                m = (a << 6) | (b << 3) | c;
+                if (m > 255)
+                        return -EINVAL;
+
+                *ret = (char) m;
+                r = 3;
+                break;
+        }
+
+        default:
+                return -EINVAL;
+        }
+
+        return r;
+}
+
 char *cunescape_length_with_prefix(const char *s, size_t length, const char *prefix) {
         char *r, *t;
         const char *f;
@@ -1363,115 +1485,27 @@ char *cunescape_length_with_prefix(const char *s, size_t length, const char *pre
                 memcpy(r, prefix, pl);
 
         for (f = s, t = r + pl; f < s + length; f++) {
-                size_t remaining = s + length - f;
+                size_t remaining;
+                int k;
+
+                remaining = s + length - f;
                 assert(remaining > 0);
 
-                if (*f != '\\') {        /* a literal literal */
+                if (*f != '\\' || remaining == 1) {
+                        /* a literal literal, or a trailing backslash, copy verbatim */
                         *(t++) = *f;
                         continue;
                 }
 
-                if (--remaining == 0) {  /* copy trailing backslash verbatim */
-                        *(t++) = *f;
-                        break;
-                }
-
-                f++;
-
-                switch (*f) {
-
-                case 'a':
-                        *(t++) = '\a';
-                        break;
-                case 'b':
-                        *(t++) = '\b';
-                        break;
-                case 'f':
-                        *(t++) = '\f';
-                        break;
-                case 'n':
-                        *(t++) = '\n';
-                        break;
-                case 'r':
-                        *(t++) = '\r';
-                        break;
-                case 't':
-                        *(t++) = '\t';
-                        break;
-                case 'v':
-                        *(t++) = '\v';
-                        break;
-                case '\\':
-                        *(t++) = '\\';
-                        break;
-                case '"':
-                        *(t++) = '"';
-                        break;
-                case '\'':
-                        *(t++) = '\'';
-                        break;
-
-                case 's':
-                        /* This is an extension of the XDG syntax files */
-                        *(t++) = ' ';
-                        break;
-
-                case 'x': {
-                        /* hexadecimal encoding */
-                        int a = -1, b = -1;
-
-                        if (remaining >= 2) {
-                                a = unhexchar(f[1]);
-                                b = unhexchar(f[2]);
-                        }
-
-                        if (a < 0 || b < 0 || (a == 0 && b == 0)) {
-                                /* Invalid escape code, let's take it literal then */
-                                *(t++) = '\\';
-                                *(t++) = 'x';
-                        } else {
-                                *(t++) = (char) ((a << 4) | b);
-                                f += 2;
-                        }
-
-                        break;
-                }
-
-                case '0':
-                case '1':
-                case '2':
-                case '3':
-                case '4':
-                case '5':
-                case '6':
-                case '7': {
-                        /* octal encoding */
-                        int a = -1, b = -1, c = -1;
-
-                        if (remaining >= 3) {
-                                a = unoctchar(f[0]);
-                                b = unoctchar(f[1]);
-                                c = unoctchar(f[2]);
-                        }
-
-                        if (a < 0 || b < 0 || c < 0 || (a == 0 && b == 0 && c == 0)) {
-                                /* Invalid escape code, let's take it literal then */
-                                *(t++) = '\\';
-                                *(t++) = f[0];
-                        } else {
-                                *(t++) = (char) ((a << 6) | (b << 3) | c);
-                                f += 2;
-                        }
-
-                        break;
-                }
-
-                default:
+                k = cunescape_one(f + 1, remaining - 1, t);
+                if (k < 0) {
                         /* Invalid escape code, let's take it literal then */
                         *(t++) = '\\';
-                        *(t++) = *f;
-                        break;
+                        continue;
                 }
+
+                f += k;
+                t++;
         }
 
         *t = 0;
@@ -2848,7 +2882,7 @@ int getttyname_malloc(int fd, char **ret) {
 
 int getttyname_harder(int fd, char **r) {
         int k;
-        char *s;
+        char *s = NULL;
 
         k = getttyname_malloc(fd, &s);
         if (k < 0)
@@ -2923,31 +2957,30 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
 
                 /* This is an ugly hack */
                 if (major(devnr) == 136) {
-                        asprintf(&b, "pts/%u", minor(devnr));
-                        goto finish;
-                }
+                        if (asprintf(&b, "pts/%u", minor(devnr)) < 0)
+                                return -ENOMEM;
+                } else {
+                        /* Probably something like the ptys which have no
+                         * symlink in /dev/char. Let's return something
+                         * vaguely useful. */
 
-                /* Probably something like the ptys which have no
-                 * symlink in /dev/char. Let's return something
-                 * vaguely useful. */
+                        b = strdup(fn + 5);
+                        if (!b)
+                                return -ENOMEM;
+                }
+        } else {
+                if (startswith(s, "/dev/"))
+                        p = s + 5;
+                else if (startswith(s, "../"))
+                        p = s + 3;
+                else
+                        p = s;
 
-                b = strdup(fn + 5);
-                goto finish;
+                b = strdup(p);
+                if (!b)
+                        return -ENOMEM;
         }
 
-        if (startswith(s, "/dev/"))
-                p = s + 5;
-        else if (startswith(s, "../"))
-                p = s + 3;
-        else
-                p = s;
-
-        b = strdup(p);
-
-finish:
-        if (!b)
-                return -ENOMEM;
-
         *r = b;
         if (_devnr)
                 *_devnr = devnr;
@@ -3402,14 +3435,14 @@ char **replace_env_argv(char **argv, char **env) {
                 /* If $FOO appears as single word, replace it by the split up variable */
                 if ((*i)[0] == '$' && (*i)[1] != '{') {
                         char *e;
-                        char **w, **m;
+                        char **w, **m = NULL;
                         unsigned q;
 
                         e = strv_env_get(env, *i+1);
                         if (e) {
                                 int r;
 
-                                r = strv_split_quoted(&m, e, true);
+                                r = strv_split_quoted(&m, e, UNQUOTE_RELAX);
                                 if (r < 0) {
                                         ret[k] = NULL;
                                         strv_free(ret);
@@ -4119,8 +4152,7 @@ static int do_execute(char **directories, usec_t timeout, char *argv[]) {
                         if (null_or_empty_path(path)) {
                                 log_debug("%s is empty (a mask).", path);
                                 continue;
-                        } else
-                                log_debug("%s will be executed.", path);
+                        }
 
                         pid = fork();
                         if (pid < 0) {
@@ -6381,7 +6413,7 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) {
                 _cleanup_free_ char *word = NULL;
                 char *value = NULL;
 
-                r = unquote_first_word(&p, &word, true);
+                r = unquote_first_word(&p, &word, UNQUOTE_RELAX);
                 if (r < 0)
                         return r;
                 if (r == 0)
@@ -6421,7 +6453,7 @@ int get_proc_cmdline_key(const char *key, char **value) {
                 _cleanup_free_ char *word = NULL;
                 const char *e;
 
-                r = unquote_first_word(&p, &word, true);
+                r = unquote_first_word(&p, &word, UNQUOTE_RELAX);
                 if (r < 0)
                         return r;
                 if (r == 0)
@@ -7274,9 +7306,10 @@ int is_dir(const char* path, bool follow) {
         return !!S_ISDIR(st.st_mode);
 }
 
-int unquote_first_word(const char **p, char **ret, bool relax) {
+int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
         _cleanup_free_ char *s = NULL;
         size_t allocated = 0, sz = 0;
+        int r;
 
         enum {
                 START,
@@ -7334,7 +7367,7 @@ int unquote_first_word(const char **p, char **ret, bool relax) {
 
                 case VALUE_ESCAPE:
                         if (c == 0) {
-                                if (relax)
+                                if (flags & UNQUOTE_RELAX)
                                         goto finish;
                                 return -EINVAL;
                         }
@@ -7342,6 +7375,14 @@ int unquote_first_word(const char **p, char **ret, bool relax) {
                         if (!GREEDY_REALLOC(s, allocated, sz+2))
                                 return -ENOMEM;
 
+                        if (flags & UNQUOTE_CUNESCAPE) {
+                                r = cunescape_one(*p, (size_t) -1, &c);
+                                if (r < 0)
+                                        return -EINVAL;
+
+                                (*p) += r - 1;
+                        }
+
                         s[sz++] = c;
                         state = VALUE;
 
@@ -7349,7 +7390,7 @@ int unquote_first_word(const char **p, char **ret, bool relax) {
 
                 case SINGLE_QUOTE:
                         if (c == 0) {
-                                if (relax)
+                                if (flags & UNQUOTE_RELAX)
                                         goto finish;
                                 return -EINVAL;
                         } else if (c == '\'')
@@ -7367,7 +7408,7 @@ int unquote_first_word(const char **p, char **ret, bool relax) {
 
                 case SINGLE_QUOTE_ESCAPE:
                         if (c == 0) {
-                                if (relax)
+                                if (flags & UNQUOTE_RELAX)
                                         goto finish;
                                 return -EINVAL;
                         }
@@ -7375,6 +7416,14 @@ int unquote_first_word(const char **p, char **ret, bool relax) {
                         if (!GREEDY_REALLOC(s, allocated, sz+2))
                                 return -ENOMEM;
 
+                        if (flags & UNQUOTE_CUNESCAPE) {
+                                r = cunescape_one(*p, (size_t) -1, &c);
+                                if (r < 0)
+                                        return -EINVAL;
+
+                                (*p) += r - 1;
+                        }
+
                         s[sz++] = c;
                         state = SINGLE_QUOTE;
                         break;
@@ -7397,7 +7446,7 @@ int unquote_first_word(const char **p, char **ret, bool relax) {
 
                 case DOUBLE_QUOTE_ESCAPE:
                         if (c == 0) {
-                                if (relax)
+                                if (flags & UNQUOTE_RELAX)
                                         goto finish;
                                 return -EINVAL;
                         }
@@ -7405,6 +7454,14 @@ int unquote_first_word(const char **p, char **ret, bool relax) {
                         if (!GREEDY_REALLOC(s, allocated, sz+2))
                                 return -ENOMEM;
 
+                        if (flags & UNQUOTE_CUNESCAPE) {
+                                r = cunescape_one(*p, (size_t) -1, &c);
+                                if (r < 0)
+                                        return -EINVAL;
+
+                                (*p) += r - 1;
+                        }
+
                         s[sz++] = c;
                         state = DOUBLE_QUOTE;
                         break;
@@ -7434,7 +7491,7 @@ finish:
         return 1;
 }
 
-int unquote_many_words(const char **p, ...) {
+int unquote_many_words(const char **p, UnquoteFlags flags, ...) {
         va_list ap;
         char **l;
         int n = 0, i, c, r;
@@ -7445,7 +7502,7 @@ int unquote_many_words(const char **p, ...) {
         assert(p);
 
         /* Count how many words are expected */
-        va_start(ap, p);
+        va_start(ap, flags);
         for (;;) {
                 if (!va_arg(ap, char **))
                         break;
@@ -7460,7 +7517,7 @@ int unquote_many_words(const char **p, ...) {
         l = newa0(char*, n);
         for (c = 0; c < n; c++) {
 
-                r = unquote_first_word(p, &l[c], false);
+                r = unquote_first_word(p, &l[c], flags);
                 if (r < 0) {
                         int j;
 
@@ -7476,7 +7533,7 @@ int unquote_many_words(const char **p, ...) {
 
         /* If we managed to parse all words, return them in the passed
          * in parameters */
-        va_start(ap, p);
+        va_start(ap, flags);
         for (i = 0; i < n; i++) {
                 char **v;
 
@@ -7737,71 +7794,6 @@ int fd_setcrtime(int fd, usec_t usec) {
         return 0;
 }
 
-int same_fd(int a, int b) {
-        struct stat sta, stb;
-        pid_t pid;
-        int r, fa, fb;
-
-        assert(a >= 0);
-        assert(b >= 0);
-
-        /* Compares two file descriptors. Note that semantics are
-         * quite different depending on whether we have kcmp() or we
-         * don't. If we have kcmp() this will only return true for
-         * dup()ed file descriptors, but not otherwise. If we don't
-         * have kcmp() this will also return true for two fds of the same
-         * file, created by separate open() calls. Since we use this
-         * call mostly for filtering out duplicates in the fd store
-         * this difference hopefully doesn't matter too much. */
-
-        if (a == b)
-                return true;
-
-        /* Try to use kcmp() if we have it. */
-        pid = getpid();
-        r = kcmp(pid, pid, KCMP_FILE, a, b);
-        if (r == 0)
-                return true;
-        if (r > 0)
-                return false;
-        if (errno != ENOSYS)
-                return -errno;
-
-        /* We don't have kcmp(), use fstat() instead. */
-        if (fstat(a, &sta) < 0)
-                return -errno;
-
-        if (fstat(b, &stb) < 0)
-                return -errno;
-
-        if ((sta.st_mode & S_IFMT) != (stb.st_mode & S_IFMT))
-                return false;
-
-        /* We consider all device fds different, since two device fds
-         * might refer to quite different device contexts even though
-         * they share the same inode and backing dev_t. */
-
-        if (S_ISCHR(sta.st_mode) || S_ISBLK(sta.st_mode))
-                return false;
-
-        if (sta.st_dev != stb.st_dev || sta.st_ino != stb.st_ino)
-                return false;
-
-        /* The fds refer to the same inode on disk, let's also check
-         * if they have the same fd flags. This is useful to
-         * distuingish the read and write side of a pipe created with
-         * pipe(). */
-        fa = fcntl(a, F_GETFL);
-        if (fa < 0)
-                return -errno;
-
-        fb = fcntl(b, F_GETFL);
-        if (fb < 0)
-                return -errno;
-
-        return fa == fb;
-}
-
 int chattr_fd(int fd, bool b, unsigned mask) {
         unsigned old_attr, new_attr;
 
@@ -7842,6 +7834,28 @@ int chattr_path(const char *p, bool b, unsigned mask) {
         return chattr_fd(fd, b, mask);
 }
 
+int change_attr_fd(int fd, unsigned value, unsigned mask) {
+        unsigned old_attr, new_attr;
+
+        assert(fd >= 0);
+
+        if (mask == 0)
+                return 0;
+
+        if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0)
+                return -errno;
+
+        new_attr = (old_attr & ~mask) |(value & mask);
+
+        if (new_attr == old_attr)
+                return 0;
+
+        if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0)
+                return -errno;
+
+        return 0;
+}
+
 int read_attr_fd(int fd, unsigned *ret) {
         assert(fd >= 0);