This file is part of systemd.
Copyright 2016 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <getopt.h>
#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"
#include "stat-util.h"
#include "strv.h"
#include "udev-util.h"
+#include "unit-def.h"
#include "unit-name.h"
+#include "user-util.h"
#include "terminal-util.h"
enum {
static bool arg_timeout_idle_set = false;
static char **arg_automount_property = NULL;
static int arg_bind_device = -1;
+static uid_t arg_uid = UID_INVALID;
+static gid_t arg_gid = GID_INVALID;
static bool arg_fsck = true;
static bool arg_aggressive_gc = false;
" --discover Discover mount device metadata\n"
" -t --type=TYPE File system type\n"
" -o --options=OPTIONS Mount options\n"
+ " --owner=USER Add uid= and gid= options for USER\n"
" --fsck=no Don't run file system check before mount\n"
" --description=TEXT Description for unit\n"
" -p --property=NAME=VALUE Set mount unit property\n"
ARG_DISCOVER,
ARG_MOUNT_TYPE,
ARG_MOUNT_OPTIONS,
+ ARG_OWNER,
ARG_FSCK,
ARG_DESCRIPTION,
ARG_TIMEOUT_IDLE,
{ "discover", no_argument, NULL, ARG_DISCOVER },
{ "type", required_argument, NULL, 't' },
{ "options", required_argument, NULL, 'o' },
+ { "owner", required_argument, NULL, ARG_OWNER },
{ "fsck", required_argument, NULL, ARG_FSCK },
{ "description", required_argument, NULL, ARG_DESCRIPTION },
{ "property", required_argument, NULL, 'p' },
return log_oom();
break;
+ case ARG_OWNER: {
+ const char *user = optarg;
+
+ r = get_user_creds(&user, &arg_uid, &arg_gid, NULL, NULL);
+ if (r < 0)
+ return log_error_errno(r,
+ r == -EBADMSG ? "UID or GID of user %s are invalid."
+ : "Cannot use \"%s\" as owner: %m",
+ optarg);
+ break;
+ }
+
case ARG_FSCK:
r = parse_boolean(optarg);
if (r < 0)
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)
return log_oom();
- path_kill_slashes(arg_mount_what);
+ path_simplify(arg_mount_what, false);
if (!path_is_absolute(arg_mount_what)) {
log_error("Only absolute path is supported: %s", arg_mount_what);
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)
return log_oom();
- path_kill_slashes(arg_mount_where);
+ path_simplify(arg_mount_where, false);
if (!path_is_absolute(arg_mount_where)) {
log_error("Only absolute path is supported: %s", arg_mount_where);
return 1;
}
-static int transient_unit_set_properties(sd_bus_message *m, char **properties) {
+static int transient_unit_set_properties(sd_bus_message *m, UnitType t, char **properties) {
int r;
if (!isempty(arg_description)) {
return r;
}
- r = bus_append_unit_property_assignment_many(m, properties);
+ r = bus_append_unit_property_assignment_many(m, t, properties);
if (r < 0)
return r;
}
static int transient_mount_set_properties(sd_bus_message *m) {
+ _cleanup_free_ char *options = NULL;
int r;
assert(m);
- r = transient_unit_set_properties(m, arg_property);
+ r = transient_unit_set_properties(m, UNIT_MOUNT, arg_property);
if (r < 0)
return r;
return r;
}
- if (arg_mount_options) {
- r = sd_bus_message_append(m, "(sv)", "Options", "s", arg_mount_options);
+ /* Prepend uid=…,gid=… if arg_uid is set */
+ if (arg_uid != UID_INVALID) {
+ r = asprintf(&options,
+ "uid=" UID_FMT ",gid=" GID_FMT "%s%s",
+ arg_uid, arg_gid,
+ arg_mount_options ? "," : "", arg_mount_options);
if (r < 0)
- return r;
+ return -ENOMEM;
}
+ if (options || arg_mount_options) {
+ log_debug("Using mount options: %s", options ?: arg_mount_options);
+
+ r = sd_bus_message_append(m, "(sv)", "Options", "s", options ?: arg_mount_options);
+ if (r < 0)
+ return r;
+ } else
+ log_debug("Not using any mount options");
+
if (arg_fsck) {
_cleanup_free_ char *fsck = NULL;
assert(m);
- r = transient_unit_set_properties(m, arg_automount_property);
+ r = transient_unit_set_properties(m, UNIT_AUTOMOUNT, arg_automount_property);
if (r < 0)
return r;
if (!GREEDY_REALLOC(l, bufsize, n + 2))
return log_oom();
- l[n++] = where;
- where = NULL;
+ l[n++] = TAKE_PTR(where);
}
if (!GREEDY_REALLOC(l, bufsize, n + 1))
return log_oom();
l[n] = NULL;
- *list = l;
- l = NULL; /* avoid freeing */
+ *list = TAKE_PTR(l);
return n;
}
if (!l)
return -ENXIO;
- *loop_dev = l;
- l = NULL; /* avoid freeing */
+ *loop_dev = TAKE_PTR(l);
return 0;
}
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,
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;
}
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_(udev_device_unrefp) struct udev_device *d = NULL;
+ _cleanup_(udev_unrefp) struct udev *udev = NULL;
_cleanup_strv_free_ char **list = NULL;
struct stat st;
const char *v;
if (!p)
return log_oom();
- path_kill_slashes(p);
+ path_simplify(p, false);
r = stop_mounts(bus, p);
if (r < 0)
}
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]);
}
static int discover_loop_backing_file(void) {
- _cleanup_udev_device_unref_ struct udev_device *d = NULL;
- _cleanup_udev_unref_ struct udev *udev = NULL;
+ _cleanup_(udev_device_unrefp) struct udev_device *d = NULL;
+ _cleanup_(udev_unrefp) struct udev *udev = NULL;
_cleanup_free_ char *loop_dev = NULL;
struct stat st;
const char *v;
}
static int discover_device(void) {
- _cleanup_udev_device_unref_ struct udev_device *d = NULL;
- _cleanup_udev_unref_ struct udev *udev = NULL;
+ _cleanup_(udev_device_unrefp) struct udev_device *d = NULL;
+ _cleanup_(udev_unrefp) struct udev *udev = NULL;
struct stat st;
const char *v;
int r;
[COLUMN_UUID] = "UUID"
};
- _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
- _cleanup_udev_unref_ struct udev *udev = NULL;
+ _cleanup_(udev_enumerate_unrefp) struct udev_enumerate *e = NULL;
+ _cleanup_(udev_unrefp) struct udev *udev = NULL;
struct udev_list_entry *item = NULL, *first = NULL;
size_t n_allocated = 0, n = 0, i;
size_t column_width[_COLUMN_MAX];
first = udev_enumerate_get_list_entry(e);
udev_list_entry_foreach(item, first) {
- _cleanup_udev_device_unref_ struct udev_device *d;
+ _cleanup_(udev_device_unrefp) struct udev_device *d;
struct item *j;
d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
qsort_safe(items, n, sizeof(struct item), compare_item);
- pager_open(arg_no_pager, false);
+ (void) pager_open(arg_no_pager, false);
fputs(ansi_underline(), stdout);
for (c = 0; c < _COLUMN_MAX; c++) {
}
int main(int argc, char* argv[]) {
- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ sd_bus *bus = NULL;
int r;
log_parse_environment();
}
}
+ /* The kernel (properly) refuses mounting file systems with unknown uid=,gid= options,
+ * but not for all filesystem types. Let's try to catch the cases where the option
+ * would be used if the file system does not support it. It is also possible to
+ * autodetect the file system, but that's only possible with disk-based file systems
+ * which incidentally seem to be implemented more carefully and reject unknown options,
+ * so it's probably OK that we do the check only when the type is specified.
+ */
+ if (arg_mount_type &&
+ !streq(arg_mount_type, "auto") &&
+ arg_uid != UID_INVALID &&
+ !fstype_can_uid_gid(arg_mount_type)) {
+ log_error("File system type %s is not known to support uid=/gid=, refusing.",
+ arg_mount_type);
+ r = -EOPNOTSUPP;
+ goto finish;
+ }
+
switch (arg_action) {
case ACTION_MOUNT:
}
finish:
+ /* make sure we terminate the bus connection first, and then close the
+ * pager, see issue #3543 for the details. */
+ bus = sd_bus_flush_close_unref(bus);
pager_close();
free(arg_mount_what);