}
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) {
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;
value = va_arg(ap, char **);
n = strlen(key);
- if (strncmp(p, key, n) != 0 ||
+ if (!strneq(p, key, n) ||
p[n] != '=')
continue;
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;
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);
+}