summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/basic/fs-util.c17
-rw-r--r--src/basic/fs-util.h1
-rw-r--r--src/test/test-fs-util.c28
3 files changed, 45 insertions, 1 deletions
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index 154163535..32b1fb605 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -647,6 +647,10 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
assert(path);
+ /* Either the file may be missing, or we return an fd to the final object, but both make no sense */
+ if ((flags & (CHASE_NONEXISTENT|CHASE_OPEN)) == (CHASE_NONEXISTENT|CHASE_OPEN))
+ return -EINVAL;
+
/* 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.
*
@@ -896,6 +900,19 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
done = NULL;
}
+ if (flags & CHASE_OPEN) {
+ int q;
+
+ /* Return the O_PATH fd we currently are looking to the caller. It can translate it to a proper fd by
+ * opening /proc/self/fd/xyz. */
+
+ assert(fd >= 0);
+ q = fd;
+ fd = -1;
+
+ return q;
+ }
+
return exists;
}
diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h
index 13008fdda..fad0a2eed 100644
--- a/src/basic/fs-util.h
+++ b/src/basic/fs-util.h
@@ -99,6 +99,7 @@ enum {
CHASE_NONEXISTENT = 1U << 1, /* If set, it's OK if the path doesn't actually exist. */
CHASE_NO_AUTOFS = 1U << 2, /* If set, return -EREMOTE if autofs mount point found */
CHASE_SAFE = 1U << 3, /* If set, return EPERM if we ever traverse from unprivileged to privileged files or directories */
+ CHASE_OPEN = 1U << 4, /* If set, return an O_PATH object to the final component */
};
int chase_symlinks(const char *path_with_prefix, const char *root, unsigned flags, char **ret);
diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c
index 1c453e11a..22aa64f4c 100644
--- a/src/test/test-fs-util.c
+++ b/src/test/test-fs-util.c
@@ -22,12 +22,15 @@
#include "alloc-util.h"
#include "fd-util.h"
+//#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
+//#include "id128-util.h"
#include "macro.h"
#include "mkdir.h"
#include "path-util.h"
#include "rm-rf.h"
+//#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
//#include "user-util.h"
@@ -37,7 +40,7 @@ static void test_chase_symlinks(void) {
_cleanup_free_ char *result = NULL;
char temp[] = "/tmp/test-chase.XXXXXX";
const char *top, *p, *pslash, *q, *qslash;
- int r;
+ int r, pfd;
assert_se(mkdtemp(temp));
@@ -262,6 +265,29 @@ static void test_chase_symlinks(void) {
assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) >= 0);
}
+ p = strjoina(temp, "/machine-id-test");
+ assert_se(symlink("/usr/../etc/./machine-id", p) >= 0);
+
+ pfd = chase_symlinks(p, NULL, CHASE_OPEN, NULL);
+ if (pfd != -ENOENT) {
+ char procfs[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(pfd) + 1];
+ _cleanup_close_ int fd = -1;
+ sd_id128_t a, b;
+
+ assert_se(pfd >= 0);
+
+ xsprintf(procfs, "/proc/self/fd/%i", pfd);
+
+ fd = open(procfs, O_RDONLY|O_CLOEXEC);
+ assert_se(fd >= 0);
+
+ safe_close(pfd);
+
+ assert_se(id128_read_fd(fd, ID128_PLAIN, &a) >= 0);
+ assert_se(sd_id128_get_machine(&b) >= 0);
+ assert_se(sd_id128_equal(a, b));
+ }
+
assert_se(rm_rf(temp, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}