/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2016 Lennart Poettering
-***/
#include <getopt.h>
-#include "libudev.h"
#include "sd-bus.h"
+#include "sd-device.h"
#include "bus-error.h"
#include "bus-unit-util.h"
#include "bus-util.h"
+#include "bus-wait-for-jobs.h"
+#include "device-util.h"
#include "dirent-util.h"
#include "escape.h"
#include "fd-util.h"
#include "fileio.h"
+#include "format-util.h"
#include "fs-util.h"
#include "fstab-util.h"
+#include "main-func.h"
#include "mount-util.h"
+#include "mountpoint-util.h"
#include "pager.h"
#include "parse-util.h"
#include "path-util.h"
+#include "pretty-print.h"
+#include "sort-util.h"
#include "spawn-polkit-agent.h"
#include "stat-util.h"
#include "strv.h"
-#include "udev-util.h"
+#include "terminal-util.h"
#include "unit-def.h"
#include "unit-name.h"
#include "user-util.h"
-#include "terminal-util.h"
enum {
ACTION_DEFAULT,
} arg_action = ACTION_DEFAULT;
static bool arg_no_block = false;
-static bool arg_no_pager = false;
+static PagerFlags arg_pager_flags = 0;
static bool arg_ask_password = true;
static bool arg_quiet = false;
static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
static bool arg_fsck = true;
static bool arg_aggressive_gc = false;
-static void help(void) {
+STATIC_DESTRUCTOR_REGISTER(arg_mount_what, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_mount_where, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_mount_type, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_mount_options, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_description, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_property, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_automount_property, strv_freep);
+
+static int help(void) {
+ _cleanup_free_ char *link = NULL;
+ int r;
+
+ r = terminal_urlify_man("systemd-mount", "1", &link);
+ if (r < 0)
+ return log_oom();
+
printf("systemd-mount [OPTIONS...] WHAT [WHERE]\n"
"systemd-mount [OPTIONS...] --list\n"
"%s [OPTIONS...] %sWHAT|WHERE...\n\n"
" --bind-device Bind automount unit to device\n"
" --list List mountable block devices\n"
" -u --umount Unmount mount points\n"
- " -G --collect Unload unit after it stopped, even when failed\n",
- program_invocation_short_name,
- streq(program_invocation_short_name, "systemd-umount") ? "" : "--umount ");
+ " -G --collect Unload unit after it stopped, even when failed\n"
+ "\nSee the %s for details.\n"
+ , program_invocation_short_name
+ , streq(program_invocation_short_name, "systemd-umount") ? "" : "--umount "
+ , link
+ );
+
+ return 0;
}
static int parse_argv(int argc, char *argv[]) {
switch (c) {
case 'h':
- help();
- return 0;
+ return help();
case ARG_VERSION:
return version();
break;
case ARG_NO_PAGER:
- arg_no_pager = true;
+ arg_pager_flags |= PAGER_DISABLE;
break;
case ARG_NO_ASK_PASSWORD:
case ARG_OWNER: {
const char *user = optarg;
- r = get_user_creds(&user, &arg_uid, &arg_gid, NULL, NULL);
+ r = get_user_creds(&user, &arg_uid, &arg_gid, NULL, NULL, 0);
if (r < 0)
return log_error_errno(r,
r == -EBADMSG ? "UID or GID of user %s are invalid."
assert_not_reached("Unhandled option");
}
- if (arg_user && arg_transport != BUS_TRANSPORT_LOCAL) {
- log_error("Execution in user context is not supported on non-local systems.");
- return -EINVAL;
- }
+ if (arg_user && arg_transport != BUS_TRANSPORT_LOCAL)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Execution in user context is not supported on non-local systems.");
if (arg_action == ACTION_LIST) {
- if (optind < argc) {
- log_error("Too many arguments.");
- return -EINVAL;
- }
+ if (optind < argc)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Too many arguments.");
- if (arg_transport != BUS_TRANSPORT_LOCAL) {
- log_error("Listing devices only supported locally.");
- return -EOPNOTSUPP;
- }
+ if (arg_transport != BUS_TRANSPORT_LOCAL)
+ return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+ "Listing devices only supported locally.");
} else if (arg_action == ACTION_UMOUNT) {
- if (optind >= argc) {
- log_error("At least one argument required.");
- return -EINVAL;
- }
+ if (optind >= argc)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "At least one argument required.");
if (arg_transport != BUS_TRANSPORT_LOCAL) {
int i;
for (i = optind; i < argc; i++)
- if (!path_is_absolute(argv[i]) ) {
- log_error("Only absolute path is supported: %s", argv[i]);
- return -EINVAL;
- }
+ if (!path_is_absolute(argv[i]) )
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Only absolute path is supported: %s", argv[i]);
}
} else {
- if (optind >= argc) {
- log_error("At least one argument required.");
- return -EINVAL;
- }
+ if (optind >= argc)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "At least one argument required.");
- if (argc > optind+2) {
- log_error("At most two arguments required.");
- return -EINVAL;
- }
+ if (argc > optind+2)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "At most two arguments required.");
if (arg_mount_type && (fstype_is_api_vfs(arg_mount_type) || fstype_is_network(arg_mount_type))) {
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);
- return -EINVAL;
- }
+ if (!path_is_absolute(arg_mount_what))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Only absolute path is supported: %s", arg_mount_what);
}
if (argc > 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 -EINVAL;
- }
+ if (!path_is_absolute(arg_mount_where))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Only absolute path is supported: %s", arg_mount_where);
}
} else
arg_discover = true;
- if (arg_discover && arg_transport != BUS_TRANSPORT_LOCAL) {
- log_error("Automatic mount location discovery is only supported locally.");
- return -EOPNOTSUPP;
- }
+ if (arg_discover && arg_transport != BUS_TRANSPORT_LOCAL)
+ return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+ "Automatic mount location discovery is only supported locally.");
}
return 1;
r = asprintf(&options,
"uid=" UID_FMT ",gid=" GID_FMT "%s%s",
arg_uid, arg_gid,
- arg_mount_options ? "," : "", arg_mount_options);
+ arg_mount_options ? "," : "", strempty(arg_mount_options));
if (r < 0)
return -ENOMEM;
}
int r;
- if (path_equal(where, "/")) {
- log_error("Refusing to operate on root directory: %s", where);
- return -EINVAL;
- }
+ if (path_equal(where, "/"))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Refusing to operate on root directory: %s", where);
- if (!path_is_normalized(where)) {
- log_error("Path contains non-normalized components: %s", where);
- return -EINVAL;
- }
+ if (!path_is_normalized(where))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Path contains non-normalized components: %s", where);
r = stop_mount(bus, where, ".mount");
if (r < 0)
}
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_(sd_device_unrefp) sd_device *d = NULL;
_cleanup_strv_free_ char **list = NULL;
struct stat st;
const char *v;
return -ENOTBLK;
}
- udev = udev_new();
- if (!udev)
- return log_oom();
+ r = sd_device_new_from_devnum(&d, 'b', st.st_rdev);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get device from device number: %m");
- d = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
- if (!d)
- return log_oom();
+ r = sd_device_get_property_value(d, "ID_FS_USAGE", &v);
+ if (r < 0)
+ return log_device_error_errno(d, r, "Failed to get device property: %m");
- 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);
+ if (!streq(v, "filesystem")) {
+ log_device_error(d, "%s does not contain a known file system.", what);
return -EINVAL;
}
- v = udev_device_get_property_value(d, "SYSTEMD_MOUNT_WHERE");
- if (!isempty(v))
+ if (sd_device_get_property_value(d, "SYSTEMD_MOUNT_WHERE", &v) >= 0)
r2 = stop_mounts(bus, v);
r = find_mount_points(what, &list);
if (!p)
return log_oom();
- path_kill_slashes(p);
+ path_simplify(p, false);
r = stop_mounts(bus, p);
if (r < 0)
return r2;
}
-static int acquire_mount_type(struct udev_device *d) {
+static int acquire_mount_type(sd_device *d) {
const char *v;
assert(d);
if (arg_mount_type)
return 0;
- v = udev_device_get_property_value(d, "ID_FS_TYPE");
- if (isempty(v))
+ if (sd_device_get_property_value(d, "ID_FS_TYPE", &v) < 0)
return 0;
arg_mount_type = strdup(v);
return 1;
}
-static int acquire_mount_options(struct udev_device *d) {
+static int acquire_mount_options(sd_device *d) {
const char *v;
+ assert(d);
+
if (arg_mount_options)
return 0;
- v = udev_device_get_property_value(d, "SYSTEMD_MOUNT_OPTIONS");
- if (isempty(v))
+ if (sd_device_get_property_value(d, "SYSTEMD_MOUNT_OPTIONS", &v) < 0)
return 0;
arg_mount_options = strdup(v);
return 1;
}
-static const char *get_model(struct udev_device *d) {
+static const char *get_model(sd_device *d) {
const char *model;
assert(d);
- model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
- if (model)
+ if (sd_device_get_property_value(d, "ID_MODEL_FROM_DATABASE", &model) >= 0)
return model;
- return udev_device_get_property_value(d, "ID_MODEL");
+ if (sd_device_get_property_value(d, "ID_MODEL", &model) >= 0)
+ return model;
+
+ return NULL;
}
-static const char* get_label(struct udev_device *d) {
+static const char* get_label(sd_device *d) {
const char *label;
assert(d);
- label = udev_device_get_property_value(d, "ID_FS_LABEL");
- if (label)
+ if (sd_device_get_property_value(d, "ID_FS_LABEL", &label) >= 0)
return label;
- return udev_device_get_property_value(d, "ID_PART_ENTRY_NAME");
+ if (sd_device_get_property_value(d, "ID_PART_ENTRY_NAME", &label) >= 0)
+ return label;
+
+ return NULL;
}
-static int acquire_mount_where(struct udev_device *d) {
+static int acquire_mount_where(sd_device *d) {
const char *v;
if (arg_mount_where)
return 0;
- v = udev_device_get_property_value(d, "SYSTEMD_MOUNT_WHERE");
- if (isempty(v)) {
+ if (sd_device_get_property_value(d, "SYSTEMD_MOUNT_WHERE", &v) < 0) {
_cleanup_free_ char *escaped = NULL;
const char *name;
if (!name) {
const char *dn;
- dn = udev_device_get_devnode(d);
- if (!dn)
+ if (sd_device_get_devname(d, &dn) < 0)
return 0;
name = basename(dn);
r = find_mount_points(loop_dev, &list);
if (r < 0)
return r;
- else if (r == 0) {
- log_error("Can't find mount point of %s. It is expected that %s is already mounted on a place.", loop_dev, loop_dev);
- return -EINVAL;
- } else if (r >= 2) {
- log_error("%s is mounted on %d places. It is expected that %s is mounted on a place.", loop_dev, r, loop_dev);
- return -EINVAL;
- }
+ else if (r == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Can't find mount point of %s. It is expected that %s is already mounted on a place.",
+ loop_dev, loop_dev);
+ else if (r >= 2)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s is mounted on %d places. It is expected that %s is mounted on a place.",
+ loop_dev, r, loop_dev);
arg_mount_where = strdup(list[0]);
if (!arg_mount_where)
return 1;
}
-static int acquire_description(struct udev_device *d) {
+static int acquire_description(sd_device *d) {
const char *model, *label;
if (arg_description)
label = get_label(d);
if (!label)
- label = udev_device_get_property_value(d, "ID_PART_ENTRY_NUMBER");
+ (void) sd_device_get_property_value(d, "ID_PART_ENTRY_NUMBER", &label);
if (model && label)
arg_description = strjoin(model, " ", label);
return 1;
}
-static int acquire_removable(struct udev_device *d) {
+static int acquire_removable(sd_device *d) {
const char *v;
/* Shortcut this if there's no reason to check it */
return 0;
for (;;) {
- v = udev_device_get_sysattr_value(d, "removable");
- if (v)
+ if (sd_device_get_sysattr_value(d, "removable", &v) > 0)
break;
- d = udev_device_get_parent(d);
- if (!d)
+ if (sd_device_get_parent(d, &d) < 0)
return 0;
- if (!streq_ptr(udev_device_get_subsystem(d), "block"))
+ if (sd_device_get_subsystem(d, &v) < 0 || !streq(v, "block"))
return 0;
}
}
static int discover_loop_backing_file(void) {
- _cleanup_udev_device_unref_ struct udev_device *d = NULL;
- _cleanup_udev_unref_ struct udev *udev = NULL;
+ _cleanup_(sd_device_unrefp) sd_device *d = NULL;
_cleanup_free_ char *loop_dev = NULL;
struct stat st;
const char *v;
return -EINVAL;
}
- udev = udev_new();
- if (!udev)
- return log_oom();
-
- d = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
- if (!d)
- return log_oom();
+ r = sd_device_new_from_devnum(&d, 'b', st.st_rdev);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get device from device number: %m");
- 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.", arg_mount_what);
+ if (sd_device_get_property_value(d, "ID_FS_USAGE", &v) < 0 || !streq(v, "filesystem")) {
+ log_device_error(d, "%s does not contain a known file system.", arg_mount_what);
return -EINVAL;
}
}
static int discover_device(void) {
- _cleanup_udev_device_unref_ struct udev_device *d = NULL;
- _cleanup_udev_unref_ struct udev *udev = NULL;
+ _cleanup_(sd_device_unrefp) sd_device *d = NULL;
struct stat st;
const char *v;
int r;
return -EINVAL;
}
- udev = udev_new();
- if (!udev)
- return log_oom();
-
- d = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
- if (!d)
- return log_oom();
+ r = sd_device_new_from_devnum(&d, 'b', st.st_rdev);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get device from device number: %m");
- v = udev_device_get_property_value(d, "ID_FS_USAGE");
- if (!streq_ptr(v, "filesystem")) {
+ if (sd_device_get_property_value(d, "ID_FS_USAGE", &v) < 0 || !streq(v, "filesystem")) {
log_error("%s does not contain a known file system.", arg_mount_what);
return -EINVAL;
}
char* columns[_COLUMN_MAX];
};
-static int compare_item(const void *a, const void *b) {
- const struct item *x = a, *y = b;
-
- if (x->columns[COLUMN_NODE] == y->columns[COLUMN_NODE])
+static int compare_item(const struct item *a, const struct item *b) {
+ if (a->columns[COLUMN_NODE] == b->columns[COLUMN_NODE])
return 0;
- if (!x->columns[COLUMN_NODE])
+ if (!a->columns[COLUMN_NODE])
return 1;
- if (!y->columns[COLUMN_NODE])
+ if (!b->columns[COLUMN_NODE])
return -1;
- return path_compare(x->columns[COLUMN_NODE], y->columns[COLUMN_NODE]);
+ return path_compare(a->columns[COLUMN_NODE], b->columns[COLUMN_NODE]);
}
static int list_devices(void) {
[COLUMN_UUID] = "UUID"
};
- _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
- _cleanup_udev_unref_ struct udev *udev = NULL;
- struct udev_list_entry *item = NULL, *first = NULL;
+ _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
size_t n_allocated = 0, n = 0, i;
size_t column_width[_COLUMN_MAX];
struct item *items = NULL;
+ sd_device *d;
unsigned c;
int r;
for (c = 0; c < _COLUMN_MAX; c++)
column_width[c] = strlen(titles[c]);
- udev = udev_new();
- if (!udev)
- return log_oom();
-
- e = udev_enumerate_new(udev);
- if (!e)
+ r = sd_device_enumerator_new(&e);
+ if (r < 0)
return log_oom();
- r = udev_enumerate_add_match_subsystem(e, "block");
+ r = sd_device_enumerator_add_match_subsystem(e, "block", true);
if (r < 0)
return log_error_errno(r, "Failed to add block match: %m");
- r = udev_enumerate_add_match_property(e, "ID_FS_USAGE", "filesystem");
+ r = sd_device_enumerator_add_match_property(e, "ID_FS_USAGE", "filesystem");
if (r < 0)
return log_error_errno(r, "Failed to add property match: %m");
- r = udev_enumerate_scan_devices(e);
- if (r < 0)
- return log_error_errno(r, "Failed to scan devices: %m");
-
- first = udev_enumerate_get_list_entry(e);
- udev_list_entry_foreach(item, first) {
- _cleanup_udev_device_unref_ struct udev_device *d;
+ FOREACH_DEVICE(e, d) {
struct item *j;
- d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
- if (!d) {
- r = log_oom();
- goto finish;
- }
-
if (!GREEDY_REALLOC0(items, n_allocated, n+1)) {
r = log_oom();
goto finish;
switch (c) {
case COLUMN_NODE:
- x = udev_device_get_devnode(d);
+ (void) sd_device_get_devname(d, &x);
break;
case COLUMN_PATH:
- x = udev_device_get_property_value(d, "ID_PATH");
+ (void) sd_device_get_property_value(d, "ID_PATH", &x);
break;
case COLUMN_MODEL:
break;
case COLUMN_WWN:
- x = udev_device_get_property_value(d, "ID_WWN");
+ (void) sd_device_get_property_value(d, "ID_WWN", &x);
break;
case COLUMN_FSTYPE:
- x = udev_device_get_property_value(d, "ID_FS_TYPE");
+ (void) sd_device_get_property_value(d, "ID_FS_TYPE", &x);
break;
case COLUMN_LABEL:
break;
case COLUMN_UUID:
- x = udev_device_get_property_value(d, "ID_FS_UUID");
+ (void) sd_device_get_property_value(d, "ID_FS_UUID", &x);
break;
}
goto finish;
}
- qsort_safe(items, n, sizeof(struct item), compare_item);
+ typesafe_qsort(items, n, compare_item);
- (void) pager_open(arg_no_pager, false);
+ (void) pager_open(arg_pager_flags);
fputs(ansi_underline(), stdout);
for (c = 0; c < _COLUMN_MAX; c++) {
return r;
}
-int main(int argc, char* argv[]) {
- sd_bus *bus = NULL;
+static int run(int argc, char* argv[]) {
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
log_parse_environment();
r = parse_argv(argc, argv);
if (r <= 0)
- goto finish;
+ return r;
- if (arg_action == ACTION_LIST) {
- r = list_devices();
- goto finish;
- }
+ if (arg_action == ACTION_LIST)
+ return list_devices();
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 (r < 0)
+ return log_error_errno(r, "Failed to create bus connection: %m");
- if (arg_action == ACTION_UMOUNT) {
- r = action_umount(bus, argc, argv);
- goto finish;
- }
+ if (arg_action == ACTION_UMOUNT)
+ return action_umount(bus, argc, argv);
if (!path_is_normalized(arg_mount_what)) {
log_error("Path contains non-normalized components: %s", arg_mount_what);
- r = -EINVAL;
- goto finish;
+ return -EINVAL;
}
if (arg_discover) {
r = discover_device();
if (r < 0)
- goto finish;
+ return r;
}
if (!arg_mount_where) {
log_error("Can't figure out where to mount %s.", arg_mount_what);
- r = -EINVAL;
- goto finish;
+ return -EINVAL;
}
if (path_equal(arg_mount_where, "/")) {
log_error("Refusing to operate on root directory.");
- r = -EINVAL;
- goto finish;
+ return -EINVAL;
}
if (!path_is_normalized(arg_mount_where)) {
log_error("Path contains non-normalized components: %s", arg_mount_where);
- r = -EINVAL;
- goto finish;
+ return -EINVAL;
}
if (streq_ptr(arg_mount_type, "auto"))
!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;
+ return -EOPNOTSUPP;
}
switch (arg_action) {
assert_not_reached("Unexpected action.");
}
-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);
- free(arg_mount_where);
- free(arg_mount_type);
- free(arg_mount_options);
- free(arg_description);
- strv_free(arg_property);
- strv_free(arg_automount_property);
-
- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+ return r;
}
+
+DEFINE_MAIN_FUNCTION(run);