diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 8fb9ecc6dc..a613c39087 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -804,7 +804,7 @@ CapabilityBoundingSet=~CAP_B CAP_C
ConfigurationDirectory=
These options take a whitespace-separated list of directory names. The specified directory
- names must be relative, and may not include . or ... If set, one or more
+ names must be relative, and may not include ... If set, one or more
directories by the specified names will be created (including their parents) below /run
(or $XDG_RUNTIME_DIR for user services), /var/lib (or
$XDG_CONFIG_HOME for user services), /var/cache (or
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
index 1b0221edc4..ca31dee4a7 100644
--- a/src/basic/cgroup-util.c
+++ b/src/basic/cgroup-util.c
@@ -628,7 +628,7 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
if (!t)
return -ENOMEM;
- *fs = path_kill_slashes(t);
+ *fs = path_simplify(t, false);
return 0;
}
@@ -645,7 +645,7 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
if (r < 0)
return r;
- path_kill_slashes(*fs);
+ path_simplify(*fs, false);
return 0;
}
@@ -1250,7 +1250,7 @@ int cg_split_spec(const char *spec, char **controller, char **path) {
if (!t)
return -ENOMEM;
- *path = path_kill_slashes(t);
+ *path = path_simplify(t, false);
}
if (controller)
@@ -1302,7 +1302,7 @@ int cg_split_spec(const char *spec, char **controller, char **path) {
return -EINVAL;
}
- path_kill_slashes(u);
+ path_simplify(u, false);
}
if (controller)
@@ -1333,7 +1333,7 @@ int cg_mangle_path(const char *path, char **result) {
if (!t)
return -ENOMEM;
- *result = path_kill_slashes(t);
+ *result = path_simplify(t, false);
return 0;
}
diff --git a/src/basic/fileio.c b/src/basic/fileio.c
index 6dd00e0698..c12b4ac7f5 100644
--- a/src/basic/fileio.c
+++ b/src/basic/fileio.c
@@ -1234,7 +1234,7 @@ int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX");
- *ret = path_kill_slashes(t);
+ *ret = path_simplify(t, false);
return 0;
}
@@ -1275,7 +1275,7 @@ int tempfn_random(const char *p, const char *extra, char **ret) {
*x = 0;
- *ret = path_kill_slashes(t);
+ *ret = path_simplify(t, false);
return 0;
}
@@ -1315,7 +1315,7 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) {
*x = 0;
- *ret = path_kill_slashes(t);
+ *ret = path_simplify(t, false);
return 0;
}
diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c
index 2774e48cf3..68a83ebae7 100644
--- a/src/basic/mount-util.c
+++ b/src/basic/mount-util.c
@@ -413,7 +413,7 @@ int bind_remount_recursive_with_mountinfo(const char *prefix, bool ro, char **bl
if (!cleaned)
return -ENOMEM;
- path_kill_slashes(cleaned);
+ path_simplify(cleaned, false);
done = set_new(&path_hash_ops);
if (!done)
diff --git a/src/basic/path-util.c b/src/basic/path-util.c
index 4f428818d1..690159d89c 100644
--- a/src/basic/path-util.c
+++ b/src/basic/path-util.c
@@ -32,6 +32,7 @@
#include "string-util.h"
#include "strv.h"
#include "time-util.h"
+#include "utf8.h"
bool path_is_absolute(const char *p) {
return p[0] == '/';
@@ -127,8 +128,8 @@ int path_make_absolute_cwd(const char *p, char **ret) {
}
int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
- char *r, *p;
- unsigned n_parents;
+ char *f, *t, *r, *p;
+ unsigned n_parents = 0;
assert(from_dir);
assert(to_path);
@@ -136,85 +137,81 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
/* Strips the common part, and adds ".." elements as necessary. */
- if (!path_is_absolute(from_dir))
+ if (!path_is_absolute(from_dir) || !path_is_absolute(to_path))
return -EINVAL;
- if (!path_is_absolute(to_path))
- return -EINVAL;
+ f = strdupa(from_dir);
+ t = strdupa(to_path);
+
+ path_simplify(f, true);
+ path_simplify(t, true);
/* Skip the common part. */
for (;;) {
size_t a, b;
- from_dir += strspn(from_dir, "/");
- to_path += strspn(to_path, "/");
+ f += *f == '/';
+ t += *t == '/';
- if (!*from_dir) {
- if (!*to_path)
+ if (!*f) {
+ if (!*t)
/* from_dir equals to_path. */
r = strdup(".");
else
/* from_dir is a parent directory of to_path. */
- r = strdup(to_path);
+ r = strdup(t);
if (!r)
return -ENOMEM;
- path_kill_slashes(r);
-
*_r = r;
return 0;
}
- if (!*to_path)
+ if (!*t)
break;
- a = strcspn(from_dir, "/");
- b = strcspn(to_path, "/");
+ a = strcspn(f, "/");
+ b = strcspn(t, "/");
- if (a != b)
+ if (a != b || memcmp(f, t, a) != 0)
break;
- if (memcmp(from_dir, to_path, a) != 0)
- break;
-
- from_dir += a;
- to_path += b;
+ f += a;
+ t += b;
}
/* If we're here, then "from_dir" has one or more elements that need to
* be replaced with "..". */
/* Count the number of necessary ".." elements. */
- for (n_parents = 0;;) {
+ for (; *f;) {
size_t w;
- from_dir += strspn(from_dir, "/");
-
- if (!*from_dir)
- break;
-
- w = strcspn(from_dir, "/");
+ w = strcspn(f, "/");
/* If this includes ".." we can't do a simple series of "..", refuse */
- if (w == 2 && from_dir[0] == '.' && from_dir[1] == '.')
+ if (w == 2 && f[0] == '.' && f[1] == '.')
return -EINVAL;
- /* Count number of elements, except if they are "." */
- if (w != 1 || from_dir[0] != '.')
- n_parents++;
+ /* Count number of elements */
+ n_parents++;
- from_dir += w;
+ f += w;
+ f += *f == '/';
}
- r = new(char, n_parents * 3 + strlen(to_path) + 1);
+ r = new(char, n_parents * 3 + strlen(t) + 1);
if (!r)
return -ENOMEM;
for (p = r; n_parents > 0; n_parents--)
p = mempcpy(p, "../", 3);
- strcpy(p, to_path);
- path_kill_slashes(r);
+ if (*t)
+ strcpy(p, t);
+ else
+ /* Remove trailing slash */
+ *(--p) = 0;
*_r = r;
return 0;
@@ -235,7 +232,7 @@ int path_strv_make_absolute_cwd(char **l) {
if (r < 0)
return r;
- path_kill_slashes(t);
+ path_simplify(t, false);
free_and_replace(*s, t);
}
@@ -335,17 +332,30 @@ char **path_strv_resolve_uniq(char **l, const char *root) {
return strv_uniq(l);
}
-char *path_kill_slashes(char *path) {
+char *path_simplify(char *path, bool kill_dots) {
char *f, *t;
- bool slash = false;
+ bool slash = false, ignore_slash = false, absolute;
- /* Removes redundant inner and trailing slashes. Modifies the
- * passed string in-place.
+ assert(path);
+
+ /* Removes redundant inner and trailing slashes. Also removes unnecessary dots
+ * if kill_dots is true. Modifies the passed string in-place.
*
- * ///foo///bar/ becomes /foo/bar
+ * ///foo//./bar/. becomes /foo/./bar/. (if kill_dots is false)
+ * ///foo//./bar/. becomes /foo/bar (if kill_dots is true)
+ * .//./foo//./bar/. becomes ./foo/bar (if kill_dots is false)
+ * .//./foo//./bar/. becomes foo/bar (if kill_dots is true)
*/
- for (f = path, t = path; *f; f++) {
+ absolute = path_is_absolute(path);
+
+ f = path;
+ if (kill_dots && *f == '.' && IN_SET(f[1], 0, '/')) {
+ ignore_slash = true;
+ f++;
+ }
+
+ for (t = path; *f; f++) {
if (*f == '/') {
slash = true;
@@ -353,17 +363,21 @@ char *path_kill_slashes(char *path) {
}
if (slash) {
+ if (kill_dots && *f == '.' && IN_SET(f[1], 0, '/'))
+ continue;
+
slash = false;
- *(t++) = '/';
+ if (ignore_slash)
+ ignore_slash = false;
+ else
+ *(t++) = '/';
}
*(t++) = *f;
}
- /* Special rule, if we are talking of the root directory, a
- trailing slash is good */
-
- if (t == path && slash)
+ /* Special rule, if we are talking of the root directory, a trailing slash is good */
+ if (absolute && t == path)
*(t++) = '/';
*t = 0;
@@ -530,7 +544,7 @@ int find_binary(const char *name, char **ret) {
/* Found it! */
if (ret) {
- *ret = path_kill_slashes(j);
+ *ret = path_simplify(j, false);
j = NULL;
}
@@ -684,12 +698,11 @@ int parse_path_argument_and_warn(const char *path, bool suppress_root, char **ar
if (r < 0)
return log_error_errno(r, "Failed to parse path \"%s\" and make it absolute: %m", path);
- path_kill_slashes(p);
+ path_simplify(p, false);
if (suppress_root && empty_or_root(p))
p = mfree(p);
- free(*arg);
- *arg = p;
+ free_and_replace(*arg, p);
return 0;
}
@@ -977,3 +990,52 @@ bool empty_or_root(const char *root) {
return root[strspn(root, "/")] == 0;
}
+
+int path_simplify_and_warn(
+ char *path,
+ unsigned flag,
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *lvalue) {
+
+ bool fatal, absolute;
+
+ assert((flag & (PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)) != (PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE));
+
+ fatal = flag & PATH_CHECK_FATAL;
+
+ if (!utf8_is_valid(path)) {
+ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, path);
+ return -EINVAL;
+ }
+
+ if (flag & (PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)) {
+ absolute = path_is_absolute(path);
+
+ if (!absolute && (flag & PATH_CHECK_ABSOLUTE)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "%s= path is not absolute%s: %s",
+ fatal ? "" : ", ignoring", lvalue, path);
+ return -EINVAL;
+ }
+
+ if (absolute && (flag & PATH_CHECK_RELATIVE)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "%s= path is absolute%s: %s",
+ fatal ? "" : ", ignoring", lvalue, path);
+ return -EINVAL;
+ }
+ }
+
+ path_simplify(path, true);
+
+ if (!path_is_normalized(path)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "%s= path is not normalized%s: %s",
+ fatal ? "" : ", ignoring", lvalue, path);
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/src/basic/path-util.h b/src/basic/path-util.h
index 134e1ebc98..d8a923d3cd 100644
--- a/src/basic/path-util.h
+++ b/src/basic/path-util.h
@@ -50,12 +50,12 @@ char* path_make_absolute(const char *p, const char *prefix);
int safe_getcwd(char **ret);
int path_make_absolute_cwd(const char *p, char **ret);
int path_make_relative(const char *from_dir, const char *to_path, char **_r);
-char* path_kill_slashes(char *path);
char* path_startswith(const char *path, const char *prefix) _pure_;
int path_compare(const char *a, const char *b) _pure_;
bool path_equal(const char *a, const char *b) _pure_;
bool path_equal_or_files_same(const char *a, const char *b, int flags);
char* path_join(const char *root, const char *path, const char *rest);
+char* path_simplify(char *path, bool kill_dots);
static inline bool path_equal_ptr(const char *a, const char *b) {
return !!a == !!b && (!a || path_equal(a, b));
@@ -101,11 +101,11 @@ int mkfs_exists(const char *fstype);
* the tree, to root. Also returns "" (and not "/"!) for the root
* directory. Excludes the specified directory itself */
#define PATH_FOREACH_PREFIX(prefix, path) \
- for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); streq(prefix, "/") ? NULL : strrchr(prefix, '/'); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/'))
+ for (char *_slash = ({ path_simplify(strcpy(prefix, path), false); streq(prefix, "/") ? NULL : strrchr(prefix, '/'); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/'))
/* Same as PATH_FOREACH_PREFIX but also includes the specified path itself */
#define PATH_FOREACH_PREFIX_MORE(prefix, path) \
- for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); if (streq(prefix, "/")) prefix[0] = 0; strrchr(prefix, 0); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/'))
+ for (char *_slash = ({ path_simplify(strcpy(prefix, path), false); if (streq(prefix, "/")) prefix[0] = 0; strrchr(prefix, 0); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/'))
char *prefix_root(const char *root, const char *path);
@@ -167,3 +167,11 @@ bool empty_or_root(const char *root);
static inline const char *empty_to_root(const char *path) {
return isempty(path) ? "/" : path;
}
+
+enum {
+ PATH_CHECK_FATAL = 1 << 0, /* If not set, then error message is appended with 'ignoring'. */
+ PATH_CHECK_ABSOLUTE = 1 << 1,
+ PATH_CHECK_RELATIVE = 1 << 2,
+};
+
+int path_simplify_and_warn(char *path, unsigned flag, const char *unit, const char *filename, unsigned line, const char *lvalue);
diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c
index 479079099b..4fa00663e4 100644
--- a/src/basic/unit-name.c
+++ b/src/basic/unit-name.c
@@ -383,7 +383,7 @@ int unit_name_path_escape(const char *f, char **ret) {
if (!p)
return -ENOMEM;
- path_kill_slashes(p);
+ path_simplify(p, false);
if (empty_or_root(p))
s = strdup("-");
diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c
index 7c7ea18b61..4ad84bec93 100644
--- a/src/cgls/cgls.c
+++ b/src/cgls/cgls.c
@@ -241,7 +241,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
- path_kill_slashes(j);
+ path_simplify(j, false);
path = j;
} else
path = root;
diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c
index 401c08600a..b2b6a25b48 100644
--- a/src/cgtop/cgtop.c
+++ b/src/cgtop/cgtop.c
@@ -470,7 +470,7 @@ static int refresh_one(
if (!p)
return -ENOMEM;
- path_kill_slashes(p);
+ path_simplify(p, false);
r = refresh_one(controller, p, a, b, iteration, depth + 1, &child);
if (r < 0)
diff --git a/src/core/automount.c b/src/core/automount.c
index c49b523eb2..e7ef6e78da 100644
--- a/src/core/automount.c
+++ b/src/core/automount.c
@@ -199,7 +199,7 @@ static int automount_set_where(Automount *a) {
if (r < 0)
return r;
- path_kill_slashes(a->where);
+ path_simplify(a->where, false);
return 1;
}
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 25778320ab..b3f8600eb4 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -1519,7 +1519,7 @@ static int unit_attach_pid_to_cgroup_via_bus(Unit *u, pid_t pid, const char *suf
return -EINVAL;
pp = strjoina("/", pp, suffix_path);
- path_kill_slashes(pp);
+ path_simplify(pp, false);
r = sd_bus_call_method(u->manager->system_bus,
"org.freedesktop.systemd1",
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index ec1b62fb42..8c752ceaa6 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -935,7 +935,7 @@ int bus_set_transient_exec_command(
c->flags = b ? EXEC_COMMAND_IGNORE_FAILURE : 0;
- path_kill_slashes(c->path);
+ path_simplify(c->path, false);
exec_command_append_list(exec_command, c);
}
@@ -2051,7 +2051,7 @@ int bus_exec_context_set_transient_property(
if (!path_is_absolute(i + offset))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s", name);
- path_kill_slashes(i + offset);
+ path_simplify(i + offset, false);
}
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
diff --git a/src/core/dbus-path.c b/src/core/dbus-path.c
index fec67d595f..7bd0acac22 100644
--- a/src/core/dbus-path.c
+++ b/src/core/dbus-path.c
@@ -108,13 +108,14 @@ static int bus_path_set_transient_property(
if (!k)
return -ENOMEM;
+ path_simplify(k, false);
+
s = new0(PathSpec, 1);
if (!s)
return -ENOMEM;
s->unit = u;
- s->path = path_kill_slashes(k);
- k = NULL;
+ s->path = TAKE_PTR(k);
s->type = t;
s->inotify_fd = -1;
diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c
index 88e180a037..aee81430bb 100644
--- a/src/core/dbus-socket.c
+++ b/src/core/dbus-socket.c
@@ -365,7 +365,7 @@ static int bus_socket_set_transient_property(
if (p->type != SOCKET_SOCKET) {
p->path = strdup(a);
- path_kill_slashes(p->path);
+ path_simplify(p->path, false);
} else if (streq(t, "Netlink")) {
r = socket_address_parse_netlink(&p->address, a);
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index dd4c755894..0953355dce 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -58,7 +58,6 @@
#include "unit-name.h"
#include "unit-printf.h"
#include "user-util.h"
-#include "utf8.h"
#include "web-util.h"
static int supported_socket_protocol_from_string(const char *s) {
@@ -314,18 +313,9 @@ int config_parse_unit_path_strv_printf(
return 0;
}
- if (!utf8_is_valid(k)) {
- log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
+ r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
+ if (r < 0)
return 0;
- }
-
- if (!path_is_absolute(k)) {
- log_syntax(unit, LOG_ERR, filename, line, 0,
- "Symlink path is not absolute: %s", k);
- return 0;
- }
-
- path_kill_slashes(k);
r = strv_push(x, k);
if (r < 0)
@@ -368,20 +358,24 @@ int config_parse_socket_listen(const char *unit,
return log_oom();
if (ltype != SOCKET_SOCKET) {
+ _cleanup_free_ char *k = NULL;
- p->type = ltype;
- r = unit_full_printf(UNIT(s), rvalue, &p->path);
+ r = unit_full_printf(UNIT(s), rvalue, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
return 0;
}
- path_kill_slashes(p->path);
+ r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
+ if (r < 0)
+ return 0;
+
+ free_and_replace(p->path, k);
+ p->type = ltype;
} else if (streq(lvalue, "ListenNetlink")) {
_cleanup_free_ char *k = NULL;
- p->type = SOCKET_SOCKET;
r = unit_full_printf(UNIT(s), rvalue, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
@@ -394,10 +388,11 @@ int config_parse_socket_listen(const char *unit,
return 0;
}
+ p->type = SOCKET_SOCKET;
+
} else {
_cleanup_free_ char *k = NULL;
- p->type = SOCKET_SOCKET;
r = unit_full_printf(UNIT(s), rvalue, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
@@ -424,6 +419,8 @@ int config_parse_socket_listen(const char *unit,
log_syntax(unit, LOG_ERR, filename, line, 0, "Address family not supported, ignoring: %s", rvalue);
return 0;
}
+
+ p->type = SOCKET_SOCKET;
}
p->fd = -1;
@@ -673,7 +670,7 @@ int config_parse_exec(
n[nlen] = NULL;
}
- path_kill_slashes(path);
+ path_simplify(path, false);
while (!isempty(p)) {
_cleanup_free_ char *word = NULL, *resolved = NULL;
@@ -837,15 +834,9 @@ int config_parse_exec_input(
if (r < 0)
return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s': %m", n);
- if (!path_is_absolute(resolved)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "file: requires an absolute path name: %s", resolved);
+ r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE | PATH_CHECK_FATAL, unit, filename, line, lvalue);
+ if (r < 0)
return -EINVAL;
- }
-
- if (!path_is_normalized(resolved)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "file: requires a normalized path name: %s", resolved);
- return -EINVAL;
- }
free_and_replace(c->stdio_file[STDIN_FILENO], resolved);
@@ -1021,15 +1012,9 @@ int config_parse_exec_output(
if (r < 0)
return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", n);
- if (!path_is_absolute(resolved)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "file: requires an absolute path name: %s", resolved);
+ r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE | PATH_CHECK_FATAL, unit, filename, line, lvalue);
+ if (r < 0)
return -EINVAL;
- }
-
- if (!path_is_normalized(resolved)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "file: requires a normalized path name, ignoring: %s", resolved);
- return -EINVAL;
- }
eo = EXEC_OUTPUT_FILE;
@@ -1624,12 +1609,9 @@ int config_parse_path_spec(const char *unit,
return 0;
}
- path_kill_slashes(k);
-
- if (!path_is_absolute(k)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Path is not absolute, ignoring: %s", k);
+ r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
+ if (r < 0)
return 0;
- }
s = new0(PathSpec, 1);
if (!s)
@@ -2048,19 +2030,9 @@ int config_parse_working_directory(
return missing_ok ? 0 : -ENOEXEC;
}
- path_kill_slashes(k);
-
- if (!utf8_is_valid(k)) {
- log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
+ r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE | (missing_ok ? 0 : PATH_CHECK_FATAL), unit, filename, line, lvalue);
+ if (r < 0)
return missing_ok ? 0 : -ENOEXEC;
- }
-
- if (!path_is_absolute(k)) {
- log_syntax(unit, LOG_ERR, filename, line, 0,
- "Working directory path '%s' is not absolute%s.",
- rvalue, missing_ok ? ", ignoring" : "");
- return missing_ok ? 0 : -ENOEXEC;
- }
c->working_directory_home = false;
free_and_replace(c->working_directory, k);
@@ -2103,15 +2075,16 @@ int config_parse_unit_env_file(const char *unit,
return 0;
}
- if (!path_is_absolute(n[0] == '-' ? n + 1 : n)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Path '%s' is not absolute, ignoring.", n);
+ r = path_simplify_and_warn(n[0] == '-' ? n + 1 : n, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
+ if (r < 0)
return 0;
- }
- r = strv_extend(env, n);
+ r = strv_push(env, n);
if (r < 0)
return log_oom();
+ n = NULL;
+
return 0;
}
@@ -2447,10 +2420,9 @@ int config_parse_unit_condition_path(
return 0;
}
- if (!path_is_absolute(p)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Path in condition not absolute, ignoring: %s", p);
+ r = path_simplify_and_warn(p, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
+ if (r < 0)
return 0;
- }
c = condition_new(t, p, trigger, negate);
if (!c)
@@ -2599,17 +2571,16 @@ int config_parse_unit_requires_mounts_for(
return 0;
}
- if (!utf8_is_valid(word)) {
- log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
- continue;
- }
-
r = unit_full_printf(u, word, &resolved);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", word);
continue;
}
+ r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
+ if (r < 0)
+ continue;
+
r = unit_require_mounts_for(u, resolved, UNIT_DEPENDENCY_FILE);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add required mount '%s', ignoring: %m", resolved);
@@ -3263,6 +3234,10 @@ int config_parse_device_allow(
return 0;
}
+ r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
+ if (r < 0)
+ return 0;
+
if (!is_deviceallow_pattern(resolved) &&
!path_startswith(resolved, "/run/systemd/inaccessible/")) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s', ignoring.", resolved);
@@ -3338,6 +3313,10 @@ int config_parse_io_device_weight(
return 0;
}
+ r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
+ if (r < 0)
+ return 0;
+
if (!path_startswith(resolved, "/dev") &&
!path_startswith(resolved, "/run/systemd/inaccessible/")) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s', ignoring.", resolved);
@@ -3417,6 +3396,10 @@ int config_parse_io_limit(
return 0;
}
+ r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
+ if (r < 0)
+ return 0;
+
if (!path_startswith(resolved, "/dev") &&
!path_startswith(resolved, "/run/systemd/inaccessible/")) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s', ignoring.", resolved);
@@ -3510,6 +3493,10 @@ int config_parse_blockio_device_weight(
return 0;
}
+ r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
+ if (r < 0)
+ return 0;
+
if (!path_startswith(resolved, "/dev") &&
!path_startswith(resolved, "/run/systemd/inaccessible/")) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", resolved);
@@ -3590,6 +3577,10 @@ int config_parse_blockio_bandwidth(
return 0;
}
+ r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
+ if (r < 0)
+ return 0;
+
if (!path_startswith(resolved, "/dev") &&
!path_startswith(resolved, "/run/systemd/inaccessible/")) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s', ignoring.", resolved);
@@ -3709,21 +3700,13 @@ int config_parse_exec_directories(
continue;
}
- if (!path_is_normalized(k)) {
- log_syntax(unit, LOG_ERR, filename, line, 0,
- "%s= path is not normalized, ignoring assignment: %s", lvalue, rvalue);
+ r = path_simplify_and_warn(k, PATH_CHECK_RELATIVE, unit, filename, line, lvalue);
+ if (r < 0)
continue;
- }
-
- if (path_is_absolute(k)) {
- log_syntax(unit, LOG_ERR, filename, line, 0,
- "%s= path is absolute, ignoring assignment: %s", lvalue, rvalue);
- continue;
- }
if (path_startswith(k, "private")) {
log_syntax(unit, LOG_ERR, filename, line, 0,
- "%s= path can't be 'private', ingoring assignment: %s", lvalue, rvalue);
+ "%s= path can't be 'private', ingoring assignment: %s", lvalue, word);
continue;
}
@@ -3845,11 +3828,6 @@ int config_parse_namespace_path_strv(
return 0;
}
- if (!utf8_is_valid(word)) {
- log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
- continue;
- }
-
w = word;
if (startswith(w, "-")) {
ignore_enoent = true;
@@ -3866,12 +3844,9 @@ int config_parse_namespace_path_strv(
continue;
}
- if (!path_is_absolute(resolved)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", resolved);
+ r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
+ if (r < 0)
continue;
- }
-
- path_kill_slashes(resolved);
joined = strjoin(ignore_enoent ? "-" : "",
shall_prefix ? "+" : "",
@@ -3950,12 +3925,9 @@ int config_parse_temporary_filesystems(
continue;
}
- if (!path_is_absolute(resolved)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", resolved);
+ r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
+ if (r < 0)
continue;
- }
-
- path_kill_slashes(resolved);
r = temporary_filesystem_add(&c->temporary_filesystems, &c->n_temporary_filesystems, path, w);
if (r == -ENOMEM)
@@ -4010,7 +3982,7 @@ int config_parse_bind_paths(
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s: %s", lvalue, rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s, ignoring: %s", lvalue, rvalue);
return 0;
}
@@ -4018,7 +3990,7 @@ int config_parse_bind_paths(
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to resolved unit specifiers in \"%s\", ignoring: %m", source);
- return 0;
+ continue;
}
s = sresolved;
@@ -4027,16 +3999,9 @@ int config_parse_bind_paths(
s++;
}
- if (!utf8_is_valid(s)) {
- log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, s);
- return 0;
- }
- if (!path_is_absolute(s)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute source path, ignoring: %s", s);
- return 0;
- }
-
- path_kill_slashes(s);
+ r = path_simplify_and_warn(s, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
+ if (r < 0)
+ continue;
/* Optionally, the destination is specified. */
if (p && p[-1] == ':') {
@@ -4044,31 +4009,26 @@ int config_parse_bind_paths(
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s: %s", lvalue, rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s, ignoring: %s", lvalue, rvalue);
return 0;
}
if (r == 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Missing argument after ':': %s", rvalue);
- return 0;
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Missing argument after ':', ignoring: %s", s);
+ continue;
}
r = unit_full_printf(u, destination, &dresolved);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to resolved specifiers in \"%s\", ignoring: %m", destination);
- return 0;
+ continue;
}
- if (!utf8_is_valid(dresolved)) {
- log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, dresolved);
- return 0;
- }
- if (!path_is_absolute(dresolved)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute destination path, ignoring: %s", dresolved);
- return 0;
- }
+ r = path_simplify_and_warn(dresolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
+ if (r < 0)
+ continue;
- d = path_kill_slashes(dresolved);
+ d = dresolved;
/* Optionally, there's also a short option string specified */
if (p && p[-1] == ':') {
@@ -4088,7 +4048,7 @@ int config_parse_bind_paths(
rbind = false;
else {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid option string, ignoring setting: %s", options);
- return 0;
+ continue;
}
}
} else
@@ -4203,7 +4163,7 @@ static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
if (c++ >= FOLLOW_MAX)
return -ELOOP;
- path_kill_slashes(*filename);
+ path_simplify(*filename, false);
/* Add the file name we are currently looking at to
* the names of this unit, but only if it is a valid
diff --git a/src/core/manager.c b/src/core/manager.c
index b4f197c204..b5742f1f7f 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -3867,7 +3867,7 @@ Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) {
assert(path);
strcpy(p, path);
- path_kill_slashes(p);
+ path_simplify(p, false);
return hashmap_get(m->units_requiring_mounts_for, streq(p, "/") ? "" : p);
}
diff --git a/src/core/mount.c b/src/core/mount.c
index d5463b7621..d9bc4abb20 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -554,7 +554,7 @@ static int mount_add_extras(Mount *m) {
return r;
}
- path_kill_slashes(m->where);
+ path_simplify(m->where, false);
if (!u->description) {
r = unit_set_description(u, m->where);
diff --git a/src/core/path.c b/src/core/path.c
index c0c0f07563..e0b9238ce0 100644
--- a/src/core/path.c
+++ b/src/core/path.c
@@ -67,7 +67,7 @@ int path_spec_watch(PathSpec *s, sd_event_io_handler_t handler) {
(void) sd_event_source_set_description(s->event_source, "path");
- /* This function assumes the path was passed through path_kill_slashes()! */
+ /* This function assumes the path was passed through path_simplify()! */
assert(!strstr(s->path, "//"));
for (slash = strchr(s->path, '/'); ; slash = strchr(slash+1, '/')) {
diff --git a/src/core/service.c b/src/core/service.c
index 1af3032597..068fd67be7 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -2887,7 +2887,7 @@ static int service_demand_pid_file(Service *s) {
return -ENOMEM;
}
- path_kill_slashes(ps->path);
+ path_simplify(ps->path, false);
/* PATH_CHANGED would not be enough. There are daemons (sendmail) that
* keep their PID file open all the time. */
diff --git a/src/core/socket.c b/src/core/socket.c
index 238c942a1a..0ef355a73b 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -1393,7 +1393,7 @@ static int usbffs_dispatch_eps(SocketPort *p) {
if (!ep)
return -ENOMEM;
- path_kill_slashes(ep);
+ path_simplify(ep, false);
r = usbffs_address_create(ep);
if (r < 0)
diff --git a/src/core/swap.c b/src/core/swap.c
index e75c9f2464..95534bdda4 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -307,7 +307,7 @@ static int swap_load(Unit *u) {
return -ENOMEM;
}
- path_kill_slashes(s->what);
+ path_simplify(s->what, false);
if (!UNIT(s)->description) {
r = unit_set_description(u, s->what);
diff --git a/src/core/unit.c b/src/core/unit.c
index 2567365937..fd0d8da3aa 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -4551,7 +4551,7 @@ int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask)
if (!p)
return -ENOMEM;
- path = path_kill_slashes(p);
+ path = path_simplify(p, false);
if (!path_is_normalized(path))
return -EPERM;
diff --git a/src/delta/delta.c b/src/delta/delta.c
index aab1dbfad2..074ef426a9 100644
--- a/src/delta/delta.c
+++ b/src/delta/delta.c
@@ -655,7 +655,7 @@ int main(int argc, char *argv[]) {
int i;
for (i = optind; i < argc; i++) {
- path_kill_slashes(argv[i]);
+ path_simplify(argv[i], false);
k = process_suffix_chop(argv[i]);
if (k < 0)
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
index 5c7e1df8f1..daa8f5cd16 100644
--- a/src/fstab-generator/fstab-generator.c
+++ b/src/fstab-generator/fstab-generator.c
@@ -543,7 +543,7 @@ static int parse_fstab(bool initrd) {
return log_oom();
if (is_path(where)) {
- path_kill_slashes(where);
+ path_simplify(where, false);
/* Follow symlinks here; see 5261ba901845c084de5a8fd06500ed09bfb0bd80 which makes sense for
* mount units, but causes problems since it historically worked to have symlinks in e.g.
diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c
index 7726cdb3aa..0e92fcbe03 100644
--- a/src/libsystemd/sd-device/sd-device.c
+++ b/src/libsystemd/sd-device/sd-device.c
@@ -178,7 +178,7 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
return log_oom();
free_and_replace(syspath, new_syspath);
- path_kill_slashes(syspath);
+ path_simplify(syspath, false);
}
if (path_startswith(syspath, "/sys/devices/")) {
diff --git a/src/mount/mount-tool.c b/src/mount/mount-tool.c
index 02989301fe..5e22a434f1 100644
--- a/src/mount/mount-tool.c
+++ b/src/mount/mount-tool.c
@@ -354,7 +354,7 @@ static int parse_argv(int argc, char *argv[]) {
if (!arg_mount_what)
return log_oom();
- path_kill_slashes(arg_mount_what);
+ path_simplify(arg_mount_what, false);
if (!path_is_absolute(arg_mount_what)) {
log_error("Only absolute path is supported: %s", arg_mount_what);
@@ -372,7 +372,7 @@ static int parse_argv(int argc, char *argv[]) {
if (!arg_mount_where)
return log_oom();
- path_kill_slashes(arg_mount_where);
+ path_simplify(arg_mount_where, false);
if (!path_is_absolute(arg_mount_where)) {
log_error("Only absolute path is supported: %s", arg_mount_where);
@@ -992,7 +992,7 @@ static int action_umount(
if (!p)
return log_oom();
- path_kill_slashes(p);
+ path_simplify(p, false);
r = stop_mounts(bus, p);
if (r < 0)
diff --git a/src/portable/portable.c b/src/portable/portable.c
index aaabe9fb36..eac0a4d616 100644
--- a/src/portable/portable.c
+++ b/src/portable/portable.c
@@ -630,14 +630,14 @@ static int portable_changes_add(
if (!p)
return -ENOMEM;
- path_kill_slashes(p);
+ path_simplify(p, false);
if (source) {
s = strdup(source);
if (!s)
return -ENOMEM;
- path_kill_slashes(s);
+ path_simplify(s, false);
}
c[(*n_changes)++] = (PortableChange) {
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index c74c83ba5b..8dc35d4206 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -211,6 +211,9 @@ static int parse_line(
return config_parse(unit, fn, NULL, sections, lookup, table, flags, userdata);
}
+ if (!utf8_is_valid(l))
+ return log_syntax_invalid_utf8(unit, LOG_WARNING, filename, line, l);
+
if (*l == '[') {
size_t k;
char *n;
@@ -237,8 +240,7 @@ static int parse_line(
*section_line = 0;
*section_ignored = true;
} else {
- free(*section);
- *section = n;
+ free_and_replace(*section, n);
*section_line = line;
*section_ignored = false;
}
@@ -396,7 +398,6 @@ int config_parse(const char *unit,
if (flags & CONFIG_PARSE_WARN)
log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
return r;
-
}
continuation = mfree(continuation);
@@ -419,7 +420,6 @@ int config_parse(const char *unit,
if (flags & CONFIG_PARSE_WARN)
log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
return r;
-
}
}
@@ -688,11 +688,6 @@ int config_parse_string(
assert(rvalue);
assert(data);
- if (!utf8_is_valid(rvalue)) {
- log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
- return 0;
- }
-
if (free_and_strdup(s, empty_to_null(rvalue)) < 0)
return log_oom();
@@ -713,6 +708,7 @@ int config_parse_path(
char **s = data, *n;
bool fatal = ltype;
+ int r;
assert(filename);
assert(lvalue);
@@ -724,27 +720,16 @@ int config_parse_path(
goto finalize;
}
- if (!utf8_is_valid(rvalue)) {
- log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
- return fatal ? -ENOEXEC : 0;
- }
-
- if (!path_is_absolute(rvalue)) {
- log_syntax(unit, LOG_ERR, filename, line, 0,
- "Not an absolute path%s: %s",
- fatal ? "" : ", ignoring", rvalue);
- return fatal ? -ENOEXEC : 0;
- }
-
n = strdup(rvalue);
if (!n)
return log_oom();
- path_kill_slashes(n);
+ r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE | (fatal ? PATH_CHECK_FATAL : 0), unit, filename, line, lvalue);
+ if (r < 0)
+ return fatal ? -ENOEXEC : 0;
finalize:
- free(*s);
- *s = n;
+ free_and_replace(*s, n);
return 0;
}
@@ -787,12 +772,6 @@ int config_parse_strv(
break;
}
- if (!utf8_is_valid(word)) {
- log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
- free(word);
- continue;
- }
-
r = strv_consume(sv, word);
if (r < 0)
return log_oom();
diff --git a/src/shared/install.c b/src/shared/install.c
index ecda662f28..46e07ebb98 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -309,9 +309,9 @@ int unit_file_changes_add(
if (!p || (source && !s))
return -ENOMEM;
- path_kill_slashes(p);
+ path_simplify(p, false);
if (s)
- path_kill_slashes(s);
+ path_simplify(s, false);
c[*n_changes] = (UnitFileChange) { type, p, s };
p = s = NULL;
@@ -516,7 +516,7 @@ static int mark_symlink_for_removal(
if (!n)
return -ENOMEM;
- path_kill_slashes(n);
+ path_simplify(n, false);
r = set_consume(*remove_symlinks_to, n);
if (r == -EEXIST)
@@ -598,7 +598,7 @@ static int remove_marked_symlinks_fd(
p = path_make_absolute(de->d_name, path);
if (!p)
return -ENOMEM;
- path_kill_slashes(p);
+ path_simplify(p, false);
q = readlink_malloc(p, &dest);
if (q == -ENOENT)
diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c
index e67f1f0645..404dd2aace 100644
--- a/src/shared/machine-image.c
+++ b/src/shared/machine-image.c
@@ -170,7 +170,7 @@ static int image_new(
if (!i->path)
return -ENOMEM;
- path_kill_slashes(i->path);
+ path_simplify(i->path, false);
*ret = TAKE_PTR(i);
diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c
index c14cfd48af..7caa97e27b 100644
--- a/src/sysusers/sysusers.c
+++ b/src/sysusers/sysusers.c
@@ -1599,8 +1599,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
if (resolved_id) {
if (path_is_absolute(resolved_id)) {
i->uid_path = TAKE_PTR(resolved_id);
-
- path_kill_slashes(i->uid_path);
+ path_simplify(i->uid_path, false);
} else {
_cleanup_free_ char *uid = NULL, *gid = NULL;
if (split_pair(resolved_id, ":", &uid, &gid) == 0) {
@@ -1651,8 +1650,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
if (resolved_id) {
if (path_is_absolute(resolved_id)) {
i->gid_path = TAKE_PTR(resolved_id);
-
- path_kill_slashes(i->gid_path);
+ path_simplify(i->gid_path, false);
} else {
r = parse_gid(resolved_id, &i->gid);
if (r < 0)
diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c
index d569bdd85f..aa6e4f1a95 100644
--- a/src/test/test-conf-parser.c
+++ b/src/test/test-conf-parser.c
@@ -96,6 +96,7 @@ static void test_config_parse_path(void) {
test_config_parse_path_one("/path", "/path");
test_config_parse_path_one("/path//////////", "/path");
test_config_parse_path_one("///path/foo///bar////bar//", "/path/foo/bar/bar");
+ test_config_parse_path_one("/path//./////hogehoge///.", "/path/hogehoge");
test_config_parse_path_one("/path/\xc3\x80", "/path/\xc3\x80");
test_config_parse_path_one("not_absolute/path", NULL);
@@ -170,7 +171,7 @@ static void test_config_parse_strv(void) {
test_config_parse_strv_one("foo bar foo", STRV_MAKE("foo", "bar", "foo"));
test_config_parse_strv_one("\"foo bar\" foo", STRV_MAKE("foo bar", "foo"));
test_config_parse_strv_one("\xc3\x80", STRV_MAKE("\xc3\x80"));
- test_config_parse_strv_one("\xc3\x7f", STRV_MAKE_EMPTY);
+ test_config_parse_strv_one("\xc3\x7f", STRV_MAKE("\xc3\x7f"));
}
static void test_config_parse_mode(void) {
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index 7095dd2a2e..13d9ee54a5 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -176,6 +176,7 @@ static void test_exec_workingdirectory(Manager *m) {
assert_se(mkdir_p("/tmp/test-exec_workingdirectory", 0755) >= 0);
test(m, "exec-workingdirectory.service", 0, CLD_EXITED);
+ test(m, "exec-workingdirectory-trailing-dot.service", 0, CLD_EXITED);
(void) rm_rf("/tmp/test-exec_workingdirectory", REMOVE_ROOT|REMOVE_PHYSICAL);
}
diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c
index c65b0b06b4..454d27accd 100644
--- a/src/test/test-path-util.c
+++ b/src/test/test-path-util.c
@@ -26,6 +26,16 @@
assert_se(path_equal(b, a) == !result); \
}
+static void test_path_simplify(const char *in, const char *out, const char *out_dot) {
+ char *p;
+
+ p = strdupa(in);
+ assert_se(streq(path_simplify(p, false), out));
+
+ p = strdupa(in);
+ assert_se(streq(path_simplify(p, true), out_dot));
+}
+
static void test_path(void) {
_cleanup_close_ int fd = -1;
@@ -69,15 +79,28 @@ static void test_path(void) {
assert_se(fd >= 0);
assert_se(fd_is_mount_point(fd, "/", 0) > 0);
- {
- char p1[] = "aaa/bbb////ccc";
- char p2[] = "//aaa/.////ccc";
- char p3[] = "/./";
-
- assert_se(path_equal(path_kill_slashes(p1), "aaa/bbb/ccc"));
- assert_se(path_equal(path_kill_slashes(p2), "/aaa/./ccc"));
- assert_se(path_equal(path_kill_slashes(p3), "/./"));
- }
+ test_path_simplify("aaa/bbb////ccc", "aaa/bbb/ccc", "aaa/bbb/ccc");
+ test_path_simplify("//aaa/.////ccc", "/aaa/./ccc", "/aaa/ccc");
+ test_path_simplify("///", "/", "/");
+ test_path_simplify("///.//", "/.", "/");
+ test_path_simplify("///.//.///", "/./.", "/");
+ test_path_simplify("////.././///../.", "/.././../.", "/../..");
+ test_path_simplify(".", ".", "");
+ test_path_simplify("./", ".", "");
+ test_path_simplify(".///.//./.", "./././.", "");
+ test_path_simplify(".///.//././/", "./././.", "");
+ test_path_simplify("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/.",
+ "/./aaa/././.bbb/../c./d.dd/..eeee/.",
+ "/aaa/.bbb/../c./d.dd/..eeee");
+ test_path_simplify("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/..",
+ "/./aaa/././.bbb/../c./d.dd/..eeee/..",
+ "/aaa/.bbb/../c./d.dd/..eeee/..");
+ test_path_simplify(".//./aaa///.//./.bbb/..///c.//d.dd///..eeee/..",
+ "././aaa/././.bbb/../c./d.dd/..eeee/..",
+ "aaa/.bbb/../c./d.dd/..eeee/..");
+ test_path_simplify("..//./aaa///.//./.bbb/..///c.//d.dd///..eeee/..",
+ ".././aaa/././.bbb/../c./d.dd/..eeee/..",
+ "../aaa/.bbb/../c./d.dd/..eeee/..");
assert_se(PATH_IN_SET("/bin", "/", "/bin", "/foo"));
assert_se(PATH_IN_SET("/bin", "/bin"));
@@ -263,7 +286,7 @@ static void test_make_relative(void) {
test("/some/path", "/", "../..");
test("/some/path", "/some/other/path", "../other/path");
test("/some/path/./dot", "/some/further/path", "../../further/path");
- test("//extra/////slashes///won't////fool///anybody//", "////extra///slashes////are/just///fine///", "../../../are/just/fine");
+ test("//extra.//.//./.slashes//./won't////fo.ol///anybody//", "/././/extra././/.slashes////ar.e/.just/././.fine///", "../../../ar.e/.just/.fine");
}
static void test_strv_resolve(void) {
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index ae39d720a2..6bfa44f076 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -431,7 +431,7 @@ static void load_unix_sockets(void) {
goto fail;
}
- path_kill_slashes(s);
+ path_simplify(s, false);
r = set_consume(unix_sockets, s);
if (r < 0 && r != -EEXIST) {
@@ -2289,7 +2289,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
return -EBADMSG;
}
- path_kill_slashes(i.argument);
+ path_simplify(i.argument, false);
break;
case CREATE_CHAR_DEVICE:
@@ -2362,7 +2362,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
return -EBADMSG;
}
- path_kill_slashes(i.path);
+ path_simplify(i.path, false);
if (!should_include_path(i.path))
return 0;
diff --git a/test/meson.build b/test/meson.build
index 162f63f1ed..9d4c7dbb72 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -145,6 +145,7 @@ test_data_files = '''
test-execute/exec-user-nobody.service
test-execute/exec-user.service
test-execute/exec-workingdirectory.service
+ test-execute/exec-workingdirectory-trailing-dot.service
test-path/basic.target
test-path/path-changed.path
test-path/path-changed.service
diff --git a/test/test-execute/exec-runtimedirectory.service b/test/test-execute/exec-runtimedirectory.service
index d8f242fde2..6a4383110f 100644
--- a/test/test-execute/exec-runtimedirectory.service
+++ b/test/test-execute/exec-runtimedirectory.service
@@ -3,5 +3,7 @@ Description=Test for RuntimeDirectory
[Service]
ExecStart=/bin/sh -x -c 'test -d %t/test-exec_runtimedirectory'
+ExecStart=/bin/sh -x -c 'test -d %t/test-exec_runtimedirectory2/hogehoge'
Type=oneshot
RuntimeDirectory=test-exec_runtimedirectory
+RuntimeDirectory=./test-exec_runtimedirectory2///./hogehoge/.
diff --git a/test/test-execute/exec-workingdirectory-trailing-dot.service b/test/test-execute/exec-workingdirectory-trailing-dot.service
new file mode 100644
index 0000000000..5c807b3172
--- /dev/null
+++ b/test/test-execute/exec-workingdirectory-trailing-dot.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for WorkingDirectory with trailing dot
+
+[Service]
+ExecStart=/bin/sh -x -c 'test "$$PWD" = "/tmp/test-exec_workingdirectory"'
+Type=oneshot
+WorkingDirectory=/tmp///./test-exec_workingdirectory/.