+15
-8
@@ -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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user