#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 "libmount-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 "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_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;
break;
case ARG_NO_PAGER:
- arg_no_pager = true;
+ arg_pager_flags |= PAGER_DISABLE;
break;
case ARG_NO_ASK_PASSWORD:
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]);
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) {
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;
}
static int find_mount_points(const char *what, char ***list) {
- _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
+ _cleanup_(mnt_free_tablep) struct libmnt_table *table = NULL;
+ _cleanup_(mnt_free_iterp) struct libmnt_iter *iter = NULL;
_cleanup_strv_free_ char **l = NULL;
size_t bufsize = 0, n = 0;
+ int r;
assert(what);
assert(list);
/* Returns all mount points obtained from /proc/self/mountinfo in *list,
* and the number of mount points as return value. */
- proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
- if (!proc_self_mountinfo)
- return log_error_errno(errno, "Can't open /proc/self/mountinfo: %m");
+ r = libmount_parse(NULL, NULL, &table, &iter);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse /proc/self/mountinfo: %m");
for (;;) {
- _cleanup_free_ char *path = NULL, *where = NULL, *dev = NULL;
- int r;
+ struct libmnt_fs *fs;
+ const char *source, *target;
- r = fscanf(proc_self_mountinfo,
- "%*s " /* (1) mount id */
- "%*s " /* (2) parent id */
- "%*s " /* (3) major:minor */
- "%*s " /* (4) root */
- "%ms " /* (5) mount point */
- "%*s" /* (6) mount options */
- "%*[^-]" /* (7) optional fields */
- "- " /* (8) separator */
- "%*s " /* (9) file system type */
- "%ms" /* (10) mount source */
- "%*s" /* (11) mount options 2 */
- "%*[^\n]", /* some rubbish at the end */
- &path, &dev);
- if (r != 2) {
- if (r == EOF)
- break;
-
- continue;
- }
+ r = mnt_table_next_fs(table, iter, &fs);
+ if (r == 1)
+ break;
+ if (r < 0)
+ return log_error_errno(r, "Failed to get next entry from /proc/self/mountinfo: %m");
- if (!streq(what, dev))
+ source = mnt_fs_get_source(fs);
+ target = mnt_fs_get_target(fs);
+ if (!source || !target)
continue;
- r = cunescape(path, UNESCAPE_RELAX, &where);
- if (r < 0)
+ if (!path_equal(source, what))
continue;
/* one extra slot is needed for the terminating NULL */
- if (!GREEDY_REALLOC(l, bufsize, n + 2))
+ if (!GREEDY_REALLOC0(l, bufsize, n + 2))
return log_oom();
- l[n++] = TAKE_PTR(where);
+ l[n] = strdup(target);
+ if (!l[n])
+ return log_oom();
+ n++;
}
- if (!GREEDY_REALLOC(l, bufsize, n + 1))
+ if (!GREEDY_REALLOC0(l, bufsize, n + 1))
return log_oom();
- l[n] = NULL;
*list = TAKE_PTR(l);
-
return n;
}
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)
r = sd_device_get_property_value(d, "ID_FS_USAGE", &v);
if (r < 0)
- return log_error_errno(r, "Failed to get device property: %m");
+ return log_device_error_errno(d, r, "Failed to get device property: %m");
if (!streq(v, "filesystem")) {
- log_error("%s does not contain a known file system.", what);
+ log_device_error(d, "%s does not contain a known file system.", what);
return -EINVAL;
}
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 log_error_errno(r, "Failed to get device from device number: %m");
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);
+ log_device_error(d, "%s does not contain a known file system.", arg_mount_what);
return -EINVAL;
}
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_show_color(true);
log_parse_environment();
log_open();
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)) {
+ if ((!arg_mount_type || !fstype_is_network(arg_mount_type))
+ && !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);