summaryrefslogtreecommitdiff
path: root/src/basic
diff options
context:
space:
mode:
Diffstat (limited to 'src/basic')
-rw-r--r--src/basic/calendarspec.c8
-rw-r--r--src/basic/fs-util.c89
-rw-r--r--src/basic/fs-util.h9
-rw-r--r--src/basic/mount-util.c14
-rw-r--r--src/basic/mount-util.h2
-rw-r--r--src/basic/parse-util.c16
-rw-r--r--src/basic/parse-util.h2
-rw-r--r--src/basic/path-util.c45
-rw-r--r--src/basic/path-util.h4
-rw-r--r--src/basic/time-util.c2
10 files changed, 123 insertions, 68 deletions
diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c
index 8b57de4744..514587d237 100644
--- a/src/basic/calendarspec.c
+++ b/src/basic/calendarspec.c
@@ -752,12 +752,8 @@ static int parse_calendar_time(const char **p, CalendarSpec *c) {
goto fail;
/* Already at the end? Then it's hours and minutes, and seconds are 0 */
- if (*t == 0) {
- if (m != NULL)
- goto null_second;
-
- goto finish;
- }
+ if (*t == 0)
+ goto null_second;
if (*t != ':') {
r = -EINVAL;
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index d2c322a0de..b30cec4f92 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -224,25 +224,25 @@ int readlink_and_make_absolute(const char *p, char **r) {
return 0;
}
-int readlink_and_canonicalize(const char *p, char **r) {
+int readlink_and_canonicalize(const char *p, const char *root, char **ret) {
char *t, *s;
- int j;
+ int r;
assert(p);
- assert(r);
+ assert(ret);
- j = readlink_and_make_absolute(p, &t);
- if (j < 0)
- return j;
+ r = readlink_and_make_absolute(p, &t);
+ if (r < 0)
+ return r;
- s = canonicalize_file_name(t);
- if (s) {
+ r = chase_symlinks(t, root, 0, &s);
+ if (r < 0)
+ /* If we can't follow up, then let's return the original string, slightly cleaned up. */
+ *ret = path_kill_slashes(t);
+ else {
+ *ret = s;
free(t);
- *r = s;
- } else
- *r = t;
-
- path_kill_slashes(*r);
+ }
return 0;
}
@@ -598,10 +598,11 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
return r;
}
-int chase_symlinks(const char *path, const char *_root, char **ret) {
+int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret) {
_cleanup_free_ char *buffer = NULL, *done = NULL, *root = NULL;
_cleanup_close_ int fd = -1;
unsigned max_follow = 32; /* how many symlinks to follow before giving up and returning ELOOP */
+ bool exists = true;
char *todo;
int r;
@@ -610,26 +611,39 @@ int chase_symlinks(const char *path, const char *_root, char **ret) {
/* This is a lot like canonicalize_file_name(), but takes an additional "root" parameter, that allows following
* symlinks relative to a root directory, instead of the root of the host.
*
- * Note that "root" matters only if we encounter an absolute symlink, it's unused otherwise. Most importantly
- * this means the path parameter passed in is not prefixed by it.
+ * Note that "root" primarily matters if we encounter an absolute symlink. It is also used when following
+ * relative symlinks to ensure they cannot be used to "escape" the root directory. The path parameter passed is
+ * assumed to be already prefixed by it, except if the CHASE_PREFIX_ROOT flag is set, in which case it is first
+ * prefixed accordingly.
*
* Algorithmically this operates on two path buffers: "done" are the components of the path we already
* processed and resolved symlinks, "." and ".." of. "todo" are the components of the path we still need to
* process. On each iteration, we move one component from "todo" to "done", processing it's special meaning
* each time. The "todo" path always starts with at least one slash, the "done" path always ends in no
* slash. We always keep an O_PATH fd to the component we are currently processing, thus keeping lookup races
- * at a minimum. */
-
- r = path_make_absolute_cwd(path, &buffer);
- if (r < 0)
- return r;
+ * at a minimum.
+ *
+ * Suggested usage: whenever you want to canonicalize a path, use this function. Pass the absolute path you got
+ * as-is: fully qualified and relative to your host's root. Optionally, specify the root parameter to tell this
+ * function what to do when encountering a symlink with an absolute path as directory: prefix it by the
+ * specified path.
+ *
+ * Note: there's also chase_symlinks_prefix() (see below), which as first step prefixes the passed path by the
+ * passed root. */
- if (_root) {
- r = path_make_absolute_cwd(_root, &root);
+ if (original_root) {
+ r = path_make_absolute_cwd(original_root, &root);
if (r < 0)
return r;
+
+ if (flags & CHASE_PREFIX_ROOT)
+ path = prefix_roota(root, path);
}
+ r = path_make_absolute_cwd(path, &buffer);
+ if (r < 0)
+ return r;
+
fd = open("/", O_CLOEXEC|O_NOFOLLOW|O_PATH);
if (fd < 0)
return -errno;
@@ -665,18 +679,20 @@ int chase_symlinks(const char *path, const char *_root, char **ret) {
_cleanup_free_ char *parent = NULL;
int fd_parent = -1;
+ /* If we already are at the top, then going up will not change anything. This is in-line with
+ * how the kernel handles this. */
if (isempty(done) || path_equal(done, "/"))
- return -EINVAL;
+ continue;
parent = dirname_malloc(done);
if (!parent)
return -ENOMEM;
- /* Don't allow this to leave the root dir */
+ /* Don't allow this to leave the root dir. */
if (root &&
path_startswith(done, root) &&
!path_startswith(parent, root))
- return -EINVAL;
+ continue;
free_and_replace(done, parent);
@@ -692,8 +708,25 @@ int chase_symlinks(const char *path, const char *_root, char **ret) {
/* Otherwise let's see what this is. */
child = openat(fd, first + n, O_CLOEXEC|O_NOFOLLOW|O_PATH);
- if (child < 0)
+ if (child < 0) {
+
+ if (errno == ENOENT &&
+ (flags & CHASE_NONEXISTENT) &&
+ (isempty(todo) || path_is_safe(todo))) {
+
+ /* If CHASE_NONEXISTENT is set, and the path does not exist, then that's OK, return
+ * what we got so far. But don't allow this if the remaining path contains "../ or "./"
+ * or something else weird. */
+
+ if (!strextend(&done, first, todo, NULL))
+ return -ENOMEM;
+
+ exists = false;
+ break;
+ }
+
return -errno;
+ }
if (fstat(child, &st) < 0)
return -errno;
@@ -778,5 +811,5 @@ int chase_symlinks(const char *path, const char *_root, char **ret) {
*ret = done;
done = NULL;
- return 0;
+ return exists;
}
diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h
index 31df47cf1e..0d925c6b84 100644
--- a/src/basic/fs-util.h
+++ b/src/basic/fs-util.h
@@ -39,7 +39,7 @@ int readlinkat_malloc(int fd, const char *p, char **ret);
int readlink_malloc(const char *p, char **r);
int readlink_value(const char *p, char **ret);
int readlink_and_make_absolute(const char *p, char **r);
-int readlink_and_canonicalize(const char *p, char **r);
+int readlink_and_canonicalize(const char *p, const char *root, char **r);
int readlink_and_make_absolute_root(const char *root, const char *path, char **ret);
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
@@ -78,4 +78,9 @@ union inotify_event_buffer {
int inotify_add_watch_fd(int fd, int what, uint32_t mask);
-int chase_symlinks(const char *path, const char *_root, char **ret);
+enum {
+ CHASE_PREFIX_ROOT = 1, /* If set, the specified path will be prefixed by the specified root before beginning the iteration */
+ CHASE_NONEXISTENT = 2, /* If set, it's OK if the path doesn't actually exist. */
+};
+
+int chase_symlinks(const char *path_with_prefix, const char *root, unsigned flags, char **ret);
diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c
index 5d37fb48be..352c3505fb 100644
--- a/src/basic/mount-util.c
+++ b/src/basic/mount-util.c
@@ -29,6 +29,7 @@
#include "escape.h"
#include "fd-util.h"
#include "fileio.h"
+#include "fs-util.h"
#include "hashmap.h"
#include "mount-util.h"
#include "parse-util.h"
@@ -205,9 +206,10 @@ fallback_fstat:
}
/* flags can be AT_SYMLINK_FOLLOW or 0 */
-int path_is_mount_point(const char *t, int flags) {
- _cleanup_close_ int fd = -1;
+int path_is_mount_point(const char *t, const char *root, int flags) {
_cleanup_free_ char *canonical = NULL, *parent = NULL;
+ _cleanup_close_ int fd = -1;
+ int r;
assert(t);
@@ -219,9 +221,9 @@ int path_is_mount_point(const char *t, int flags) {
* /bin -> /usr/bin/ and /usr is a mount point, then the parent that we
* look at needs to be /usr, not /. */
if (flags & AT_SYMLINK_FOLLOW) {
- canonical = canonicalize_file_name(t);
- if (!canonical)
- return -errno;
+ r = chase_symlinks(t, root, 0, &canonical);
+ if (r < 0)
+ return r;
t = canonical;
}
@@ -473,7 +475,7 @@ int bind_remount_recursive(const char *prefix, bool ro, char **blacklist) {
return r;
/* Deal with mount points that are obstructed by a later mount */
- r = path_is_mount_point(x, 0);
+ r = path_is_mount_point(x, NULL, 0);
if (r == -ENOENT || r == 0)
continue;
if (r < 0)
diff --git a/src/basic/mount-util.h b/src/basic/mount-util.h
index 4f305df19f..b840956d63 100644
--- a/src/basic/mount-util.h
+++ b/src/basic/mount-util.h
@@ -30,7 +30,7 @@
#include "missing.h"
int fd_is_mount_point(int fd, const char *filename, int flags);
-int path_is_mount_point(const char *path, int flags);
+int path_is_mount_point(const char *path, const char *root, int flags);
int repeat_unmount(const char *path, int flags);
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
index c98815b9bc..6e58ced6f5 100644
--- a/src/basic/parse-util.c
+++ b/src/basic/parse-util.c
@@ -574,3 +574,19 @@ int parse_nice(const char *p, int *ret) {
*ret = n;
return 0;
}
+
+int parse_ip_port(const char *s, uint16_t *ret) {
+ uint16_t l;
+ int r;
+
+ r = safe_atou16(s, &l);
+ if (r < 0)
+ return r;
+
+ if (l == 0)
+ return -EINVAL;
+
+ *ret = (uint16_t) l;
+
+ return 0;
+}
diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h
index 461e1cd4d8..4d132f0de5 100644
--- a/src/basic/parse-util.h
+++ b/src/basic/parse-util.h
@@ -110,3 +110,5 @@ int parse_percent_unbounded(const char *p);
int parse_percent(const char *p);
int parse_nice(const char *p, int *ret);
+
+int parse_ip_port(const char *s, uint16_t *ret);
diff --git a/src/basic/path-util.c b/src/basic/path-util.c
index 5cdac50c68..9a51e0d8bc 100644
--- a/src/basic/path-util.c
+++ b/src/basic/path-util.c
@@ -220,10 +220,11 @@ int path_strv_make_absolute_cwd(char **l) {
return 0;
}
-char **path_strv_resolve(char **l, const char *prefix) {
+char **path_strv_resolve(char **l, const char *root) {
char **s;
unsigned k = 0;
bool enomem = false;
+ int r;
if (strv_isempty(l))
return l;
@@ -233,17 +234,17 @@ char **path_strv_resolve(char **l, const char *prefix) {
* changes on failure. */
STRV_FOREACH(s, l) {
- char *t, *u;
_cleanup_free_ char *orig = NULL;
+ char *t, *u;
if (!path_is_absolute(*s)) {
free(*s);
continue;
}
- if (prefix) {
+ if (root) {
orig = *s;
- t = strappend(prefix, orig);
+ t = prefix_root(root, orig);
if (!t) {
enomem = true;
continue;
@@ -251,28 +252,26 @@ char **path_strv_resolve(char **l, const char *prefix) {
} else
t = *s;
- errno = 0;
- u = canonicalize_file_name(t);
- if (!u) {
- if (errno == ENOENT) {
- if (prefix) {
- u = orig;
- orig = NULL;
- free(t);
- } else
- u = t;
- } else {
+ r = chase_symlinks(t, root, 0, &u);
+ if (r == -ENOENT) {
+ if (root) {
+ u = orig;
+ orig = NULL;
free(t);
- if (errno == ENOMEM || errno == 0)
- enomem = true;
+ } else
+ u = t;
+ } else if (r < 0) {
+ free(t);
- continue;
- }
- } else if (prefix) {
+ if (r == -ENOMEM)
+ enomem = true;
+
+ continue;
+ } else if (root) {
char *x;
free(t);
- x = path_startswith(u, prefix);
+ x = path_startswith(u, root);
if (x) {
/* restore the slash if it was lost */
if (!startswith(x, "/"))
@@ -304,12 +303,12 @@ char **path_strv_resolve(char **l, const char *prefix) {
return l;
}
-char **path_strv_resolve_uniq(char **l, const char *prefix) {
+char **path_strv_resolve_uniq(char **l, const char *root) {
if (strv_isempty(l))
return l;
- if (!path_strv_resolve(l, prefix))
+ if (!path_strv_resolve(l, root))
return NULL;
return strv_uniq(l);
diff --git a/src/basic/path-util.h b/src/basic/path-util.h
index 66545f52d9..d2bc0d3b8e 100644
--- a/src/basic/path-util.h
+++ b/src/basic/path-util.h
@@ -66,8 +66,8 @@ static inline bool path_equal_ptr(const char *a, const char *b) {
})
int path_strv_make_absolute_cwd(char **l);
-char** path_strv_resolve(char **l, const char *prefix);
-char** path_strv_resolve_uniq(char **l, const char *prefix);
+char** path_strv_resolve(char **l, const char *root);
+char** path_strv_resolve_uniq(char **l, const char *root);
int find_binary(const char *name, char **filename);
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index cbdfd55ada..7a5b29d77e 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -883,6 +883,7 @@ static char* extract_multiplier(char *p, usec_t *multiplier) {
{ "y", USEC_PER_YEAR },
{ "usec", 1ULL },
{ "us", 1ULL },
+ { "µs", 1ULL },
};
unsigned i;
@@ -1016,6 +1017,7 @@ int parse_nsec(const char *t, nsec_t *nsec) {
{ "y", NSEC_PER_YEAR },
{ "usec", NSEC_PER_USEC },
{ "us", NSEC_PER_USEC },
+ { "µs", NSEC_PER_USEC },
{ "nsec", 1ULL },
{ "ns", 1ULL },
{ "", 1ULL }, /* default is nsec */