mount-tool: various tweaks (#36584)

Split out from #36337
This commit is contained in:
Lennart Poettering
2025-03-03 13:57:27 +01:00
committed by GitHub
2 changed files with 121 additions and 98 deletions
+15 -8
View File
@@ -263,15 +263,22 @@
<varlistentry>
<term><option>--bind-device</option></term>
<listitem><para>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.</para>
<listitem><para>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.</para>
<para>Note that if <option>--discover</option> is used (or only a single argument passed, which implies
<option>--discover</option>, see above), and the file system block device is detected to be removable, this
option is implied.</para>
<para>If <option>--discover</option> is used (or only a single argument passed, which implies
<option>--discover</option>, see above), and the file system block device is detected to be removable,
this option is implied.</para>
<para>Note that mount units by default gain a <varname>Requires=</varname> dependency on
the backing device. This behavior can be controlled via <option>x-systemd.device-bound=</option>
mount option, see <citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details. In particular, <option>x-systemd.device-bound=no</option> takes precedence over this option,
which suppresses device dependencies both in the generated mount units and what's implied by service manager.
</para>
<xi:include href="version-info.xml" xpointer="v232"/></listitem>
</varlistentry>
+106 -90
View File
@@ -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);