diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 475400177a6..aa33da48b0d 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -621,10 +621,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, * 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. */ + * specified path. */ if (original_root) { r = path_make_absolute_cwd(original_root, &root); @@ -722,6 +719,10 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, * what we got so far. But don't allow this if the remaining path contains "../ or "./" * or something else weird. */ + /* If done is "/", as first also contains slash at the head, then remove this redundant slash. */ + if (streq_ptr(done, "/")) + *done = '\0'; + if (!strextend(&done, first, todo, NULL)) return -ENOMEM; @@ -794,6 +795,10 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, done = first; first = NULL; } else { + /* If done is "/", as first also contains slash at the head, then remove this redundant slash. */ + if (streq(done, "/")) + *done = '\0'; + if (!strextend(&done, first, NULL)) return -ENOMEM; } diff --git a/src/mount/mount-tool.c b/src/mount/mount-tool.c index dd5f62e824c..da3647e7e2f 100644 --- a/src/mount/mount-tool.c +++ b/src/mount/mount-tool.c @@ -30,6 +30,7 @@ #include "escape.h" #include "fd-util.h" #include "fileio.h" +#include "fs-util.h" #include "fstab-util.h" #include "mount-util.h" #include "pager.h" @@ -333,19 +334,15 @@ static int parse_argv(int argc, char *argv[]) { return log_oom(); } else if (arg_transport == BUS_TRANSPORT_LOCAL) { - _cleanup_free_ char *u = NULL, *p = NULL; + _cleanup_free_ char *u = NULL; u = fstab_node_to_udev_node(argv[optind]); if (!u) return log_oom(); - r = path_make_absolute_cwd(u, &p); + r = chase_symlinks(u, NULL, 0, &arg_mount_what); if (r < 0) return log_error_errno(r, "Failed to make path %s absolute: %m", u); - - arg_mount_what = canonicalize_file_name(p); - if (!arg_mount_what) - return log_error_errno(errno, "Failed to canonicalize path %s: %m", p); } else { arg_mount_what = strdup(argv[optind]); if (!arg_mount_what) @@ -361,16 +358,9 @@ static int parse_argv(int argc, char *argv[]) { if (argc > optind+1) { if (arg_transport == BUS_TRANSPORT_LOCAL) { - _cleanup_free_ char *p = NULL; - - r = path_make_absolute_cwd(argv[optind+1], &p); + r = chase_symlinks(argv[optind+1], NULL, CHASE_NONEXISTENT, &arg_mount_where); if (r < 0) return log_error_errno(r, "Failed to make path %s absolute: %m", argv[optind+1]); - - arg_mount_where = canonicalize_file_name(p); - if (!arg_mount_where) - return log_error_errno(errno, "Failed to canonicalize path %s: %m", p); - } else { arg_mount_where = strdup(argv[optind+1]); if (!arg_mount_where) @@ -829,7 +819,7 @@ static int stop_mount( r = unit_name_from_path(where, suffix, &mount_unit); if (r < 0) - return log_error_errno(r, "Failed to make mount unit name from path %s: %m", where); + return log_error_errno(r, "Failed to make %s unit name from path %s: %m", suffix + 1, where); r = sd_bus_message_new_method_call( bus, @@ -853,8 +843,12 @@ static int stop_mount( polkit_agent_open_if_enabled(arg_transport, arg_ask_password); r = sd_bus_call(bus, m, 0, &error, &reply); - if (r < 0) - return log_error_errno(r, "Failed to stop mount unit: %s", bus_error_message(&error, r)); + if (r < 0) { + if (streq(suffix, ".automount") && + sd_bus_error_has_name(&error, "org.freedesktop.systemd1.NoSuchUnit")) + return 0; + return log_error_errno(r, "Failed to stop %s unit: %s", suffix + 1, bus_error_message(&error, r)); + } if (w) { const char *object; @@ -991,26 +985,19 @@ static int action_umount( } for (i = optind; i < argc; i++) { - _cleanup_free_ char *u = NULL, *a = NULL, *p = NULL; + _cleanup_free_ char *u = NULL, *p = NULL; struct stat st; u = fstab_node_to_udev_node(argv[i]); if (!u) return log_oom(); - r = path_make_absolute_cwd(u, &a); + r = chase_symlinks(u, NULL, 0, &p); if (r < 0) { r2 = log_error_errno(r, "Failed to make path %s absolute: %m", argv[i]); continue; } - p = canonicalize_file_name(a); - - if (!p) { - r2 = log_error_errno(errno, "Failed to canonicalize path %s: %m", argv[i]); - continue; - } - if (stat(p, &st) < 0) return log_error_errno(errno, "Can't stat %s (from %s): %m", p, argv[i]); diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c index 83ddc398b88..86d963c4c78 100644 --- a/src/test/test-fs-util.c +++ b/src/test/test-fs-util.c @@ -168,6 +168,26 @@ static void test_chase_symlinks(void) { assert_se(r > 0 && path_equal(result, "/etc")); result = mfree(result); + r = chase_symlinks("/../.././//../../etc", NULL, 0, &result); + assert_se(r > 0); + assert_se(streq(result, "/etc")); + result = mfree(result); + + r = chase_symlinks("/../.././//../../test-chase.fsldajfl", NULL, CHASE_NONEXISTENT, &result); + assert_se(r == 0); + assert_se(streq(result, "/test-chase.fsldajfl")); + result = mfree(result); + + r = chase_symlinks("/../.././//../../etc", "/", CHASE_PREFIX_ROOT, &result); + assert_se(r > 0); + assert_se(streq(result, "/etc")); + result = mfree(result); + + r = chase_symlinks("/../.././//../../test-chase.fsldajfl", "/", CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &result); + assert_se(r == 0); + assert_se(streq(result, "/test-chase.fsldajfl")); + result = mfree(result); + r = chase_symlinks("/etc/machine-id/foo", NULL, 0, &result); assert_se(r == -ENOTDIR); result = mfree(result); @@ -242,6 +262,7 @@ static void test_readlink_and_make_absolute(void) { char name2[] = "test-readlink_and_make_absolute/original"; char name_alias[] = "/tmp/test-readlink_and_make_absolute-alias"; char *r = NULL; + _cleanup_free_ char *pwd = NULL; assert_se(mkdir_safe(tempdir, 0755, getuid(), getgid(), false) >= 0); assert_se(touch(name) >= 0); @@ -252,6 +273,8 @@ static void test_readlink_and_make_absolute(void) { free(r); assert_se(unlink(name_alias) >= 0); + assert_se(pwd = get_current_dir_name()); + assert_se(chdir(tempdir) >= 0); assert_se(symlink(name2, name_alias) >= 0); assert_se(readlink_and_make_absolute(name_alias, &r) >= 0); @@ -259,6 +282,8 @@ static void test_readlink_and_make_absolute(void) { free(r); assert_se(unlink(name_alias) >= 0); + assert_se(chdir(pwd) >= 0); + assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); }