2 This file is part of elogind.
4 Copyright 2016 Lennart Poettering
6 elogind is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 elogind is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with elogind; If not, see <http://www.gnu.org/licenses/>.
25 #include "bus-error.h"
26 #include "bus-unit-util.h"
29 #include "fstab-util.h"
31 #include "parse-util.h"
32 #include "path-util.h"
33 #include "spawn-polkit-agent.h"
35 #include "udev-util.h"
36 #include "unit-name.h"
37 #include "terminal-util.h"
44 } arg_action = ACTION_DEFAULT;
46 static bool arg_no_block = false;
47 static bool arg_no_pager = false;
48 static bool arg_ask_password = true;
49 static bool arg_quiet = false;
50 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
51 static bool arg_user = false;
52 static const char *arg_host = NULL;
53 static bool arg_discover = false;
54 static char *arg_mount_what = NULL;
55 static char *arg_mount_where = NULL;
56 static char *arg_mount_type = NULL;
57 static char *arg_mount_options = NULL;
58 static char *arg_description = NULL;
59 static char **arg_property = NULL;
60 static usec_t arg_timeout_idle = USEC_INFINITY;
61 static bool arg_timeout_idle_set = false;
62 static char **arg_automount_property = NULL;
63 static int arg_bind_device = -1;
64 static bool arg_fsck = true;
66 static void polkit_agent_open_if_enabled(void) {
68 /* Open the polkit agent as a child process if necessary */
69 if (!arg_ask_password)
72 if (arg_transport != BUS_TRANSPORT_LOCAL)
78 static void help(void) {
79 printf("%s [OPTIONS...] WHAT [WHERE]\n\n"
80 "Establish a mount or auto-mount point transiently.\n\n"
81 " -h --help Show this help\n"
82 " --version Show package version\n"
83 " --no-block Do not wait until operation finished\n"
84 " --no-pager Do not pipe output into a pager\n"
85 " --no-ask-password Do not prompt for password\n"
86 " -q --quiet Suppress information messages during runtime\n"
87 " --user Run as user unit\n"
88 " -H --host=[USER@]HOST Operate on remote host\n"
89 " -M --machine=CONTAINER Operate on local container\n"
90 " --discover Discover mount device metadata\n"
91 " -t --type=TYPE File system type\n"
92 " -o --options=OPTIONS Mount options\n"
93 " --fsck=no Don't run file system check before mount\n"
94 " --description=TEXT Description for unit\n"
95 " -p --property=NAME=VALUE Set mount unit property\n"
96 " -A --automount=BOOL Create an auto-mount point\n"
97 " --timeout-idle-sec=SEC Specify automount idle timeout\n"
98 " --automount-property=NAME=VALUE\n"
99 " Set automount unit property\n"
100 " --bind-device Bind automount unit to device\n"
101 " --list List mountable block devices\n"
102 , program_invocation_short_name);
105 static int parse_argv(int argc, char *argv[]) {
121 ARG_AUTOMOUNT_PROPERTY,
126 static const struct option options[] = {
127 { "help", no_argument, NULL, 'h' },
128 { "version", no_argument, NULL, ARG_VERSION },
129 { "no-block", no_argument, NULL, ARG_NO_BLOCK },
130 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
131 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
132 { "quiet", no_argument, NULL, 'q' },
133 { "user", no_argument, NULL, ARG_USER },
134 { "system", no_argument, NULL, ARG_SYSTEM },
135 { "host", required_argument, NULL, 'H' },
136 { "machine", required_argument, NULL, 'M' },
137 { "discover", no_argument, NULL, ARG_DISCOVER },
138 { "type", required_argument, NULL, 't' },
139 { "options", required_argument, NULL, 'o' },
140 { "description", required_argument, NULL, ARG_DESCRIPTION },
141 { "property", required_argument, NULL, 'p' },
142 { "automount", required_argument, NULL, ARG_AUTOMOUNT },
143 { "timeout-idle-sec", required_argument, NULL, ARG_TIMEOUT_IDLE },
144 { "automount-property", required_argument, NULL, ARG_AUTOMOUNT_PROPERTY },
145 { "bind-device", no_argument, NULL, ARG_BIND_DEVICE },
146 { "list", no_argument, NULL, ARG_LIST },
155 while ((c = getopt_long(argc, argv, "hqH:M:t:o:p:A", options, NULL)) >= 0)
174 case ARG_NO_ASK_PASSWORD:
175 arg_ask_password = false;
191 arg_transport = BUS_TRANSPORT_REMOTE;
196 arg_transport = BUS_TRANSPORT_MACHINE;
205 if (free_and_strdup(&arg_mount_type, optarg) < 0)
210 if (free_and_strdup(&arg_mount_options, optarg) < 0)
215 r = parse_boolean(optarg);
217 return log_error_errno(r, "Failed to parse --fsck= argument: %s", optarg);
222 case ARG_DESCRIPTION:
223 if (free_and_strdup(&arg_description, optarg) < 0)
228 if (strv_extend(&arg_property, optarg) < 0)
234 arg_action = ACTION_AUTOMOUNT;
238 r = parse_boolean(optarg);
240 return log_error_errno(r, "--automount= expects a valid boolean parameter: %s", optarg);
242 arg_action = r ? ACTION_AUTOMOUNT : ACTION_MOUNT;
245 case ARG_TIMEOUT_IDLE:
246 r = parse_sec(optarg, &arg_timeout_idle);
248 return log_error_errno(r, "Failed to parse timeout: %s", optarg);
252 case ARG_AUTOMOUNT_PROPERTY:
253 if (strv_extend(&arg_automount_property, optarg) < 0)
258 case ARG_BIND_DEVICE:
259 arg_bind_device = true;
263 arg_action = ACTION_LIST;
270 assert_not_reached("Unhandled option");
273 if (arg_user && arg_transport != BUS_TRANSPORT_LOCAL) {
274 log_error("Execution in user context is not supported on non-local systems.");
278 if (arg_action == ACTION_LIST) {
280 log_error("Too many arguments.");
284 if (arg_transport != BUS_TRANSPORT_LOCAL) {
285 log_error("Listing devices only supported locally.");
289 if (optind >= argc) {
290 log_error("At least one argument required.");
294 if (argc > optind+2) {
295 log_error("At most two arguments required.");
299 arg_mount_what = fstab_node_to_udev_node(argv[optind]);
303 if (argc > optind+1) {
304 r = path_make_absolute_cwd(argv[optind+1], &arg_mount_where);
306 return log_error_errno(r, "Failed to make path absolute: %m");
310 if (arg_discover && arg_transport != BUS_TRANSPORT_LOCAL) {
311 log_error("Automatic mount location discovery is only supported locally.");
319 static int transient_unit_set_properties(sd_bus_message *m, char **properties) {
322 if (!isempty(arg_description)) {
323 r = sd_bus_message_append(m, "(sv)", "Description", "s", arg_description);
328 if (arg_bind_device && is_device_path(arg_mount_what)) {
329 _cleanup_free_ char *device_unit = NULL;
331 r = unit_name_from_path(arg_mount_what, ".device", &device_unit);
335 r = sd_bus_message_append(m, "(sv)(sv)",
336 "After", "as", 1, device_unit,
337 "BindsTo", "as", 1, device_unit);
342 r = bus_append_unit_property_assignment_many(m, properties);
349 static int transient_mount_set_properties(sd_bus_message *m) {
354 r = transient_unit_set_properties(m, arg_property);
358 if (arg_mount_what) {
359 r = sd_bus_message_append(m, "(sv)", "What", "s", arg_mount_what);
364 if (arg_mount_type) {
365 r = sd_bus_message_append(m, "(sv)", "Type", "s", arg_mount_type);
370 if (arg_mount_options) {
371 r = sd_bus_message_append(m, "(sv)", "Options", "s", arg_mount_options);
377 _cleanup_free_ char *fsck = NULL;
379 r = unit_name_from_path_instance("elogind-fsck", arg_mount_what, ".service", &fsck);
383 r = sd_bus_message_append(m,
385 "Requires", "as", 1, fsck,
386 "After", "as", 1, fsck);
394 static int transient_automount_set_properties(sd_bus_message *m) {
399 r = transient_unit_set_properties(m, arg_automount_property);
403 if (arg_timeout_idle != USEC_INFINITY) {
404 r = sd_bus_message_append(m, "(sv)", "TimeoutIdleUSec", "t", arg_timeout_idle);
412 static int start_transient_mount(
416 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
417 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
418 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
419 _cleanup_free_ char *mount_unit = NULL;
423 r = bus_wait_for_jobs_new(bus, &w);
425 return log_error_errno(r, "Could not watch jobs: %m");
428 r = unit_name_from_path(arg_mount_where, ".mount", &mount_unit);
430 return log_error_errno(r, "Failed to make mount unit name: %m");
432 r = sd_bus_message_new_method_call(
435 "org.freedesktop.elogind1",
436 "/org/freedesktop/elogind1",
437 "org.freedesktop.elogind1.Manager",
438 "StartTransientUnit");
440 return bus_log_create_error(r);
442 r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
444 return bus_log_create_error(r);
447 r = sd_bus_message_append(m, "ss", mount_unit, "fail");
449 return bus_log_create_error(r);
452 r = sd_bus_message_open_container(m, 'a', "(sv)");
454 return bus_log_create_error(r);
456 r = transient_mount_set_properties(m);
458 return bus_log_create_error(r);
460 r = sd_bus_message_close_container(m);
462 return bus_log_create_error(r);
464 /* Auxiliary units */
465 r = sd_bus_message_append(m, "a(sa(sv))", 0);
467 return bus_log_create_error(r);
469 polkit_agent_open_if_enabled();
471 r = sd_bus_call(bus, m, 0, &error, &reply);
473 return log_error_errno(r, "Failed to start transient mount unit: %s", bus_error_message(&error, r));
478 r = sd_bus_message_read(reply, "o", &object);
480 return bus_log_parse_error(r);
482 r = bus_wait_for_jobs_one(w, object, arg_quiet);
488 log_info("Started unit %s%s%s for mount point: %s%s%s",
489 ansi_highlight(), mount_unit, ansi_normal(),
490 ansi_highlight(), arg_mount_where, ansi_normal());
495 static int start_transient_automount(
499 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
500 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
501 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
502 _cleanup_free_ char *automount_unit = NULL, *mount_unit = NULL;
506 r = bus_wait_for_jobs_new(bus, &w);
508 return log_error_errno(r, "Could not watch jobs: %m");
511 r = unit_name_from_path(arg_mount_where, ".automount", &automount_unit);
513 return log_error_errno(r, "Failed to make automount unit name: %m");
515 r = unit_name_from_path(arg_mount_where, ".mount", &mount_unit);
517 return log_error_errno(r, "Failed to make mount unit name: %m");
519 r = sd_bus_message_new_method_call(
522 "org.freedesktop.elogind1",
523 "/org/freedesktop/elogind1",
524 "org.freedesktop.elogind1.Manager",
525 "StartTransientUnit");
527 return bus_log_create_error(r);
529 r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
531 return bus_log_create_error(r);
534 r = sd_bus_message_append(m, "ss", automount_unit, "fail");
536 return bus_log_create_error(r);
539 r = sd_bus_message_open_container(m, 'a', "(sv)");
541 return bus_log_create_error(r);
543 r = transient_automount_set_properties(m);
545 return bus_log_create_error(r);
547 r = sd_bus_message_close_container(m);
549 return bus_log_create_error(r);
551 /* Auxiliary units */
552 r = sd_bus_message_open_container(m, 'a', "(sa(sv))");
554 return bus_log_create_error(r);
556 r = sd_bus_message_open_container(m, 'r', "sa(sv)");
558 return bus_log_create_error(r);
560 r = sd_bus_message_append(m, "s", mount_unit);
562 return bus_log_create_error(r);
564 r = sd_bus_message_open_container(m, 'a', "(sv)");
566 return bus_log_create_error(r);
568 r = transient_mount_set_properties(m);
570 return bus_log_create_error(r);
572 r = sd_bus_message_close_container(m);
574 return bus_log_create_error(r);
576 r = sd_bus_message_close_container(m);
578 return bus_log_create_error(r);
580 r = sd_bus_message_close_container(m);
582 return bus_log_create_error(r);
584 polkit_agent_open_if_enabled();
586 r = sd_bus_call(bus, m, 0, &error, &reply);
588 return log_error_errno(r, "Failed to start transient automount unit: %s", bus_error_message(&error, r));
593 r = sd_bus_message_read(reply, "o", &object);
595 return bus_log_parse_error(r);
597 r = bus_wait_for_jobs_one(w, object, arg_quiet);
603 log_info("Started unit %s%s%s for mount point: %s%s%s",
604 ansi_highlight(), automount_unit, ansi_normal(),
605 ansi_highlight(), arg_mount_where, ansi_normal());
610 static int acquire_mount_type(struct udev_device *d) {
618 v = udev_device_get_property_value(d, "ID_FS_TYPE");
622 arg_mount_type = strdup(v);
626 log_debug("Discovered type=%s", arg_mount_type);
630 static int acquire_mount_options(struct udev_device *d) {
633 if (arg_mount_options)
636 v = udev_device_get_property_value(d, "SYSTEMD_MOUNT_OPTIONS");
640 arg_mount_options = strdup(v);
641 if (!arg_mount_options)
644 log_debug("Discovered options=%s", arg_mount_options);
648 static const char *get_model(struct udev_device *d) {
653 model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
657 return udev_device_get_property_value(d, "ID_MODEL");
660 static const char* get_label(struct udev_device *d) {
665 label = udev_device_get_property_value(d, "ID_FS_LABEL");
669 return udev_device_get_property_value(d, "ID_PART_ENTRY_NAME");
672 static int acquire_mount_where(struct udev_device *d) {
678 v = udev_device_get_property_value(d, "SYSTEMD_MOUNT_WHERE");
680 _cleanup_free_ char *escaped = NULL;
689 dn = udev_device_get_devnode(d);
696 escaped = xescape(name, "\\");
697 if (!filename_is_valid(escaped))
700 arg_mount_where = strjoin("/run/media/system/", escaped, NULL);
702 arg_mount_where = strdup(v);
704 if (!arg_mount_where)
707 log_debug("Discovered where=%s", arg_mount_where);
711 static int acquire_description(struct udev_device *d) {
712 const char *model, *label;
717 model = get_model(d);
719 label = get_label(d);
721 label = udev_device_get_property_value(d, "ID_PART_ENTRY_NUMBER");
724 arg_description = strjoin(model, " ", label, NULL);
726 arg_description = strdup(label);
728 arg_description = strdup(model);
732 if (!arg_description)
735 log_debug("Discovered description=%s", arg_description);
739 static int acquire_removable(struct udev_device *d) {
742 /* Shortcut this if there's no reason to check it */
743 if (arg_action != ACTION_DEFAULT && arg_timeout_idle_set && arg_bind_device >= 0)
747 v = udev_device_get_sysattr_value(d, "removable");
751 d = udev_device_get_parent(d);
755 if (!streq_ptr(udev_device_get_subsystem(d), "block"))
759 if (parse_boolean(v) <= 0)
762 log_debug("Discovered removable device.");
764 if (arg_action == ACTION_DEFAULT) {
765 log_debug("Automatically turning on automount.");
766 arg_action = ACTION_AUTOMOUNT;
769 if (!arg_timeout_idle_set) {
770 log_debug("Setting idle timeout to 1s.");
771 arg_timeout_idle = USEC_PER_SEC;
774 if (arg_bind_device < 0) {
775 log_debug("Binding automount unit to device.");
776 arg_bind_device = true;
782 static int discover_device(void) {
783 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
784 _cleanup_udev_unref_ struct udev *udev = NULL;
792 if (!is_device_path(arg_mount_what)) {
793 log_error("Discovery only supported for block devices, don't know what to do.");
797 if (stat(arg_mount_what, &st) < 0)
798 return log_error_errno(errno, "Can't stat %s: %m", arg_mount_what);
800 if (!S_ISBLK(st.st_mode)) {
801 log_error("Path %s is not a block device, don't know what to do.", arg_mount_what);
809 d = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
813 v = udev_device_get_property_value(d, "ID_FS_USAGE");
814 if (!streq_ptr(v, "filesystem")) {
815 log_error("%s does not contain a file system.", arg_mount_what);
819 r = acquire_mount_type(d);
823 r = acquire_mount_options(d);
827 r = acquire_mount_where(d);
831 r = acquire_description(d);
835 r = acquire_removable(d);
854 char* columns[_COLUMN_MAX];
857 static int compare_item(const void *a, const void *b) {
858 const struct item *x = a, *y = b;
860 if (x->columns[COLUMN_NODE] == y->columns[COLUMN_NODE])
862 if (!x->columns[COLUMN_NODE])
864 if (!y->columns[COLUMN_NODE])
867 return path_compare(x->columns[COLUMN_NODE], y->columns[COLUMN_NODE]);
870 static int list_devices(void) {
872 static const char * const titles[_COLUMN_MAX] = {
873 [COLUMN_NODE] = "NODE",
874 [COLUMN_PATH] = "PATH",
875 [COLUMN_MODEL] = "MODEL",
876 [COLUMN_WWN] = "WWN",
877 [COLUMN_FSTYPE] = "TYPE",
878 [COLUMN_LABEL] = "LABEL",
879 [COLUMN_UUID] = "UUID"
882 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
883 _cleanup_udev_unref_ struct udev *udev = NULL;
884 struct udev_list_entry *item = NULL, *first = NULL;
885 size_t n_allocated = 0, n = 0, i;
886 size_t column_width[_COLUMN_MAX];
887 struct item *items = NULL;
891 for (c = 0; c < _COLUMN_MAX; c++)
892 column_width[c] = strlen(titles[c]);
898 e = udev_enumerate_new(udev);
902 r = udev_enumerate_add_match_subsystem(e, "block");
904 return log_error_errno(r, "Failed to add block match: %m");
906 r = udev_enumerate_add_match_property(e, "ID_FS_USAGE", "filesystem");
908 return log_error_errno(r, "Failed to add property match: %m");
910 r = udev_enumerate_scan_devices(e);
912 return log_error_errno(r, "Failed to scan devices: %m");
914 first = udev_enumerate_get_list_entry(e);
915 udev_list_entry_foreach(item, first) {
916 _cleanup_udev_device_unref_ struct udev_device *d;
919 d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
925 if (!GREEDY_REALLOC0(items, n_allocated, n+1)) {
932 for (c = 0; c < _COLUMN_MAX; c++) {
939 x = udev_device_get_devnode(d);
943 x = udev_device_get_property_value(d, "ID_PATH");
951 x = udev_device_get_property_value(d, "ID_WWN");
955 x = udev_device_get_property_value(d, "ID_FS_TYPE");
963 x = udev_device_get_property_value(d, "ID_FS_UUID");
970 j->columns[c] = strdup(x);
971 if (!j->columns[c]) {
977 if (k > column_width[c])
983 log_info("No devices found.");
987 qsort_safe(items, n, sizeof(struct item), compare_item);
989 pager_open(arg_no_pager, false);
991 fputs(ansi_underline(), stdout);
992 for (c = 0; c < _COLUMN_MAX; c++) {
996 printf("%-*s", (int) column_width[c], titles[c]);
998 fputs(ansi_normal(), stdout);
1001 for (i = 0; i < n; i++) {
1002 for (c = 0; c < _COLUMN_MAX; c++) {
1006 printf("%-*s", (int) column_width[c], strna(items[i].columns[c]));
1008 fputc('\n', stdout);
1014 for (i = 0; i < n; i++)
1015 for (c = 0; c < _COLUMN_MAX; c++)
1016 free(items[i].columns[c]);
1022 int main(int argc, char* argv[]) {
1023 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1026 log_parse_environment();
1029 r = parse_argv(argc, argv);
1033 if (arg_action == ACTION_LIST) {
1038 r = discover_device();
1041 if (!arg_mount_where) {
1042 log_error("Can't figure out where to mount %s.", arg_mount_what);
1047 path_kill_slashes(arg_mount_where);
1049 if (path_equal(arg_mount_where, "/")) {
1050 log_error("Refusing to operate on root directory.");
1055 if (!path_is_safe(arg_mount_where)) {
1056 log_error("Path is contains unsafe components.");
1061 if (streq_ptr(arg_mount_type, "auto"))
1062 arg_mount_type = mfree(arg_mount_type);
1063 if (streq_ptr(arg_mount_options, "defaults"))
1064 arg_mount_options = mfree(arg_mount_options);
1066 if (!is_device_path(arg_mount_what))
1069 if (arg_fsck && arg_mount_type && arg_transport == BUS_TRANSPORT_LOCAL) {
1070 r = fsck_exists(arg_mount_type);
1072 log_warning_errno(r, "Couldn't determine whether fsck for %s exists, proceeding anyway.", arg_mount_type);
1074 log_debug("Disabling file system check as fsck for %s doesn't exist.", arg_mount_type);
1075 arg_fsck = false; /* fsck doesn't exist, let's not attempt it */
1079 r = bus_connect_transport_elogind(arg_transport, arg_host, arg_user, &bus);
1081 log_error_errno(r, "Failed to create bus connection: %m");
1085 switch (arg_action) {
1088 case ACTION_DEFAULT:
1089 r = start_transient_mount(bus, argv + optind);
1092 case ACTION_AUTOMOUNT:
1093 r = start_transient_automount(bus, argv + optind);
1097 assert_not_reached("Unexpected action.");
1101 bus = sd_bus_flush_close_unref(bus);
1105 free(arg_mount_what);
1106 free(arg_mount_where);
1107 free(arg_mount_type);
1108 free(arg_mount_options);
1109 free(arg_description);
1110 strv_free(arg_property);
1111 strv_free(arg_automount_property);
1113 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;