summaryrefslogtreecommitdiff
path: root/src/basic
diff options
context:
space:
mode:
Diffstat (limited to 'src/basic')
-rw-r--r--src/basic/dirent-util.c11
-rw-r--r--src/basic/dirent-util.h2
-rw-r--r--src/basic/extract-word.c7
-rw-r--r--src/basic/extract-word.h2
-rw-r--r--src/basic/generate-gperfs.py2
-rw-r--r--src/basic/glob-util.c64
-rw-r--r--src/basic/glob-util.h4
-rw-r--r--src/basic/rm-rf.c9
8 files changed, 66 insertions, 35 deletions
diff --git a/src/basic/dirent-util.c b/src/basic/dirent-util.c
index 6b9d26773e..5bf58bcdc3 100644
--- a/src/basic/dirent-util.c
+++ b/src/basic/dirent-util.c
@@ -75,3 +75,14 @@ bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) {
return endswith(de->d_name, suffix);
}
+
+struct dirent* readdir_no_dot(DIR *dirp) {
+ struct dirent* d;
+
+ for (;;) {
+ d = readdir(dirp);
+ if (d && dot_or_dot_dot(d->d_name))
+ continue;
+ return d;
+ }
+}
diff --git a/src/basic/dirent-util.h b/src/basic/dirent-util.h
index b91d04908f..18b9db9b28 100644
--- a/src/basic/dirent-util.h
+++ b/src/basic/dirent-util.h
@@ -31,6 +31,8 @@ int dirent_ensure_type(DIR *d, struct dirent *de);
bool dirent_is_file(const struct dirent *de) _pure_;
bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pure_;
+struct dirent* readdir_no_dot(DIR *dirp);
+
#define FOREACH_DIRENT(de, d, on_error) \
for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) \
if (!de) { \
diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c
index f8cac3e911..804f14c44c 100644
--- a/src/basic/extract-word.c
+++ b/src/basic/extract-word.c
@@ -241,7 +241,12 @@ int extract_first_word_and_warn(
return log_syntax(unit, LOG_ERR, filename, line, r, "Unable to decode word \"%s\", ignoring: %m", rvalue);
}
-int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) {
+/* We pass ExtractFlags as unsigned int (to avoid undefined behaviour when passing
+ * an object that undergoes default argument promotion as an argument to va_start).
+ * Let's make sure that ExtractFlags fits into an unsigned int. */
+assert_cc(sizeof(enum ExtractFlags) <= sizeof(unsigned));
+
+int extract_many_words(const char **p, const char *separators, unsigned flags, ...) {
va_list ap;
char **l;
int n = 0, i, c, r;
diff --git a/src/basic/extract-word.h b/src/basic/extract-word.h
index 21db5ef33f..04746c6d08 100644
--- a/src/basic/extract-word.h
+++ b/src/basic/extract-word.h
@@ -32,4 +32,4 @@ typedef enum ExtractFlags {
int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);
int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue);
-int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_;
+int extract_many_words(const char **p, const char *separators, unsigned flags, ...) _sentinel_;
diff --git a/src/basic/generate-gperfs.py b/src/basic/generate-gperfs.py
index 2e7d8931dd..d4cc9aa45c 100644
--- a/src/basic/generate-gperfs.py
+++ b/src/basic/generate-gperfs.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
"""Generate %-from-name.gperf from %-list.txt
"""
diff --git a/src/basic/glob-util.c b/src/basic/glob-util.c
index 007198c269..f611c42e4c 100644
--- a/src/basic/glob-util.c
+++ b/src/basic/glob-util.c
@@ -17,54 +17,70 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <dirent.h>
#include <errno.h>
#include <glob.h>
+#include <sys/types.h>
+#include "dirent-util.h"
#include "glob-util.h"
#include "macro.h"
+#include "path-util.h"
#include "strv.h"
-int glob_exists(const char *path) {
- _cleanup_globfree_ glob_t g = {};
+int safe_glob(const char *path, int flags, glob_t *pglob) {
int k;
- assert(path);
+ /* We want to set GLOB_ALTDIRFUNC ourselves, don't allow it to be set. */
+ assert(!(flags & GLOB_ALTDIRFUNC));
+
+ if (!pglob->gl_closedir)
+ pglob->gl_closedir = (void (*)(void *)) closedir;
+ if (!pglob->gl_readdir)
+ pglob->gl_readdir = (struct dirent *(*)(void *)) readdir_no_dot;
+ if (!pglob->gl_opendir)
+ pglob->gl_opendir = (void *(*)(const char *)) opendir;
+ if (!pglob->gl_lstat)
+ pglob->gl_lstat = lstat;
+ if (!pglob->gl_stat)
+ pglob->gl_stat = stat;
errno = 0;
- k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
+ k = glob(path, flags | GLOB_ALTDIRFUNC, NULL, pglob);
if (k == GLOB_NOMATCH)
- return 0;
+ return -ENOENT;
if (k == GLOB_NOSPACE)
return -ENOMEM;
if (k != 0)
return errno > 0 ? -errno : -EIO;
+ if (strv_isempty(pglob->gl_pathv))
+ return -ENOENT;
- return !strv_isempty(g.gl_pathv);
+ return 0;
}
-int glob_extend(char ***strv, const char *path) {
+int glob_exists(const char *path) {
_cleanup_globfree_ glob_t g = {};
int k;
- char **p;
- errno = 0;
- k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
+ assert(path);
- if (k == GLOB_NOMATCH)
- return -ENOENT;
- if (k == GLOB_NOSPACE)
- return -ENOMEM;
- if (k != 0)
- return errno > 0 ? -errno : -EIO;
- if (strv_isempty(g.gl_pathv))
- return -ENOENT;
+ k = safe_glob(path, GLOB_NOSORT|GLOB_BRACE, &g);
+ if (k == -ENOENT)
+ return false;
+ if (k < 0)
+ return k;
+ return true;
+}
+
+int glob_extend(char ***strv, const char *path) {
+ _cleanup_globfree_ glob_t g = {};
+ int k;
- STRV_FOREACH(p, g.gl_pathv) {
- k = strv_extend(strv, *p);
- if (k < 0)
- return k;
- }
+ k = safe_glob(path, GLOB_NOSORT|GLOB_BRACE, &g);
+ if (k < 0)
+ return k;
- return 0;
+ return strv_extend_strv(strv, g.gl_pathv, false);
}
diff --git a/src/basic/glob-util.h b/src/basic/glob-util.h
index 5d8fb47a26..e1f6083afa 100644
--- a/src/basic/glob-util.h
+++ b/src/basic/glob-util.h
@@ -19,12 +19,16 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <glob.h>
#include <stdbool.h>
#include <string.h>
#include "macro.h"
#include "string-util.h"
+/* Note: this function modifies pglob to set various functions. */
+int safe_glob(const char *path, int flags, glob_t *pglob);
+
int glob_exists(const char *path);
int glob_extend(char ***strv, const char *path);
diff --git a/src/basic/rm-rf.c b/src/basic/rm-rf.c
index bdaca264ff..ff040e7a55 100644
--- a/src/basic/rm-rf.c
+++ b/src/basic/rm-rf.c
@@ -182,18 +182,11 @@ int rm_rf(const char *path, RemoveFlags flags) {
/* We refuse to clean the root file system with this
* call. This is extra paranoia to never cause a really
* seriously broken system. */
- if (path_equal(path, "/")) {
+ if (path_equal_or_files_same(path, "/")) {
log_error("Attempted to remove entire root file system, and we can't allow that.");
return -EPERM;
}
- /* Another safe-check. Removing "/path/.." could easily remove entire root as well.
- * It's especially easy to do using globs in tmpfiles, like "/path/.*", which the glob()
- * function expands to both "/path/." and "/path/..".
- * Return -EINVAL to be consistent with rmdir("/path/."). */
- if (endswith(path, "/..") || endswith(path, "/../"))
- return -EINVAL;
-
if ((flags & (REMOVE_SUBVOLUME|REMOVE_ROOT|REMOVE_PHYSICAL)) == (REMOVE_SUBVOLUME|REMOVE_ROOT|REMOVE_PHYSICAL)) {
/* Try to remove as subvolume first */
r = btrfs_subvol_remove(path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);