chiark / gitweb /
Revert "log_error() if inotify_add_watch() fails"
[elogind.git] / src / shared / util.c
index 1d30ea585133addaea9a862571c77ea195863c96..d754c836f2b5386cd01f711fb71b74e030a4aa30 100644 (file)
@@ -183,18 +183,25 @@ bool first_word(const char *s, const char *word) {
 }
 
 int close_nointr(int fd) {
-        assert(fd >= 0);
-
-        for (;;) {
-                int r;
+        int r;
 
-                r = close(fd);
-                if (r >= 0)
-                        return r;
+        assert(fd >= 0);
+        r = close(fd);
 
-                if (errno != EINTR)
-                        return -errno;
-        }
+        /* Just ignore EINTR; a retry loop is the wrong
+         * thing to do on Linux.
+         *
+         * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
+         * https://bugzilla.gnome.org/show_bug.cgi?id=682819
+         * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR
+         * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain
+         */
+        if (_unlikely_(r < 0 && errno == EINTR))
+                return 0;
+        else if (r >= 0)
+                return r;
+        else
+                return -errno;
 }
 
 void close_nointr_nofail(int fd) {
@@ -218,9 +225,9 @@ void close_many(const int fds[], unsigned n_fd) {
 int parse_boolean(const char *v) {
         assert(v);
 
-        if (streq(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' || strcaseeq(v, "on"))
                 return 1;
-        else if (streq(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' || strcaseeq(v, "off"))
                 return 0;
 
         return -EINVAL;
@@ -720,7 +727,7 @@ int parse_env_file(
                                 value = va_arg(ap, char **);
 
                                 n = strlen(key);
-                                if (strncmp(p, key, n) != 0 ||
+                                if (!strneq(p, key, n) ||
                                     p[n] != '=')
                                         continue;
 
@@ -766,77 +773,82 @@ fail:
         return r;
 }
 
-int load_env_file(const char *fname,
-                  char ***rl) {
+int load_env_file(const char *fname, char ***rl) {
 
-        FILE _cleanup_fclose_ *f;
-        char *b;
-        char _cleanup_free_ *c = NULL;
-        char _cleanup_strv_free_ **m = NULL;
+        _cleanup_fclose_ FILE *f;
+        _cleanup_strv_free_ char **m = NULL;
+        _cleanup_free_ char *c = NULL;
 
         assert(fname);
         assert(rl);
 
+        /* This reads an environment file, but will not complain about
+         * any invalid assignments, that needs to be done by the
+         * caller */
+
         f = fopen(fname, "re");
         if (!f)
                 return -errno;
 
         while (!feof(f)) {
-                char l[LINE_MAX], *p, *u, *cs;
-                char **t;
+                char l[LINE_MAX], *p, *cs, *b;
 
                 if (!fgets(l, sizeof(l), f)) {
-                        if (!feof(f))
+                        if (ferror(f))
                                 return -errno;
-                        else if (!c)
-                                break;
+
+                        /* The previous line was a continuation line?
+                         * Let's process it now, before we leave the
+                         * loop */
+                        if (c)
+                                goto process;
+
+                        break;
                 }
 
+                /* Is this a continuation line? If so, just append
+                 * this to c, and go to next line right-away */
                 cs = endswith(l, "\\\n");
                 if (cs) {
                         *cs = '\0';
                         b = strappend(c, l);
                         if (!b)
-                                return log_oom();
+                                return -ENOMEM;
 
                         free(c);
                         c = b;
-                        *l = '\0';
                         continue;
                 }
 
+                /* If the previous line was a continuation line,
+                 * append the current line to it */
                 if (c) {
                         b = strappend(c, l);
                         if (!b)
-                                return log_oom();
+                                return -ENOMEM;
 
                         free(c);
                         c = b;
                 }
 
+        process:
                 p = strstrip(c ? c : l);
 
-                if (!*p)
-                        continue;
+                if (*p && !strchr(COMMENTS, *p)) {
+                        _cleanup_free_ char *u;
+                        int k;
 
-                if (strchr(COMMENTS, *p))
-                        continue;
+                        u = normalize_env_assignment(p);
+                        if (!u)
+                                return -ENOMEM;
 
-                u = normalize_env_assignment(p);
-                if (!u)
-                        return log_oom();
+                        k = strv_extend(&m, u);
+                        if (k < 0)
+                                return -ENOMEM;
+                }
 
                 free(c);
                 c = NULL;
-
-                t = strv_append(m, u);
-                free(u);
-
-                if (!t)
-                        return log_oom();
-
-                strv_free(m);
-                m = t;
         }
 
         *rl = m;
@@ -5904,3 +5916,82 @@ int on_ac_power(void) {
 
         return found_online || !found_offline;
 }
+
+static int search_and_fopen_internal(const char *path, const char *mode, char **search, FILE **_f) {
+        char **i;
+
+        assert(path);
+        assert(mode);
+        assert(_f);
+
+        if (!path_strv_canonicalize_uniq(search))
+                return -ENOMEM;
+
+        STRV_FOREACH(i, search) {
+                _cleanup_free_ char *p = NULL;
+                FILE *f;
+
+                p = strjoin(*i, "/", path, NULL);
+                if (!p)
+                        return -ENOMEM;
+
+                f = fopen(p, mode);
+                if (f) {
+                        *_f = f;
+                        return 0;
+                }
+
+                if (errno != ENOENT)
+                        return -errno;
+        }
+
+        return -ENOENT;
+}
+
+int search_and_fopen(const char *path, const char *mode, const char **search, FILE **_f) {
+        _cleanup_strv_free_ char **copy = NULL;
+
+        assert(path);
+        assert(mode);
+        assert(_f);
+
+        if (path_is_absolute(path)) {
+                FILE *f;
+
+                f = fopen(path, mode);
+                if (f) {
+                        *_f = f;
+                        return 0;
+                }
+
+                return -errno;
+        }
+
+        copy = strv_copy((char**) search);
+        if (!copy)
+                return -ENOMEM;
+
+        return search_and_fopen_internal(path, mode, copy, _f);
+}
+
+int search_and_fopen_nulstr(const char *path, const char *mode, const char *search, FILE **_f) {
+        _cleanup_strv_free_ char **s = NULL;
+
+        if (path_is_absolute(path)) {
+                FILE *f;
+
+                f = fopen(path, mode);
+                if (f) {
+                        *_f = f;
+                        return 0;
+                }
+
+                return -errno;
+        }
+
+        s = strv_split_nulstr(search);
+        if (!s)
+                return -ENOMEM;
+
+        return search_and_fopen_internal(path, mode, s, _f);
+}