summaryrefslogtreecommitdiff
path: root/src/shared
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/conf-files.c112
-rw-r--r--src/shared/conf-files.h1
-rw-r--r--src/shared/hashmap.c27
-rw-r--r--src/shared/hashmap.h2
-rw-r--r--src/shared/path-util.c10
-rw-r--r--src/shared/path-util.h1
-rw-r--r--src/shared/strv.c16
-rw-r--r--src/shared/strv.h1
-rw-r--r--src/shared/util.c79
-rw-r--r--src/shared/util.h3
10 files changed, 210 insertions, 42 deletions
diff --git a/src/shared/conf-files.c b/src/shared/conf-files.c
index 5bbd2388d3..296e605761 100644
--- a/src/shared/conf-files.c
+++ b/src/shared/conf-files.c
@@ -38,7 +38,7 @@
#include "conf-files.h"
static int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) {
- _cleanup_closedir_ DIR *dir;
+ _cleanup_closedir_ DIR *dir = NULL;
_cleanup_free_ char *dirpath = NULL;
if (asprintf(&dirpath, "%s%s", root ? root : "", path) < 0)
@@ -55,11 +55,11 @@ static int files_add(Hashmap *h, const char *root, const char *path, const char
struct dirent *de;
union dirent_storage buf;
char *p;
- int err;
+ int r;
- err = readdir_r(dir, &buf.de, &de);
- if (err != 0)
- return err;
+ r = readdir_r(dir, &buf.de, &de);
+ if (r != 0)
+ return -r;
if (!de)
break;
@@ -67,11 +67,19 @@ static int files_add(Hashmap *h, const char *root, const char *path, const char
if (!dirent_is_file_with_suffix(de, suffix))
continue;
- if (asprintf(&p, "%s/%s", dirpath, de->d_name) < 0)
+ p = strjoin(dirpath, "/", de->d_name, NULL);
+ if (!p)
return -ENOMEM;
- if (hashmap_put(h, path_get_file_name(p), p) <= 0) {
- log_debug("Skip overridden file: %s.", p);
+ r = hashmap_put(h, path_get_file_name(p), p);
+ if (r == -EEXIST) {
+ log_debug("Skipping overridden file: %s.", p);
+ free(p);
+ } else if (r < 0) {
+ free(p);
+ return r;
+ } else if (r == 0) {
+ log_debug("Duplicate file %s", p);
free(p);
}
}
@@ -87,64 +95,84 @@ static int base_cmp(const void *a, const void *b) {
return strcmp(path_get_file_name(s1), path_get_file_name(s2));
}
-int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char **dirs) {
- Hashmap *fh = NULL;
- char **files = NULL;
- const char **p;
+static int conf_files_list_strv_internal(char ***strv, const char *suffix, const char *root, char **dirs) {
+ Hashmap *fh;
+ char **files, **p;
int r;
- assert(dirs);
+ assert(strv);
+ assert(suffix);
+
+ /* This alters the dirs string array */
+ if (!path_strv_canonicalize_uniq(dirs))
+ return -ENOMEM;
fh = hashmap_new(string_hash_func, string_compare_func);
- if (!fh) {
- r = -ENOMEM;
- goto finish;
- }
+ if (!fh)
+ return -ENOMEM;
STRV_FOREACH(p, dirs) {
r = files_add(fh, root, *p, suffix);
- if (r < 0)
- log_warning("Failed to search for files in %s: %s",
- *p, strerror(-r));
+ if (r == -ENOMEM) {
+ hashmap_free_free(fh);
+ return r;
+ } else if (r < 0)
+ log_debug("Failed to search for files in %s: %s",
+ *p, strerror(-r));
}
files = hashmap_get_strv(fh);
if (files == NULL) {
- log_error("Failed to compose list of files.");
- r = -ENOMEM;
- goto finish;
+ hashmap_free_free(fh);
+ return -ENOMEM;
}
+
qsort(files, hashmap_size(fh), sizeof(char *), base_cmp);
- r = 0;
+ *strv = files;
-finish:
hashmap_free(fh);
- *strv = files;
- return r;
+ return 0;
+}
+
+int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char **dirs) {
+ _cleanup_strv_free_ char **copy = NULL;
+
+ assert(strv);
+ assert(suffix);
+
+ copy = strv_copy((char**) dirs);
+ if (!copy)
+ return -ENOMEM;
+
+ return conf_files_list_strv_internal(strv, suffix, root, copy);
}
int conf_files_list(char ***strv, const char *suffix, const char *root, const char *dir, ...) {
- char **dirs = NULL;
+ _cleanup_strv_free_ char **dirs = NULL;
va_list ap;
- int r;
+
+ assert(strv);
+ assert(suffix);
va_start(ap, dir);
dirs = strv_new_ap(dir, ap);
va_end(ap);
- if (!dirs) {
- r = -ENOMEM;
- goto finish;
- }
- if (!path_strv_canonicalize(dirs)) {
- r = -ENOMEM;
- goto finish;
- }
- strv_uniq(dirs);
+ if (!dirs)
+ return -ENOMEM;
+
+ return conf_files_list_strv_internal(strv, suffix, root, dirs);
+}
- r = conf_files_list_strv(strv, suffix, root, (const char **)dirs);
+int conf_files_list_nulstr(char ***strv, const char *suffix, const char *root, const char *d) {
+ _cleanup_strv_free_ char **dirs = NULL;
+
+ assert(strv);
+ assert(suffix);
+
+ dirs = strv_split_nulstr(d);
+ if (!dirs)
+ return -ENOMEM;
-finish:
- strv_free(dirs);
- return r;
+ return conf_files_list_strv_internal(strv, suffix, root, dirs);
}
diff --git a/src/shared/conf-files.h b/src/shared/conf-files.h
index 4d7941f4cb..28588e6f03 100644
--- a/src/shared/conf-files.h
+++ b/src/shared/conf-files.h
@@ -27,5 +27,6 @@
int conf_files_list(char ***strv, const char *suffix, const char *root, const char *dir, ...);
int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char **dirs);
+int conf_files_list_nulstr(char ***strv, const char *suffix, const char *root, const char *dirs);
#endif
diff --git a/src/shared/hashmap.c b/src/shared/hashmap.c
index a2c728d642..9f7db34397 100644
--- a/src/shared/hashmap.c
+++ b/src/shared/hashmap.c
@@ -309,6 +309,17 @@ void hashmap_free_free(Hashmap *h) {
hashmap_free(h);
}
+void hashmap_free_free_free(Hashmap *h) {
+
+ /* Free the hashmap and all data and key objects in it */
+
+ if (!h)
+ return;
+
+ hashmap_clear_free_free(h);
+ hashmap_free(h);
+}
+
void hashmap_clear(Hashmap *h) {
if (!h)
return;
@@ -327,6 +338,22 @@ void hashmap_clear_free(Hashmap *h) {
free(p);
}
+void hashmap_clear_free_free(Hashmap *h) {
+ if (!h)
+ return;
+
+ while (h->iterate_list_head) {
+ void *a, *b;
+
+ a = h->iterate_list_head->value;
+ b = (void*) h->iterate_list_head->key;
+ remove_entry(h, h->iterate_list_head);
+ free(a);
+ free(b);
+ }
+}
+
+
static struct hashmap_entry *hash_scan(Hashmap *h, unsigned hash, const void *key) {
struct hashmap_entry *e;
assert(h);
diff --git a/src/shared/hashmap.h b/src/shared/hashmap.h
index 6fd71cf519..26bd03096d 100644
--- a/src/shared/hashmap.h
+++ b/src/shared/hashmap.h
@@ -50,6 +50,7 @@ int uint64_compare_func(const void *a, const void *b);
Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func);
void hashmap_free(Hashmap *h);
void hashmap_free_free(Hashmap *h);
+void hashmap_free_free_free(Hashmap *h);
Hashmap *hashmap_copy(Hashmap *h);
int hashmap_ensure_allocated(Hashmap **h, hash_func_t hash_func, compare_func_t compare_func);
@@ -77,6 +78,7 @@ void *hashmap_iterate_skip(Hashmap *h, const void *key, Iterator *i);
void hashmap_clear(Hashmap *h);
void hashmap_clear_free(Hashmap *h);
+void hashmap_clear_free_free(Hashmap *h);
void *hashmap_steal_first(Hashmap *h);
void *hashmap_steal_first_key(Hashmap *h);
diff --git a/src/shared/path-util.c b/src/shared/path-util.c
index 52ce65de6d..0b50ea646a 100644
--- a/src/shared/path-util.c
+++ b/src/shared/path-util.c
@@ -215,6 +215,16 @@ char **path_strv_canonicalize(char **l) {
return l;
}
+char **path_strv_canonicalize_uniq(char **l) {
+ if (strv_isempty(l))
+ return l;
+
+ if (!path_strv_canonicalize(l))
+ return NULL;
+
+ return strv_uniq(l);
+}
+
char *path_kill_slashes(char *path) {
char *f, *t;
bool slash = false;
diff --git a/src/shared/path-util.h b/src/shared/path-util.h
index e37ab9350b..ff523943dc 100644
--- a/src/shared/path-util.h
+++ b/src/shared/path-util.h
@@ -37,6 +37,7 @@ bool path_equal(const char *a, const char *b);
char **path_strv_make_absolute_cwd(char **l);
char **path_strv_canonicalize(char **l);
+char **path_strv_canonicalize_uniq(char **l);
int path_is_mount_point(const char *path, bool allow_symlink);
int path_is_read_only_fs(const char *path);
diff --git a/src/shared/strv.c b/src/shared/strv.c
index ee0b71ece0..ec25755289 100644
--- a/src/shared/strv.c
+++ b/src/shared/strv.c
@@ -504,6 +504,22 @@ char **strv_parse_nulstr(const char *s, size_t l) {
return v;
}
+char **strv_split_nulstr(const char *s) {
+ const char *i;
+ char **r = NULL;
+
+ NULSTR_FOREACH(i, s)
+ if (strv_extend(&r, i) < 0) {
+ strv_free(r);
+ return NULL;
+ }
+
+ if (!r)
+ return strv_new(NULL, NULL);
+
+ return r;
+}
+
bool strv_overlap(char **a, char **b) {
char **i, **j;
diff --git a/src/shared/strv.h b/src/shared/strv.h
index d28625bd2f..b3802a7a3f 100644
--- a/src/shared/strv.h
+++ b/src/shared/strv.h
@@ -62,6 +62,7 @@ char **strv_split_quoted(const char *s) _malloc_;
char *strv_join(char **l, const char *separator) _malloc_;
char **strv_parse_nulstr(const char *s, size_t l);
+char **strv_split_nulstr(const char *s);
bool strv_overlap(char **a, char **b);
diff --git a/src/shared/util.c b/src/shared/util.c
index 29cb9f1e8d..24f9e7ee58 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -5909,3 +5909,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);
+}
diff --git a/src/shared/util.h b/src/shared/util.h
index d926b01919..cd13457528 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -568,6 +568,9 @@ char *strip_tab_ansi(char **p, size_t *l);
int on_ac_power(void);
+int search_and_fopen(const char *path, const char *mode, const char **search, FILE **_f);
+int search_and_fopen_nulstr(const char *path, const char *mode, const char *search, FILE **_f);
+
#define FOREACH_LINE(f, line, on_error) \
for (char line[LINE_MAX]; !feof(f); ) \
if (!fgets(line, sizeof(line), f)) { \