diff --git a/man/systemd-mount.xml b/man/systemd-mount.xml index 9723af64d6..effcf82dd6 100644 --- a/man/systemd-mount.xml +++ b/man/systemd-mount.xml @@ -263,15 +263,22 @@ - This option only has an effect in automount mode, - and controls whether the automount unit shall be bound to the backing device's lifetime. If set, the - automount unit will be stopped automatically when the backing device vanishes. By default, the automount unit - stays around, and subsequent accesses will block until backing device is replugged. This option has no effect - in case of non-device mounts, such as network or virtual file system mounts. + Controls whether the generated mount/automount unit shall be bound to the backing device's + lifetime. This setting is especially useful in automount mode. If set, the units will be stopped automatically + when the backing device vanishes. By default, the automount unit stays around, and subsequent accesses + will block until backing device is replugged. This option has no effect in case of non-device mounts, + such as network or virtual file system mounts. - Note that if is used (or only a single argument passed, which implies - , see above), and the file system block device is detected to be removable, this - option is implied. + If is used (or only a single argument passed, which implies + , see above), and the file system block device is detected to be removable, + this option is implied. + + Note that mount units by default gain a Requires= dependency on + the backing device. This behavior can be controlled via + mount option, see systemd.mount5 + for details. In particular, takes precedence over this option, + which suppresses device dependencies both in the generated mount units and what's implied by service manager. + diff --git a/src/mount/mount-tool.c b/src/mount/mount-tool.c index 27fd318fb0..bda1e3a3be 100644 --- a/src/mount/mount-tool.c +++ b/src/mount/mount-tool.c @@ -433,6 +433,10 @@ static int parse_argv(int argc, char *argv[]) { "More than two arguments are not allowed."); if (arg_tmpfs) { + if (arg_discover) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "--discover cannot be used in conjunction with --tmpfs."); + if (argc <= optind+1) { arg_mount_what = strdup("tmpfs"); if (!arg_mount_what) @@ -447,35 +451,44 @@ static int parse_argv(int argc, char *argv[]) { return log_oom(); } - if (!strv_contains(arg_property, "Type=tmpfs") && - strv_extend(&arg_property, "Type=tmpfs") < 0) - return log_oom(); + if (!arg_mount_type) { + arg_mount_type = strdup("tmpfs"); + if (!arg_mount_type) + return log_oom(); + } else if (!streq(arg_mount_type, "tmpfs")) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "--tmpfs requested with incompatible --type=, refusing: %s", + arg_mount_type); } else { if (arg_mount_type && !fstype_is_blockdev_backed(arg_mount_type)) { arg_mount_what = strdup(argv[optind]); if (!arg_mount_what) return log_oom(); - - } else if (arg_transport == BUS_TRANSPORT_LOCAL && arg_canonicalize) { - _cleanup_free_ char *u = NULL; - - u = fstab_node_to_udev_node(argv[optind]); - if (!u) - return log_oom(); - - r = chase(u, /* root= */ NULL, /* flags= */ 0, &arg_mount_what, /* ret_fd= */ NULL); - if (r < 0) - return log_error_errno(r, "Failed to make path %s absolute: %m", u); - } else { - if (!path_is_absolute(argv[optind])) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Path must be absolute when operating remotely or when canonicalization is turned off: %s", - argv[optind]); + _cleanup_free_ char *u = NULL; + const char *p = argv[optind]; - r = path_simplify_alloc(argv[optind], &arg_mount_what); - if (r < 0) - return log_error_errno(r, "Failed to simplify path: %m"); + if (arg_canonicalize) { + u = fstab_node_to_udev_node(p); + if (!u) + return log_oom(); + p = u; + } + + if (arg_transport == BUS_TRANSPORT_LOCAL && arg_canonicalize) { + r = chase(p, /* root= */ NULL, /* flags= */ 0, &arg_mount_what, /* ret_fd= */ NULL); + if (r < 0) + return log_error_errno(r, "Failed to chase path '%s': %m", p); + } else { + if (!path_is_absolute(p)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Path must be absolute when operating remotely or when canonicalization is turned off: %s", + p); + + r = path_simplify_alloc(p, &arg_mount_what); + if (r < 0) + return log_oom(); + } } } @@ -489,6 +502,24 @@ static int parse_argv(int argc, char *argv[]) { if (arg_discover && arg_transport != BUS_TRANSPORT_LOCAL) return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Automatic mount location discovery is only supported locally."); + + _cleanup_free_ char *dev_bound = NULL; + r = fstab_filter_options(arg_mount_options, "x-systemd.device-bound\0", + /* ret_namefound = */ NULL, &dev_bound, /* ret_values = */ NULL, /* ret_filtered = */ NULL); + if (r < 0) + return log_error_errno(r, "Failed to parse mount options for x-systemd.device-bound=: %m"); + if (r > 0 && !isempty(dev_bound)) { + /* If x-systemd.device-bound=no is explicitly specified, never bind automount unit + * to device either. */ + r = parse_boolean(dev_bound); + if (r < 0) + return log_error_errno(r, "Invalid x-systemd.device-bound= option: %s", dev_bound); + if (r == 0) { + log_full(arg_bind_device > 0 ? LOG_NOTICE : LOG_DEBUG, + "x-systemd.device-bound=no set, automatically disabling --bind-device."); + arg_bind_device = false; + } + } } return 1; @@ -497,13 +528,16 @@ static int parse_argv(int argc, char *argv[]) { static int transient_unit_set_properties(sd_bus_message *m, UnitType t, char **properties) { int r; + assert(m); + assert(IN_SET(t, UNIT_MOUNT, UNIT_AUTOMOUNT)); + if (!isempty(arg_description)) { r = sd_bus_message_append(m, "(sv)", "Description", "s", arg_description); if (r < 0) return r; } - if (arg_bind_device && is_device_path(arg_mount_what)) { + if (arg_bind_device > 0 && is_device_path(arg_mount_what)) { _cleanup_free_ char *device_unit = NULL; r = unit_name_from_path(arg_mount_what, ".device", &device_unit); @@ -629,16 +663,15 @@ static int transient_automount_set_properties(sd_bus_message *m) { return 0; } -static int start_transient_mount( - sd_bus *bus, - char **argv) { - +static int start_transient_mount(sd_bus *bus) { _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; _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL; _cleanup_free_ char *mount_unit = NULL; int r; + assert(bus); + if (!arg_no_block) { r = bus_wait_for_jobs_new(bus, &w); if (r < 0) @@ -671,7 +704,7 @@ static int start_transient_mount( if (r < 0) return bus_log_create_error(r); - /* Auxiliary units */ + /* No auxiliary units */ r = sd_bus_message_append(m, "a(sa(sv))", 0); if (r < 0) return bus_log_create_error(r); @@ -702,16 +735,15 @@ static int start_transient_mount( return 0; } -static int start_transient_automount( - sd_bus *bus, - char **argv) { - +static int start_transient_automount(sd_bus *bus) { _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; _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL; _cleanup_free_ char *automount_unit = NULL, *mount_unit = NULL; int r; + assert(bus); + if (!arg_no_block) { r = bus_wait_for_jobs_new(bus, &w); if (r < 0) @@ -807,7 +839,7 @@ static int start_transient_automount( return 0; } -static int find_mount_points(const char *what, char ***list) { +static int find_mount_points_by_source(const char *what, char ***ret) { _cleanup_(mnt_free_tablep) struct libmnt_table *table = NULL; _cleanup_(mnt_free_iterp) struct libmnt_iter *iter = NULL; _cleanup_strv_free_ char **l = NULL; @@ -815,10 +847,10 @@ static int find_mount_points(const char *what, char ***list) { int r; assert(what); - assert(list); + assert(ret); - /* Returns all mount points obtained from /proc/self/mountinfo in *list, - * and the number of mount points as return value. */ + /* Obtain all mount points with source being "what" from /proc/self/mountinfo, return value shows + * the total number of them. */ r = libmount_parse_mountinfo(/* source = */ NULL, &table, &iter); if (r < 0) @@ -842,20 +874,12 @@ static int find_mount_points(const char *what, char ***list) { if (!path_equal(source, what)) continue; - /* one extra slot is needed for the terminating NULL */ - if (!GREEDY_REALLOC0(l, n + 2)) + r = strv_extend_with_size(&l, &n, target); + if (r < 0) return log_oom(); - - l[n] = strdup(target); - if (!l[n]) - return log_oom(); - n++; } - if (!GREEDY_REALLOC0(l, n + 1)) - return log_oom(); - - *list = TAKE_PTR(l); + *ret = TAKE_PTR(l); return n; } @@ -905,17 +929,17 @@ static int find_loop_device(const char *backing_file, sd_device **ret) { return -ENXIO; } -static int stop_mount( - sd_bus *bus, - const char *where, - const char *suffix) { - +static int stop_mount(sd_bus *bus, const char *where, const char *suffix) { _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; _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL; _cleanup_free_ char *mount_unit = NULL; int r; + assert(bus); + assert(where); + assert(suffix); + if (!arg_no_block) { r = bus_wait_for_jobs_new(bus, &w); if (r < 0) @@ -924,7 +948,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 %s unit name from path %s: %m", suffix + 1, where); + return log_error_errno(r, "Failed to make %s unit name from path '%s': %m", suffix + 1, where); r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StopUnit"); if (r < 0) @@ -965,15 +989,15 @@ static int stop_mount( return 0; } -static int stop_mounts( - sd_bus *bus, - const char *where) { - +static int stop_mounts(sd_bus *bus, const char *where) { int r; + assert(bus); + assert(where); + if (path_equal(where, "/")) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Refusing to operate on root directory: %s", where); + "Refusing to unmount root directory."); if (!path_is_normalized(where)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), @@ -1005,15 +1029,12 @@ static int umount_by_device(sd_bus *bus, sd_device *dev) { if (r < 0) return r; - r = find_mount_points(v, &list); + r = find_mount_points_by_source(v, &list); if (r < 0) return r; - STRV_FOREACH(l, list) { - r = stop_mounts(bus, *l); - if (r < 0) - ret = r; - } + STRV_FOREACH(l, list) + RET_GATHER(ret, stop_mounts(bus, *l)); return ret; } @@ -1054,11 +1075,7 @@ static int umount_loop(sd_bus *bus, const char *backing_file) { return umount_by_device(bus, dev); } -static int action_umount( - sd_bus *bus, - int argc, - char **argv) { - +static int action_umount(sd_bus *bus, int argc, char **argv) { int r, ret = 0; assert(bus); @@ -1088,13 +1105,13 @@ static int action_umount( _cleanup_close_ int fd = -EBADF; r = chase(u, /* root= */ NULL, 0, &p, &fd); if (r < 0) { - RET_GATHER(ret, log_error_errno(r, "Failed to make path %s absolute: %m", u)); + RET_GATHER(ret, log_error_errno(r, "Failed to chase path '%s': %m", u)); continue; } struct stat st; if (fstat(fd, &st) < 0) - return log_error_errno(errno, "Can't stat %s (from %s): %m", p, argv[i]); + return log_error_errno(errno, "Can't stat '%s' (from %s): %m", p, argv[i]); r = is_mount_point_at(fd, /* filename= */ NULL, /* flags= */ 0); fd = safe_close(fd); /* before continuing make sure the dir is not keeping anything busy */ @@ -1107,14 +1124,17 @@ static int action_umount( if (r < 0) log_warning_errno(r, "Failed to determine if '%s' is a mount point, ignoring: %m", u); - if (S_ISBLK(st.st_mode)) - RET_GATHER(ret, umount_by_device_node(bus, p)); + if (S_ISDIR(st.st_mode)) + r = stop_mounts(bus, p); + else if (S_ISBLK(st.st_mode)) + r = umount_by_device_node(bus, p); else if (S_ISREG(st.st_mode)) - RET_GATHER(ret, umount_loop(bus, p)); - else if (S_ISDIR(st.st_mode)) - RET_GATHER(ret, stop_mounts(bus, p)); + r = umount_loop(bus, p); else - RET_GATHER(ret, log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid file type: %s (from %s)", p, argv[i])); + r = log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Unknown file type for unmounting: %s (from %s)", + p, argv[i]); + RET_GATHER(ret, r); } } @@ -1231,7 +1251,7 @@ static int acquire_mount_where_for_loop_dev(sd_device *dev) { if (r < 0) return r; - r = find_mount_points(node, &list); + r = find_mount_points_by_source(node, &list); if (r < 0) return r; if (r == 0) @@ -1282,6 +1302,8 @@ static int acquire_description(sd_device *d) { static int acquire_removable(sd_device *d) { const char *v; + assert(d); + /* Shortcut this if there's no reason to check it */ if (arg_action != ACTION_DEFAULT && arg_timeout_idle_set && arg_bind_device >= 0) return 0; @@ -1325,9 +1347,6 @@ static int discover_loop_backing_file(void) { int r; r = find_loop_device(arg_mount_what, &d); - if (r < 0 && r != -ENXIO) - return log_error_errno(errno, "Can't get loop device for %s: %m", arg_mount_what); - if (r == -ENXIO) { _cleanup_free_ char *escaped = NULL, *bn = NULL; @@ -1352,7 +1371,9 @@ static int discover_loop_backing_file(void) { log_debug("Discovered where=%s", arg_mount_where); return 0; - } + + } else if (r < 0) + return log_error_errno(r, "Can't get loop device for %s: %m", arg_mount_what); r = acquire_mount_type(d); if (r < 0) @@ -1387,8 +1408,7 @@ static int discover_device(void) { if (!S_ISBLK(st.st_mode)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Invalid file type: %s", - arg_mount_what); + "Unsupported mount source type for --discover: %s", arg_mount_what); r = sd_device_new_from_stat_rdev(&d, &st); if (r < 0) @@ -1608,18 +1628,14 @@ static int run(int argc, char* argv[]) { case ACTION_MOUNT: case ACTION_DEFAULT: - r = start_transient_mount(bus, argv + optind); - break; + return start_transient_mount(bus); case ACTION_AUTOMOUNT: - r = start_transient_automount(bus, argv + optind); - break; + return start_transient_automount(bus); default: assert_not_reached(); } - - return r; } DEFINE_MAIN_FUNCTION(run);