diff options
Diffstat (limited to 'src/shared')
-rw-r--r-- | src/shared/conf-files.c | 112 | ||||
-rw-r--r-- | src/shared/conf-files.h | 1 | ||||
-rw-r--r-- | src/shared/hashmap.c | 27 | ||||
-rw-r--r-- | src/shared/hashmap.h | 2 | ||||
-rw-r--r-- | src/shared/path-util.c | 10 | ||||
-rw-r--r-- | src/shared/path-util.h | 1 | ||||
-rw-r--r-- | src/shared/strv.c | 16 | ||||
-rw-r--r-- | src/shared/strv.h | 1 | ||||
-rw-r--r-- | src/shared/util.c | 79 | ||||
-rw-r--r-- | src/shared/util.h | 3 |
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)) { \ |