From: Yu Watanabe Date: Mon, 26 Jun 2017 20:07:07 +0000 (+0900) Subject: systemd-mount: support device names and multiple arguments for umount (#6096) X-Git-Tag: v234~89 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9017f5d88d5061487de53f00a1a8c0a83e41e760;p=platform%2Fupstream%2Fsystemd.git systemd-mount: support device names and multiple arguments for umount (#6096) This makes systemd-umount (or systemd-mount -u) supports multiple arguments which can be path, device, or fstab style node name, like `systemd-umount /path/to/umount /dev/sda1 UUID=xxxxxx-xxxx LABEL=xxxxx`. C.f. https://github.com/systemd/systemd/pull/5235#issuecomment-277731314. --- diff --git a/man/systemd-mount.xml b/man/systemd-mount.xml index 71a4ed5..68654f4 100644 --- a/man/systemd-mount.xml +++ b/man/systemd-mount.xml @@ -62,9 +62,10 @@ - systemd-umount + systemd-mount OPTIONS - WHERE + + WHAT|WHERE @@ -253,7 +254,11 @@ Stop the mount and automount units corresponding to the specified mount points - WHERE. + WHERE or the devices WHAT. + systemd-mount with this option or systemd-umount can take multiple arguments + which can be path, device, or /etc/fstab style node name, like + systemd-mount --umount /path/to/umount /dev/sda1 UUID=xxxxxx-xxxx LABEL=xxxxx. + diff --git a/src/mount/mount-tool.c b/src/mount/mount-tool.c index b709166..ea5bcd1 100644 --- a/src/mount/mount-tool.c +++ b/src/mount/mount-tool.c @@ -26,6 +26,7 @@ #include "bus-unit-util.h" #include "bus-util.h" #include "escape.h" +#include "fd-util.h" #include "fstab-util.h" #include "pager.h" #include "parse-util.h" @@ -77,7 +78,9 @@ static void polkit_agent_open_if_enabled(void) { } static void help(void) { - printf("%s [OPTIONS...] WHAT [WHERE]\n\n" + printf("systemd-mount [OPTIONS...] WHAT [WHERE]\n" + "systemd-mount [OPTIONS...] --list\n" + "%s [OPTIONS...] %sWHAT|WHERE...\n\n" "Establish a mount or auto-mount point transiently.\n\n" " -h --help Show this help\n" " --version Show package version\n" @@ -100,8 +103,9 @@ static void help(void) { " Set automount unit property\n" " --bind-device Bind automount unit to device\n" " --list List mountable block devices\n" - " -u --umount Unmount mount points\n" - , program_invocation_short_name); + " -u --umount Unmount mount points\n", + program_invocation_short_name, + streq(program_invocation_short_name, "systemd-umount") ? "" : "--umount "); } static int parse_argv(int argc, char *argv[]) { @@ -297,6 +301,16 @@ static int parse_argv(int argc, char *argv[]) { log_error("Listing devices only supported locally."); return -EOPNOTSUPP; } + } else if (arg_action == ACTION_UMOUNT) { + if (optind >= argc) { + log_error("At least one argument required."); + return -EINVAL; + } + + if (arg_transport != BUS_TRANSPORT_LOCAL) { + log_error("Unmounting devices only supported locally."); + return -EOPNOTSUPP; + } } else { if (optind >= argc) { log_error("At least one argument required."); @@ -621,8 +635,9 @@ static int start_transient_automount( static int stop_mount( sd_bus *bus, - char **argv, - const char *suffix) { + const char *where, + const char *suffix, + bool ignore_enoent) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; @@ -636,9 +651,9 @@ static int stop_mount( return log_error_errno(r, "Could not watch jobs: %m"); } - r = unit_name_from_path(arg_mount_where, suffix, &mount_unit); + r = unit_name_from_path(where, suffix, &mount_unit); if (r < 0) - return log_error_errno(r, "Failed to make mount unit name: %m"); + return log_error_errno(r, "Failed to make mount unit name from path %s: %m", where); r = sd_bus_message_new_method_call( bus, @@ -662,8 +677,11 @@ static int stop_mount( polkit_agent_open_if_enabled(); 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 (r != -ENOENT || !ignore_enoent) + return log_error_errno(r, "Failed to stop mount unit: %s", bus_error_message(&error, r)); + return r; + } if (w) { const char *object; @@ -680,28 +698,195 @@ static int stop_mount( if (!arg_quiet) log_info("Stopped unit %s%s%s for mount point: %s%s%s", ansi_highlight(), mount_unit, ansi_normal(), - ansi_highlight(), arg_mount_where, ansi_normal()); + ansi_highlight(), where, ansi_normal()); return 0; } static int stop_mounts( sd_bus *bus, - char **argv) { + const char *where, + bool ignore_enoent) { int r; - r = stop_mount(bus, argv + optind, ".mount"); + if (path_equal(where, "/")) { + log_error("Refusing to operate on root directory: %s", where); + return -EINVAL; + } + + if (!path_is_safe(where)) { + log_error("Path contains unsafe components: %s", where); + return -EINVAL; + } + + r = stop_mount(bus, where, ".mount", ignore_enoent); if (r < 0) return r; - r = stop_mount(bus, argv + optind, ".automount"); + r = stop_mount(bus, where, ".automount", ignore_enoent); if (r < 0) return r; return 0; } +static int umount_by_mountinfo(sd_bus *bus, const char *what) { + _cleanup_fclose_ FILE *proc_self_mountinfo = NULL; + int r, r2 = 0; + + proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"); + if (!proc_self_mountinfo) + return -errno; + + for (;;) { + _cleanup_free_ char *path = NULL, *where = NULL, *dev = NULL; + int k; + + k = fscanf(proc_self_mountinfo, + "%*s " /* (1) mount id */ + "%*s " /* (2) parent id */ + "%*s " /* (3) major:minor */ + "%*s " /* (4) root */ + "%ms " /* (5) mount point */ + "%*s" /* (6) mount options */ + "%*[^-]" /* (7) optional fields */ + "- " /* (8) separator */ + "%*s " /* (9) file system type */ + "%ms" /* (10) mount source */ + "%*s" /* (11) mount options 2 */ + "%*[^\n]", /* some rubbish at the end */ + &path, &dev); + if (k != 2) { + if (k == EOF) + break; + + continue; + } + + if (!streq(what, dev)) + continue; + + r = cunescape(path, UNESCAPE_RELAX, &where); + if (r < 0) { + if (r2 >= 0) + r2 = r; + continue; + } + + r = stop_mounts(bus, where, false); + if (r < 0) { + if (r2 >= 0) + r2 = r; + continue; + } + } + + return r2; +} + +static int umount_by_device(sd_bus *bus, const char *what) { + _cleanup_udev_device_unref_ struct udev_device *d = NULL; + _cleanup_udev_unref_ struct udev *udev = NULL; + _cleanup_free_ char *where = NULL; + struct stat st; + const char *v; + int r = 0, r2; + + assert(what); + + if (stat(what, &st) < 0) + return log_error_errno(errno, "Can't stat %s: %m", what); + + if (!S_ISBLK(st.st_mode)) { + log_error("Path %s is not a block device, don't know what to do.", what); + return -ENOTBLK; + } + + udev = udev_new(); + if (!udev) + return log_oom(); + + d = udev_device_new_from_devnum(udev, 'b', st.st_rdev); + if (!d) + return log_oom(); + + v = udev_device_get_property_value(d, "ID_FS_USAGE"); + if (!streq_ptr(v, "filesystem")) { + log_error("%s does not contain a known file system.", what); + return -EINVAL; + } + + v = udev_device_get_property_value(d, "SYSTEMD_MOUNT_WHERE"); + if (!isempty(v)) { + where = strdup(v); + if (!where) + return log_oom(); + r = stop_mounts(bus, where, false); + } + + v = udev_device_get_devnode(d); + if (!isempty(v)) { + r2 = umount_by_mountinfo(bus, v); + if (r2 < 0) + return r2; + } + + return r; +} + +static int action_umount( + sd_bus *bus, + int argc, + char **argv) { + + int i, r, r2 = 0; + + for (i = optind; i < argc; i++) { + _cleanup_free_ char *what = NULL, *where = NULL, *u = NULL; + bool ignore_enoent; + + u = fstab_node_to_udev_node(argv[i]); + if (!u) + return log_oom(); + if (streq(u, argv[i])) { + r = path_make_absolute_cwd(argv[i], &where); + if (r < 0) { + log_error_errno(r, "Failed to make path absolute: %m"); + if (r2 >= 0) + r2 = r; + } else { + path_kill_slashes(where); + ignore_enoent = is_device_path(where); + r = stop_mounts(bus, where, ignore_enoent); + if (r >= 0) + continue; + if ((r != -ENOENT || !ignore_enoent) && r2 >= 0) + r2 = r; + } + } + + r = path_make_absolute_cwd(u, &what); + if (r < 0) { + log_error_errno(r, "Failed to make path absolute: %m"); + if (r2 >= 0) + r2 = r; + continue; + } + + path_kill_slashes(what); + + if (!is_device_path(what)) + continue; + + r = umount_by_device(bus, what); + if (r < 0 && r2 >= 0) + r2 = r; + } + + return r2; +} + static int acquire_mount_type(struct udev_device *d) { const char *v; @@ -907,7 +1092,7 @@ static int discover_device(void) { v = udev_device_get_property_value(d, "ID_FS_USAGE"); if (!streq_ptr(v, "filesystem")) { - log_error("%s does not contain a file system.", arg_mount_what); + log_error("%s does not contain a known file system.", arg_mount_what); return -EINVAL; } @@ -1130,6 +1315,17 @@ int main(int argc, char* argv[]) { goto finish; } + r = bus_connect_transport_systemd(arg_transport, arg_host, arg_user, &bus); + if (r < 0) { + log_error_errno(r, "Failed to create bus connection: %m"); + goto finish; + } + + if (arg_action == ACTION_UMOUNT) { + r = action_umount(bus, argc, argv); + goto finish; + } + r = discover_device(); if (r < 0) goto finish; @@ -1148,7 +1344,7 @@ int main(int argc, char* argv[]) { } if (!path_is_safe(arg_mount_where)) { - log_error("Path is contains unsafe components."); + log_error("Path contains unsafe components."); r = -EINVAL; goto finish; } @@ -1171,12 +1367,6 @@ int main(int argc, char* argv[]) { } } - r = bus_connect_transport_systemd(arg_transport, arg_host, arg_user, &bus); - if (r < 0) { - log_error_errno(r, "Failed to create bus connection: %m"); - goto finish; - } - switch (arg_action) { case ACTION_MOUNT: @@ -1188,10 +1378,6 @@ int main(int argc, char* argv[]) { r = start_transient_automount(bus, argv + optind); break; - case ACTION_UMOUNT: - r = stop_mounts(bus, argv + optind); - break; - default: assert_not_reached("Unexpected action."); }