summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2019-07-26 18:42:31 +0200
committerGitHub <noreply@github.com>2019-07-26 18:42:31 +0200
commit17f8fd9cf74b190c19140e16a0bf65de588bdbc7 (patch)
treeb101673efb20d3e1d1f00001d8987d94da8977a2 /src
parent2a2f3e7f3e3734c0b8fd718c0a03b88b09a68704 (diff)
parent22f62b1274ba120ebc0d7de95bf3241982ddb840 (diff)
downloadsystemd-17f8fd9cf74b190c19140e16a0bf65de588bdbc7.tar.gz
systemd-17f8fd9cf74b190c19140e16a0bf65de588bdbc7.tar.bz2
systemd-17f8fd9cf74b190c19140e16a0bf65de588bdbc7.zip
Merge pull request #13194 from keszybz/chase-symlinks-testing
Chase symlinks testing
Diffstat (limited to 'src')
-rw-r--r--src/basic/fs-util.c18
-rw-r--r--src/basic/fs-util.h18
-rw-r--r--src/test/meson.build5
-rw-r--r--src/test/test-chase-symlinks.c105
4 files changed, 129 insertions, 17 deletions
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index f929db9c23..b2ac648838 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -732,7 +732,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
* 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.
+ * to 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
@@ -742,9 +742,9 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
* There are three ways to invoke this function:
*
* 1. Without CHASE_STEP or CHASE_OPEN: in this case the path is resolved and the normalized path is returned
- * in `ret`. The return value is < 0 on error. If CHASE_NONEXISTENT is also set 0 is returned if the file
- * doesn't exist, > 0 otherwise. If CHASE_NONEXISTENT is not set >= 0 is returned if the destination was
- * found, -ENOENT if it doesn't.
+ * in `ret`. The return value is < 0 on error. If CHASE_NONEXISTENT is also set, 0 is returned if the file
+ * doesn't exist, > 0 otherwise. If CHASE_NONEXISTENT is not set, >= 0 is returned if the destination was
+ * found, -ENOENT if it wasn't.
*
* 2. With CHASE_OPEN: in this case the destination is opened after chasing it as O_PATH and this file
* descriptor is returned as return value. This is useful to open files relative to some root
@@ -760,13 +760,13 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
*
* 4. With CHASE_SAFE: in this case the path must not contain unsafe transitions, i.e. transitions from
* unprivileged to privileged files or directories. In such cases the return value is -ENOLINK. If
- * CHASE_WARN is also set a warning describing the unsafe transition is emitted.
+ * CHASE_WARN is also set, a warning describing the unsafe transition is emitted.
*
- * 5. With CHASE_NO_AUTOFS: in this case if an autofs mount point is encountered, the path normalization is
- * aborted and -EREMOTE is returned. If CHASE_WARN is also set a warning showing the path of the mount point
- * is emitted.
+ * 5. With CHASE_NO_AUTOFS: in this case if an autofs mount point is encountered, path normalization
+ * is aborted and -EREMOTE is returned. If CHASE_WARN is also set, a warning showing the path of
+ * the mount point is emitted.
*
- * */
+ */
/* A root directory of "/" or "" is identical to none */
if (empty_or_root(original_root))
diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h
index c7c5899815..1f0bdd95b3 100644
--- a/src/basic/fs-util.h
+++ b/src/basic/fs-util.h
@@ -74,14 +74,16 @@ union inotify_event_buffer {
int inotify_add_watch_fd(int fd, int what, uint32_t mask);
enum {
- CHASE_PREFIX_ROOT = 1 << 0, /* If set, the specified path will be prefixed by the specified root before beginning the iteration */
- CHASE_NONEXISTENT = 1 << 1, /* If set, it's OK if the path doesn't actually exist. */
- CHASE_NO_AUTOFS = 1 << 2, /* If set, return -EREMOTE if autofs mount point found */
- CHASE_SAFE = 1 << 3, /* If set, return EPERM if we ever traverse from unprivileged to privileged files or directories */
- CHASE_OPEN = 1 << 4, /* If set, return an O_PATH object to the final component */
- CHASE_TRAIL_SLASH = 1 << 5, /* If set, any trailing slash will be preserved */
- CHASE_STEP = 1 << 6, /* If set, just execute a single step of the normalization */
- CHASE_NOFOLLOW = 1 << 7, /* Only valid with CHASE_OPEN: when the path's right-most component refers to symlink return O_PATH fd of the symlink, rather than following it. */
+ CHASE_PREFIX_ROOT = 1 << 0, /* The specified path will be prefixed by the specified root before beginning the iteration */
+ CHASE_NONEXISTENT = 1 << 1, /* It's OK if the path doesn't actually exist. */
+ CHASE_NO_AUTOFS = 1 << 2, /* Return -EREMOTE if autofs mount point found */
+ CHASE_SAFE = 1 << 3, /* Return EPERM if we ever traverse from unprivileged to privileged files or directories */
+ CHASE_OPEN = 1 << 4, /* Return an O_PATH object to the final component */
+ CHASE_TRAIL_SLASH = 1 << 5, /* Any trailing slash will be preserved */
+ CHASE_STEP = 1 << 6, /* Just execute a single step of the normalization */
+ CHASE_NOFOLLOW = 1 << 7, /* Do not follow the path's right-most compontent. With CHASE_OPEN, when
+ * the path's right-most component refers to symlink, return O_PATH fd of
+ * the symlink. */
CHASE_WARN = 1 << 8, /* Emit an appropriate warning when an error is encountered */
};
diff --git a/src/test/meson.build b/src/test/meson.build
index e337e50146..0595cfe37a 100644
--- a/src/test/meson.build
+++ b/src/test/meson.build
@@ -627,6 +627,11 @@ tests += [
[],
[]],
+ [['src/test/test-chase-symlinks.c'],
+ [],
+ [],
+ '', 'manual'],
+
[['src/test/test-path.c',
'src/test/test-helper.c'],
[libcore,
diff --git a/src/test/test-chase-symlinks.c b/src/test/test-chase-symlinks.c
new file mode 100644
index 0000000000..3fac6b6bc5
--- /dev/null
+++ b/src/test/test-chase-symlinks.c
@@ -0,0 +1,105 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <getopt.h>
+
+#include "log.h"
+#include "fs-util.h"
+#include "main-func.h"
+
+static char *arg_root = NULL;
+static int arg_flags = 0;
+
+static int parse_argv(int argc, char *argv[]) {
+ enum {
+ ARG_ROOT = 0x1000,
+ };
+
+ static const struct option options[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "root", required_argument, NULL, ARG_ROOT },
+
+ { "prefix-root", no_argument, NULL, CHASE_PREFIX_ROOT },
+ { "nonexistent", no_argument, NULL, CHASE_NONEXISTENT },
+ { "no_autofs", no_argument, NULL, CHASE_NO_AUTOFS },
+ { "safe", no_argument, NULL, CHASE_SAFE },
+ { "open", no_argument, NULL, CHASE_OPEN },
+ { "trail-slash", no_argument, NULL, CHASE_TRAIL_SLASH },
+ { "step", no_argument, NULL, CHASE_STEP },
+ { "nofollow", no_argument, NULL, CHASE_NOFOLLOW },
+ { "warn", no_argument, NULL, CHASE_WARN },
+ {}
+ };
+
+ int c;
+
+ assert(argc >= 0);
+ assert(argv);
+
+ while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
+ switch (c) {
+
+ case 'h':
+ printf("Syntax:\n"
+ " %s [OPTION...] path...\n"
+ "Options:\n"
+ , argv[0]);
+ for (size_t i = 0; i < ELEMENTSOF(options) - 1; i++)
+ printf(" --%s\n", options[i].name);
+ return 0;
+
+ case ARG_ROOT:
+ arg_root = optarg;
+ break;
+
+ case CHASE_PREFIX_ROOT:
+ case CHASE_NONEXISTENT:
+ case CHASE_NO_AUTOFS:
+ case CHASE_SAFE:
+ case CHASE_OPEN:
+ case CHASE_TRAIL_SLASH:
+ case CHASE_STEP:
+ case CHASE_NOFOLLOW:
+ case CHASE_WARN:
+ arg_flags |= c;
+ break;
+
+ case '?':
+ return -EINVAL;
+
+ default:
+ assert_not_reached("Unhandled option");
+ }
+
+ if (optind == argc)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "At least one argument is required.");
+
+ return 1;
+}
+
+static int run(int argc, char **argv) {
+ int r;
+
+ log_show_color(true);
+ log_parse_environment();
+ log_open();
+
+ r = parse_argv(argc, argv);
+ if (r <= 0)
+ return r;
+
+ for (int i = optind; i < argc; i++) {
+ _cleanup_free_ char *p = NULL;
+
+ printf("%s ", argv[i]);
+ fflush(stdout);
+
+ r = chase_symlinks(argv[i], arg_root, arg_flags, &p);
+ if (r < 0)
+ log_error_errno(r, "failed: %m");
+ else
+ log_info("→ %s", p);
+ }
+
+ return 0;
+}
+
+DEFINE_MAIN_FUNCTION(run);