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 r = sd_bus_message_append(m, "(sv)", "Description", "s", arg_description);
326 if (arg_bind_device && is_device_path(arg_mount_what)) {
327 _cleanup_free_ char *device_unit = NULL;
329 r = unit_name_from_path(arg_mount_what, ".device", &device_unit);
333 r = sd_bus_message_append(m, "(sv)(sv)",
334 "After", "as", 1, device_unit,
335 "BindsTo", "as", 1, device_unit);
340 r = bus_append_unit_property_assignment_many(m, properties);
347 static int transient_mount_set_properties(sd_bus_message *m) {
352 r = transient_unit_set_properties(m, arg_property);
356 if (arg_mount_what) {
357 r = sd_bus_message_append(m, "(sv)", "What", "s", arg_mount_what);
362 if (arg_mount_type) {
363 r = sd_bus_message_append(m, "(sv)", "Type", "s", arg_mount_type);
368 if (arg_mount_options) {
369 r = sd_bus_message_append(m, "(sv)", "Options", "s", arg_mount_options);
375 _cleanup_free_ char *fsck = NULL;
377 r = unit_name_from_path_instance("elogind-fsck", arg_mount_what, ".service", &fsck);
381 r = sd_bus_message_append(m,
383 "Requires", "as", 1, fsck,
384 "After", "as", 1, fsck);
392 static int transient_automount_set_properties(sd_bus_message *m) {
397 r = transient_unit_set_properties(m, arg_automount_property);
401 if (arg_timeout_idle != USEC_INFINITY) {
402 r = sd_bus_message_append(m, "(sv)", "TimeoutIdleUSec", "t", arg_timeout_idle);
410 static int start_transient_mount(
414 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
415 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
416 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
417 _cleanup_free_ char *mount_unit = NULL;
421 r = bus_wait_for_jobs_new(bus, &w);
423 return log_error_errno(r, "Could not watch jobs: %m");
426 r = unit_name_from_path(arg_mount_where, ".mount", &mount_unit);
428 return log_error_errno(r, "Failed to make mount unit name: %m");
430 r = sd_bus_message_new_method_call(
433 "org.freedesktop.elogind1",
434 "/org/freedesktop/elogind1",
435 "org.freedesktop.elogind1.Manager",
436 "StartTransientUnit");
438 return bus_log_create_error(r);
440 r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
442 return bus_log_create_error(r);
445 r = sd_bus_message_append(m, "ss", mount_unit, "fail");
447 return bus_log_create_error(r);
450 r = sd_bus_message_open_container(m, 'a', "(sv)");
452 return bus_log_create_error(r);
454 r = transient_mount_set_properties(m);
456 return bus_log_create_error(r);
458 r = sd_bus_message_close_container(m);
460 return bus_log_create_error(r);
462 /* Auxiliary units */
463 r = sd_bus_message_append(m, "a(sa(sv))", 0);
465 return bus_log_create_error(r);
467 polkit_agent_open_if_enabled();
469 r = sd_bus_call(bus, m, 0, &error, &reply);
471 return log_error_errno(r, "Failed to start transient mount unit: %s", bus_error_message(&error, r));
476 r = sd_bus_message_read(reply, "o", &object);
478 return bus_log_parse_error(r);
480 r = bus_wait_for_jobs_one(w, object, arg_quiet);
486 log_info("Started unit %s%s%s for mount point: %s%s%s",
487 ansi_highlight(), mount_unit, ansi_normal(),
488 ansi_highlight(), arg_mount_where, ansi_normal());
493 static int start_transient_automount(
497 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
498 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
499 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
500 _cleanup_free_ char *automount_unit = NULL, *mount_unit = NULL;
504 r = bus_wait_for_jobs_new(bus, &w);
506 return log_error_errno(r, "Could not watch jobs: %m");
509 r = unit_name_from_path(arg_mount_where, ".automount", &automount_unit);
511 return log_error_errno(r, "Failed to make automount unit name: %m");
513 r = unit_name_from_path(arg_mount_where, ".mount", &mount_unit);
515 return log_error_errno(r, "Failed to make mount unit name: %m");
517 r = sd_bus_message_new_method_call(
520 "org.freedesktop.elogind1",
521 "/org/freedesktop/elogind1",
522 "org.freedesktop.elogind1.Manager",
523 "StartTransientUnit");
525 return bus_log_create_error(r);
527 r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
529 return bus_log_create_error(r);
532 r = sd_bus_message_append(m, "ss", automount_unit, "fail");
534 return bus_log_create_error(r);
537 r = sd_bus_message_open_container(m, 'a', "(sv)");
539 return bus_log_create_error(r);
541 r = transient_automount_set_properties(m);
543 return bus_log_create_error(r);
545 r = sd_bus_message_close_container(m);
547 return bus_log_create_error(r);
549 /* Auxiliary units */
550 r = sd_bus_message_open_container(m, 'a', "(sa(sv))");
552 return bus_log_create_error(r);
554 r = sd_bus_message_open_container(m, 'r', "sa(sv)");
556 return bus_log_create_error(r);
558 r = sd_bus_message_append(m, "s", mount_unit);
560 return bus_log_create_error(r);
562 r = sd_bus_message_open_container(m, 'a', "(sv)");
564 return bus_log_create_error(r);
566 r = transient_mount_set_properties(m);
568 return bus_log_create_error(r);
570 r = sd_bus_message_close_container(m);
572 return bus_log_create_error(r);
574 r = sd_bus_message_close_container(m);
576 return bus_log_create_error(r);
578 r = sd_bus_message_close_container(m);
580 return bus_log_create_error(r);
582 polkit_agent_open_if_enabled();
584 r = sd_bus_call(bus, m, 0, &error, &reply);
586 return log_error_errno(r, "Failed to start transient automount unit: %s", bus_error_message(&error, r));
591 r = sd_bus_message_read(reply, "o", &object);
593 return bus_log_parse_error(r);
595 r = bus_wait_for_jobs_one(w, object, arg_quiet);
601 log_info("Started unit %s%s%s for mount point: %s%s%s",
602 ansi_highlight(), automount_unit, ansi_normal(),
603 ansi_highlight(), arg_mount_where, ansi_normal());
608 static int acquire_mount_type(struct udev_device *d) {
616 v = udev_device_get_property_value(d, "ID_FS_TYPE");
620 arg_mount_type = strdup(v);
624 log_debug("Discovered type=%s", arg_mount_type);
628 static int acquire_mount_options(struct udev_device *d) {
631 if (arg_mount_options)
634 v = udev_device_get_property_value(d, "SYSTEMD_MOUNT_OPTIONS");
638 arg_mount_options = strdup(v);
639 if (!arg_mount_options)
642 log_debug("Discovered options=%s", arg_mount_options);
646 static const char *get_model(struct udev_device *d) {
651 model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
655 return udev_device_get_property_value(d, "ID_MODEL");
658 static const char* get_label(struct udev_device *d) {
663 label = udev_device_get_property_value(d, "ID_FS_LABEL");
667 return udev_device_get_property_value(d, "ID_PART_ENTRY_NAME");
670 static int acquire_mount_where(struct udev_device *d) {
676 v = udev_device_get_property_value(d, "SYSTEMD_MOUNT_WHERE");
678 _cleanup_free_ char *escaped = NULL;
687 dn = udev_device_get_devnode(d);
694 escaped = xescape(name, "\\");
695 if (!filename_is_valid(escaped))
698 arg_mount_where = strjoin("/run/media/system/", escaped, NULL);
700 arg_mount_where = strdup(v);
702 if (!arg_mount_where)
705 log_debug("Discovered where=%s", arg_mount_where);
709 static int acquire_description(struct udev_device *d) {
710 const char *model, *label;
715 model = get_model(d);
717 label = get_label(d);
719 label = udev_device_get_property_value(d, "ID_PART_ENTRY_NUMBER");
722 arg_description = strjoin(model, " ", label, NULL);
724 arg_description = strdup(label);
726 arg_description = strdup(model);
730 if (!arg_description)
733 log_debug("Discovered description=%s", arg_description);
737 static int acquire_removable(struct udev_device *d) {
740 /* Shortcut this if there's no reason to check it */
741 if (arg_action != ACTION_DEFAULT && arg_timeout_idle_set && arg_bind_device >= 0)
745 v = udev_device_get_sysattr_value(d, "removable");
749 d = udev_device_get_parent(d);
753 if (!streq_ptr(udev_device_get_subsystem(d), "block"))
757 if (parse_boolean(v) <= 0)
760 log_debug("Discovered removable device.");
762 if (arg_action == ACTION_DEFAULT) {
763 log_debug("Automatically turning on automount.");
764 arg_action = ACTION_AUTOMOUNT;
767 if (!arg_timeout_idle_set) {
768 log_debug("Setting idle timeout to 1s.");
769 arg_timeout_idle = USEC_PER_SEC;
772 if (arg_bind_device < 0) {
773 log_debug("Binding automount unit to device.");
774 arg_bind_device = true;
780 static int discover_device(void) {
781 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
782 _cleanup_udev_unref_ struct udev *udev = NULL;
790 if (!is_device_path(arg_mount_what)) {
791 log_error("Discovery only supported for block devices, don't know what to do.");
795 if (stat(arg_mount_what, &st) < 0)
796 return log_error_errno(errno, "Can't stat %s: %m", arg_mount_what);
798 if (!S_ISBLK(st.st_mode)) {
799 log_error("Path %s is not a block device, don't know what to do.", arg_mount_what);
807 d = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
811 v = udev_device_get_property_value(d, "ID_FS_USAGE");
812 if (!streq_ptr(v, "filesystem")) {
813 log_error("%s does not contain a file system.", arg_mount_what);
817 r = acquire_mount_type(d);
821 r = acquire_mount_options(d);
825 r = acquire_mount_where(d);
829 r = acquire_description(d);
833 r = acquire_removable(d);
852 char* columns[_COLUMN_MAX];
855 static int compare_item(const void *a, const void *b) {
856 const struct item *x = a, *y = b;
858 if (x->columns[COLUMN_NODE] == y->columns[COLUMN_NODE])
860 if (!x->columns[COLUMN_NODE])
862 if (!y->columns[COLUMN_NODE])
865 return path_compare(x->columns[COLUMN_NODE], y->columns[COLUMN_NODE]);
868 static int list_devices(void) {
870 static const char * const titles[_COLUMN_MAX] = {
871 [COLUMN_NODE] = "NODE",
872 [COLUMN_PATH] = "PATH",
873 [COLUMN_MODEL] = "MODEL",
874 [COLUMN_WWN] = "WWN",
875 [COLUMN_FSTYPE] = "TYPE",
876 [COLUMN_LABEL] = "LABEL",
877 [COLUMN_UUID] = "UUID"
880 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
881 _cleanup_udev_unref_ struct udev *udev = NULL;
882 struct udev_list_entry *item = NULL, *first = NULL;
883 size_t n_allocated = 0, n = 0, i;
884 size_t column_width[_COLUMN_MAX];
885 struct item *items = NULL;
889 for (c = 0; c < _COLUMN_MAX; c++)
890 column_width[c] = strlen(titles[c]);
896 e = udev_enumerate_new(udev);
900 r = udev_enumerate_add_match_subsystem(e, "block");
902 return log_error_errno(r, "Failed to add block match: %m");
904 r = udev_enumerate_add_match_property(e, "ID_FS_USAGE", "filesystem");
906 return log_error_errno(r, "Failed to add property match: %m");
908 r = udev_enumerate_scan_devices(e);
910 return log_error_errno(r, "Failed to scan devices: %m");
912 first = udev_enumerate_get_list_entry(e);
913 udev_list_entry_foreach(item, first) {
914 _cleanup_udev_device_unref_ struct udev_device *d;
917 d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
923 if (!GREEDY_REALLOC0(items, n_allocated, n+1)) {
930 for (c = 0; c < _COLUMN_MAX; c++) {
937 x = udev_device_get_devnode(d);
941 x = udev_device_get_property_value(d, "ID_PATH");
949 x = udev_device_get_property_value(d, "ID_WWN");
953 x = udev_device_get_property_value(d, "ID_FS_TYPE");
961 x = udev_device_get_property_value(d, "ID_FS_UUID");
968 j->columns[c] = strdup(x);
969 if (!j->columns[c]) {
975 if (k > column_width[c])
981 log_info("No devices found.");
985 qsort_safe(items, n, sizeof(struct item), compare_item);
987 pager_open(arg_no_pager, false);
989 fputs(ansi_underline(), stdout);
990 for (c = 0; c < _COLUMN_MAX; c++) {
994 printf("%-*s", (int) column_width[c], titles[c]);
996 fputs(ansi_normal(), stdout);
999 for (i = 0; i < n; i++) {
1000 for (c = 0; c < _COLUMN_MAX; c++) {
1004 printf("%-*s", (int) column_width[c], strna(items[i].columns[c]));
1006 fputc('\n', stdout);
1012 for (i = 0; i < n; i++)
1013 for (c = 0; c < _COLUMN_MAX; c++)
1014 free(items[i].columns[c]);
1020 int main(int argc, char* argv[]) {
1021 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1024 log_parse_environment();
1027 r = parse_argv(argc, argv);
1031 if (arg_action == ACTION_LIST) {
1036 r = discover_device();
1039 if (!arg_mount_where) {
1040 log_error("Can't figure out where to mount %s.", arg_mount_what);
1045 path_kill_slashes(arg_mount_where);
1047 if (path_equal(arg_mount_where, "/")) {
1048 log_error("Refusing to operate on root directory.");
1053 if (!path_is_safe(arg_mount_where)) {
1054 log_error("Path is contains unsafe components.");
1059 if (streq_ptr(arg_mount_type, "auto"))
1060 arg_mount_type = mfree(arg_mount_type);
1061 if (streq_ptr(arg_mount_options, "defaults"))
1062 arg_mount_options = mfree(arg_mount_options);
1064 if (!is_device_path(arg_mount_what))
1067 if (arg_fsck && arg_mount_type && arg_transport == BUS_TRANSPORT_LOCAL) {
1068 r = fsck_exists(arg_mount_type);
1070 log_warning_errno(r, "Couldn't determine whether fsck for %s exists, proceeding anyway.", arg_mount_type);
1072 log_debug("Disabling file system check as fsck for %s doesn't exist.", arg_mount_type);
1073 arg_fsck = false; /* fsck doesn't exist, let's not attempt it */
1077 r = bus_connect_transport_elogind(arg_transport, arg_host, arg_user, &bus);
1079 log_error_errno(r, "Failed to create bus connection: %m");
1083 switch (arg_action) {
1086 case ACTION_DEFAULT:
1087 r = start_transient_mount(bus, argv + optind);
1090 case ACTION_AUTOMOUNT:
1091 r = start_transient_automount(bus, argv + optind);
1095 assert_not_reached("Unexpected action.");
1099 bus = sd_bus_flush_close_unref(bus);
1103 free(arg_mount_what);
1104 free(arg_mount_where);
1105 free(arg_mount_type);
1106 free(arg_mount_options);
1107 free(arg_description);
1108 strv_free(arg_property);
1109 strv_free(arg_automount_property);
1111 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;