2 This file is part of systemd.
4 Copyright 2016 Lennart Poettering
6 systemd 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 systemd 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 systemd; 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"
45 } arg_action
= ACTION_DEFAULT
;
47 static bool arg_no_block
= false;
48 static bool arg_no_pager
= false;
49 static bool arg_ask_password
= true;
50 static bool arg_quiet
= false;
51 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
52 static bool arg_user
= false;
53 static const char *arg_host
= NULL
;
54 static bool arg_discover
= false;
55 static char *arg_mount_what
= NULL
;
56 static char *arg_mount_where
= NULL
;
57 static char *arg_mount_type
= NULL
;
58 static char *arg_mount_options
= NULL
;
59 static char *arg_description
= NULL
;
60 static char **arg_property
= NULL
;
61 static usec_t arg_timeout_idle
= USEC_INFINITY
;
62 static bool arg_timeout_idle_set
= false;
63 static char **arg_automount_property
= NULL
;
64 static int arg_bind_device
= -1;
65 static bool arg_fsck
= true;
67 static void polkit_agent_open_if_enabled(void) {
69 /* Open the polkit agent as a child process if necessary */
70 if (!arg_ask_password
)
73 if (arg_transport
!= BUS_TRANSPORT_LOCAL
)
79 static void help(void) {
80 printf("%s [OPTIONS...] WHAT [WHERE]\n\n"
81 "Establish a mount or auto-mount point transiently.\n\n"
82 " -h --help Show this help\n"
83 " --version Show package version\n"
84 " --no-block Do not wait until operation finished\n"
85 " --no-pager Do not pipe output into a pager\n"
86 " --no-ask-password Do not prompt for password\n"
87 " -q --quiet Suppress information messages during runtime\n"
88 " --user Run as user unit\n"
89 " -H --host=[USER@]HOST Operate on remote host\n"
90 " -M --machine=CONTAINER Operate on local container\n"
91 " --discover Discover mount device metadata\n"
92 " -t --type=TYPE File system type\n"
93 " -o --options=OPTIONS Mount options\n"
94 " --fsck=no Don't run file system check before mount\n"
95 " --description=TEXT Description for unit\n"
96 " -p --property=NAME=VALUE Set mount unit property\n"
97 " -A --automount=BOOL Create an auto-mount point\n"
98 " --timeout-idle-sec=SEC Specify automount idle timeout\n"
99 " --automount-property=NAME=VALUE\n"
100 " Set automount unit property\n"
101 " --bind-device Bind automount unit to device\n"
102 " --list List mountable block devices\n"
103 " -u --umount Unmount mount points\n"
104 , program_invocation_short_name
);
107 static int parse_argv(int argc
, char *argv
[]) {
123 ARG_AUTOMOUNT_PROPERTY
,
128 static const struct option options
[] = {
129 { "help", no_argument
, NULL
, 'h' },
130 { "version", no_argument
, NULL
, ARG_VERSION
},
131 { "no-block", no_argument
, NULL
, ARG_NO_BLOCK
},
132 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
133 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
134 { "quiet", no_argument
, NULL
, 'q' },
135 { "user", no_argument
, NULL
, ARG_USER
},
136 { "system", no_argument
, NULL
, ARG_SYSTEM
},
137 { "host", required_argument
, NULL
, 'H' },
138 { "machine", required_argument
, NULL
, 'M' },
139 { "discover", no_argument
, NULL
, ARG_DISCOVER
},
140 { "type", required_argument
, NULL
, 't' },
141 { "options", required_argument
, NULL
, 'o' },
142 { "fsck", required_argument
, NULL
, ARG_FSCK
},
143 { "description", required_argument
, NULL
, ARG_DESCRIPTION
},
144 { "property", required_argument
, NULL
, 'p' },
145 { "automount", required_argument
, NULL
, ARG_AUTOMOUNT
},
146 { "timeout-idle-sec", required_argument
, NULL
, ARG_TIMEOUT_IDLE
},
147 { "automount-property", required_argument
, NULL
, ARG_AUTOMOUNT_PROPERTY
},
148 { "bind-device", no_argument
, NULL
, ARG_BIND_DEVICE
},
149 { "list", no_argument
, NULL
, ARG_LIST
},
150 { "umount", no_argument
, NULL
, 'u' },
151 { "unmount", no_argument
, NULL
, 'u' },
160 if (strstr(program_invocation_short_name
, "systemd-umount"))
161 arg_action
= ACTION_UMOUNT
;
163 while ((c
= getopt_long(argc
, argv
, "hqH:M:t:o:p:Au", options
, NULL
)) >= 0)
182 case ARG_NO_ASK_PASSWORD
:
183 arg_ask_password
= false;
199 arg_transport
= BUS_TRANSPORT_REMOTE
;
204 arg_transport
= BUS_TRANSPORT_MACHINE
;
213 if (free_and_strdup(&arg_mount_type
, optarg
) < 0)
218 if (free_and_strdup(&arg_mount_options
, optarg
) < 0)
223 r
= parse_boolean(optarg
);
225 return log_error_errno(r
, "Failed to parse --fsck= argument: %s", optarg
);
230 case ARG_DESCRIPTION
:
231 if (free_and_strdup(&arg_description
, optarg
) < 0)
236 if (strv_extend(&arg_property
, optarg
) < 0)
242 arg_action
= ACTION_AUTOMOUNT
;
246 r
= parse_boolean(optarg
);
248 return log_error_errno(r
, "--automount= expects a valid boolean parameter: %s", optarg
);
250 arg_action
= r
? ACTION_AUTOMOUNT
: ACTION_MOUNT
;
253 case ARG_TIMEOUT_IDLE
:
254 r
= parse_sec(optarg
, &arg_timeout_idle
);
256 return log_error_errno(r
, "Failed to parse timeout: %s", optarg
);
260 case ARG_AUTOMOUNT_PROPERTY
:
261 if (strv_extend(&arg_automount_property
, optarg
) < 0)
266 case ARG_BIND_DEVICE
:
267 arg_bind_device
= true;
271 arg_action
= ACTION_LIST
;
275 arg_action
= ACTION_UMOUNT
;
282 assert_not_reached("Unhandled option");
285 if (arg_user
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
286 log_error("Execution in user context is not supported on non-local systems.");
290 if (arg_action
== ACTION_LIST
) {
292 log_error("Too many arguments.");
296 if (arg_transport
!= BUS_TRANSPORT_LOCAL
) {
297 log_error("Listing devices only supported locally.");
301 if (optind
>= argc
) {
302 log_error("At least one argument required.");
306 if (argc
> optind
+2) {
307 log_error("At most two arguments required.");
311 arg_mount_what
= fstab_node_to_udev_node(argv
[optind
]);
315 if (argc
> optind
+1) {
316 r
= path_make_absolute_cwd(argv
[optind
+1], &arg_mount_where
);
318 return log_error_errno(r
, "Failed to make path absolute: %m");
322 if (arg_discover
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
323 log_error("Automatic mount location discovery is only supported locally.");
331 static int transient_unit_set_properties(sd_bus_message
*m
, char **properties
) {
334 if (!isempty(arg_description
)) {
335 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", arg_description
);
340 if (arg_bind_device
&& is_device_path(arg_mount_what
)) {
341 _cleanup_free_
char *device_unit
= NULL
;
343 r
= unit_name_from_path(arg_mount_what
, ".device", &device_unit
);
347 r
= sd_bus_message_append(m
, "(sv)(sv)",
348 "After", "as", 1, device_unit
,
349 "BindsTo", "as", 1, device_unit
);
354 r
= bus_append_unit_property_assignment_many(m
, properties
);
361 static int transient_mount_set_properties(sd_bus_message
*m
) {
366 r
= transient_unit_set_properties(m
, arg_property
);
370 if (arg_mount_what
) {
371 r
= sd_bus_message_append(m
, "(sv)", "What", "s", arg_mount_what
);
376 if (arg_mount_type
) {
377 r
= sd_bus_message_append(m
, "(sv)", "Type", "s", arg_mount_type
);
382 if (arg_mount_options
) {
383 r
= sd_bus_message_append(m
, "(sv)", "Options", "s", arg_mount_options
);
389 _cleanup_free_
char *fsck
= NULL
;
391 r
= unit_name_from_path_instance("systemd-fsck", arg_mount_what
, ".service", &fsck
);
395 r
= sd_bus_message_append(m
,
397 "Requires", "as", 1, fsck
,
398 "After", "as", 1, fsck
);
406 static int transient_automount_set_properties(sd_bus_message
*m
) {
411 r
= transient_unit_set_properties(m
, arg_automount_property
);
415 if (arg_timeout_idle
!= USEC_INFINITY
) {
416 r
= sd_bus_message_append(m
, "(sv)", "TimeoutIdleUSec", "t", arg_timeout_idle
);
424 static int start_transient_mount(
428 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
429 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
430 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
431 _cleanup_free_
char *mount_unit
= NULL
;
435 r
= bus_wait_for_jobs_new(bus
, &w
);
437 return log_error_errno(r
, "Could not watch jobs: %m");
440 r
= unit_name_from_path(arg_mount_where
, ".mount", &mount_unit
);
442 return log_error_errno(r
, "Failed to make mount unit name: %m");
444 r
= sd_bus_message_new_method_call(
447 "org.freedesktop.systemd1",
448 "/org/freedesktop/systemd1",
449 "org.freedesktop.systemd1.Manager",
450 "StartTransientUnit");
452 return bus_log_create_error(r
);
454 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
456 return bus_log_create_error(r
);
459 r
= sd_bus_message_append(m
, "ss", mount_unit
, "fail");
461 return bus_log_create_error(r
);
464 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
466 return bus_log_create_error(r
);
468 r
= transient_mount_set_properties(m
);
470 return bus_log_create_error(r
);
472 r
= sd_bus_message_close_container(m
);
474 return bus_log_create_error(r
);
476 /* Auxiliary units */
477 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
479 return bus_log_create_error(r
);
481 polkit_agent_open_if_enabled();
483 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
485 return log_error_errno(r
, "Failed to start transient mount unit: %s", bus_error_message(&error
, r
));
490 r
= sd_bus_message_read(reply
, "o", &object
);
492 return bus_log_parse_error(r
);
494 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
500 log_info("Started unit %s%s%s for mount point: %s%s%s",
501 ansi_highlight(), mount_unit
, ansi_normal(),
502 ansi_highlight(), arg_mount_where
, ansi_normal());
507 static int start_transient_automount(
511 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
512 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
513 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
514 _cleanup_free_
char *automount_unit
= NULL
, *mount_unit
= NULL
;
518 r
= bus_wait_for_jobs_new(bus
, &w
);
520 return log_error_errno(r
, "Could not watch jobs: %m");
523 r
= unit_name_from_path(arg_mount_where
, ".automount", &automount_unit
);
525 return log_error_errno(r
, "Failed to make automount unit name: %m");
527 r
= unit_name_from_path(arg_mount_where
, ".mount", &mount_unit
);
529 return log_error_errno(r
, "Failed to make mount unit name: %m");
531 r
= sd_bus_message_new_method_call(
534 "org.freedesktop.systemd1",
535 "/org/freedesktop/systemd1",
536 "org.freedesktop.systemd1.Manager",
537 "StartTransientUnit");
539 return bus_log_create_error(r
);
541 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
543 return bus_log_create_error(r
);
546 r
= sd_bus_message_append(m
, "ss", automount_unit
, "fail");
548 return bus_log_create_error(r
);
551 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
553 return bus_log_create_error(r
);
555 r
= transient_automount_set_properties(m
);
557 return bus_log_create_error(r
);
559 r
= sd_bus_message_close_container(m
);
561 return bus_log_create_error(r
);
563 /* Auxiliary units */
564 r
= sd_bus_message_open_container(m
, 'a', "(sa(sv))");
566 return bus_log_create_error(r
);
568 r
= sd_bus_message_open_container(m
, 'r', "sa(sv)");
570 return bus_log_create_error(r
);
572 r
= sd_bus_message_append(m
, "s", mount_unit
);
574 return bus_log_create_error(r
);
576 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
578 return bus_log_create_error(r
);
580 r
= transient_mount_set_properties(m
);
582 return bus_log_create_error(r
);
584 r
= sd_bus_message_close_container(m
);
586 return bus_log_create_error(r
);
588 r
= sd_bus_message_close_container(m
);
590 return bus_log_create_error(r
);
592 r
= sd_bus_message_close_container(m
);
594 return bus_log_create_error(r
);
596 polkit_agent_open_if_enabled();
598 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
600 return log_error_errno(r
, "Failed to start transient automount unit: %s", bus_error_message(&error
, r
));
605 r
= sd_bus_message_read(reply
, "o", &object
);
607 return bus_log_parse_error(r
);
609 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
615 log_info("Started unit %s%s%s for mount point: %s%s%s",
616 ansi_highlight(), automount_unit
, ansi_normal(),
617 ansi_highlight(), arg_mount_where
, ansi_normal());
622 static int stop_mount(
625 const char *suffix
) {
627 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
628 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
629 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
630 _cleanup_free_
char *mount_unit
= NULL
;
634 r
= bus_wait_for_jobs_new(bus
, &w
);
636 return log_error_errno(r
, "Could not watch jobs: %m");
639 r
= unit_name_from_path(arg_mount_where
, suffix
, &mount_unit
);
641 return log_error_errno(r
, "Failed to make mount unit name: %m");
643 r
= sd_bus_message_new_method_call(
646 "org.freedesktop.systemd1",
647 "/org/freedesktop/systemd1",
648 "org.freedesktop.systemd1.Manager",
651 return bus_log_create_error(r
);
653 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
655 return bus_log_create_error(r
);
658 r
= sd_bus_message_append(m
, "ss", mount_unit
, "fail");
660 return bus_log_create_error(r
);
662 polkit_agent_open_if_enabled();
664 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
666 return log_error_errno(r
, "Failed to stop mount unit: %s", bus_error_message(&error
, r
));
671 r
= sd_bus_message_read(reply
, "o", &object
);
673 return bus_log_parse_error(r
);
675 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
681 log_info("Stopped unit %s%s%s for mount point: %s%s%s",
682 ansi_highlight(), mount_unit
, ansi_normal(),
683 ansi_highlight(), arg_mount_where
, ansi_normal());
688 static int stop_mounts(
694 r
= stop_mount(bus
, argv
+ optind
, ".mount");
698 r
= stop_mount(bus
, argv
+ optind
, ".automount");
705 static int acquire_mount_type(struct udev_device
*d
) {
713 v
= udev_device_get_property_value(d
, "ID_FS_TYPE");
717 arg_mount_type
= strdup(v
);
721 log_debug("Discovered type=%s", arg_mount_type
);
725 static int acquire_mount_options(struct udev_device
*d
) {
728 if (arg_mount_options
)
731 v
= udev_device_get_property_value(d
, "SYSTEMD_MOUNT_OPTIONS");
735 arg_mount_options
= strdup(v
);
736 if (!arg_mount_options
)
739 log_debug("Discovered options=%s", arg_mount_options
);
743 static const char *get_model(struct udev_device
*d
) {
748 model
= udev_device_get_property_value(d
, "ID_MODEL_FROM_DATABASE");
752 return udev_device_get_property_value(d
, "ID_MODEL");
755 static const char* get_label(struct udev_device
*d
) {
760 label
= udev_device_get_property_value(d
, "ID_FS_LABEL");
764 return udev_device_get_property_value(d
, "ID_PART_ENTRY_NAME");
767 static int acquire_mount_where(struct udev_device
*d
) {
773 v
= udev_device_get_property_value(d
, "SYSTEMD_MOUNT_WHERE");
775 _cleanup_free_
char *escaped
= NULL
;
784 dn
= udev_device_get_devnode(d
);
791 escaped
= xescape(name
, "\\");
792 if (!filename_is_valid(escaped
))
795 arg_mount_where
= strjoin("/run/media/system/", escaped
);
797 arg_mount_where
= strdup(v
);
799 if (!arg_mount_where
)
802 log_debug("Discovered where=%s", arg_mount_where
);
806 static int acquire_description(struct udev_device
*d
) {
807 const char *model
, *label
;
812 model
= get_model(d
);
814 label
= get_label(d
);
816 label
= udev_device_get_property_value(d
, "ID_PART_ENTRY_NUMBER");
819 arg_description
= strjoin(model
, " ", label
);
821 arg_description
= strdup(label
);
823 arg_description
= strdup(model
);
827 if (!arg_description
)
830 log_debug("Discovered description=%s", arg_description
);
834 static int acquire_removable(struct udev_device
*d
) {
837 /* Shortcut this if there's no reason to check it */
838 if (arg_action
!= ACTION_DEFAULT
&& arg_timeout_idle_set
&& arg_bind_device
>= 0)
842 v
= udev_device_get_sysattr_value(d
, "removable");
846 d
= udev_device_get_parent(d
);
850 if (!streq_ptr(udev_device_get_subsystem(d
), "block"))
854 if (parse_boolean(v
) <= 0)
857 log_debug("Discovered removable device.");
859 if (arg_action
== ACTION_DEFAULT
) {
860 log_debug("Automatically turning on automount.");
861 arg_action
= ACTION_AUTOMOUNT
;
864 if (!arg_timeout_idle_set
) {
865 log_debug("Setting idle timeout to 1s.");
866 arg_timeout_idle
= USEC_PER_SEC
;
869 if (arg_bind_device
< 0) {
870 log_debug("Binding automount unit to device.");
871 arg_bind_device
= true;
877 static int discover_device(void) {
878 _cleanup_udev_device_unref_
struct udev_device
*d
= NULL
;
879 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
887 if (!is_device_path(arg_mount_what
)) {
888 log_error("Discovery only supported for block devices, don't know what to do.");
892 if (stat(arg_mount_what
, &st
) < 0)
893 return log_error_errno(errno
, "Can't stat %s: %m", arg_mount_what
);
895 if (!S_ISBLK(st
.st_mode
)) {
896 log_error("Path %s is not a block device, don't know what to do.", arg_mount_what
);
904 d
= udev_device_new_from_devnum(udev
, 'b', st
.st_rdev
);
908 v
= udev_device_get_property_value(d
, "ID_FS_USAGE");
909 if (!streq_ptr(v
, "filesystem")) {
910 log_error("%s does not contain a file system.", arg_mount_what
);
914 r
= acquire_mount_type(d
);
918 r
= acquire_mount_options(d
);
922 r
= acquire_mount_where(d
);
926 r
= acquire_description(d
);
930 r
= acquire_removable(d
);
949 char* columns
[_COLUMN_MAX
];
952 static int compare_item(const void *a
, const void *b
) {
953 const struct item
*x
= a
, *y
= b
;
955 if (x
->columns
[COLUMN_NODE
] == y
->columns
[COLUMN_NODE
])
957 if (!x
->columns
[COLUMN_NODE
])
959 if (!y
->columns
[COLUMN_NODE
])
962 return path_compare(x
->columns
[COLUMN_NODE
], y
->columns
[COLUMN_NODE
]);
965 static int list_devices(void) {
967 static const char * const titles
[_COLUMN_MAX
] = {
968 [COLUMN_NODE
] = "NODE",
969 [COLUMN_PATH
] = "PATH",
970 [COLUMN_MODEL
] = "MODEL",
971 [COLUMN_WWN
] = "WWN",
972 [COLUMN_FSTYPE
] = "TYPE",
973 [COLUMN_LABEL
] = "LABEL",
974 [COLUMN_UUID
] = "UUID"
977 _cleanup_udev_enumerate_unref_
struct udev_enumerate
*e
= NULL
;
978 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
979 struct udev_list_entry
*item
= NULL
, *first
= NULL
;
980 size_t n_allocated
= 0, n
= 0, i
;
981 size_t column_width
[_COLUMN_MAX
];
982 struct item
*items
= NULL
;
986 for (c
= 0; c
< _COLUMN_MAX
; c
++)
987 column_width
[c
] = strlen(titles
[c
]);
993 e
= udev_enumerate_new(udev
);
997 r
= udev_enumerate_add_match_subsystem(e
, "block");
999 return log_error_errno(r
, "Failed to add block match: %m");
1001 r
= udev_enumerate_add_match_property(e
, "ID_FS_USAGE", "filesystem");
1003 return log_error_errno(r
, "Failed to add property match: %m");
1005 r
= udev_enumerate_scan_devices(e
);
1007 return log_error_errno(r
, "Failed to scan devices: %m");
1009 first
= udev_enumerate_get_list_entry(e
);
1010 udev_list_entry_foreach(item
, first
) {
1011 _cleanup_udev_device_unref_
struct udev_device
*d
;
1014 d
= udev_device_new_from_syspath(udev
, udev_list_entry_get_name(item
));
1020 if (!GREEDY_REALLOC0(items
, n_allocated
, n
+1)) {
1027 for (c
= 0; c
< _COLUMN_MAX
; c
++) {
1028 const char *x
= NULL
;
1034 x
= udev_device_get_devnode(d
);
1038 x
= udev_device_get_property_value(d
, "ID_PATH");
1046 x
= udev_device_get_property_value(d
, "ID_WWN");
1050 x
= udev_device_get_property_value(d
, "ID_FS_TYPE");
1058 x
= udev_device_get_property_value(d
, "ID_FS_UUID");
1065 j
->columns
[c
] = strdup(x
);
1066 if (!j
->columns
[c
]) {
1072 if (k
> column_width
[c
])
1073 column_width
[c
] = k
;
1078 log_info("No devices found.");
1082 qsort_safe(items
, n
, sizeof(struct item
), compare_item
);
1084 pager_open(arg_no_pager
, false);
1086 fputs(ansi_underline(), stdout
);
1087 for (c
= 0; c
< _COLUMN_MAX
; c
++) {
1091 printf("%-*s", (int) column_width
[c
], titles
[c
]);
1093 fputs(ansi_normal(), stdout
);
1094 fputc('\n', stdout
);
1096 for (i
= 0; i
< n
; i
++) {
1097 for (c
= 0; c
< _COLUMN_MAX
; c
++) {
1101 printf("%-*s", (int) column_width
[c
], strna(items
[i
].columns
[c
]));
1103 fputc('\n', stdout
);
1109 for (i
= 0; i
< n
; i
++)
1110 for (c
= 0; c
< _COLUMN_MAX
; c
++)
1111 free(items
[i
].columns
[c
]);
1117 int main(int argc
, char* argv
[]) {
1118 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1121 log_parse_environment();
1124 r
= parse_argv(argc
, argv
);
1128 if (arg_action
== ACTION_LIST
) {
1133 r
= discover_device();
1136 if (!arg_mount_where
) {
1137 log_error("Can't figure out where to mount %s.", arg_mount_what
);
1142 path_kill_slashes(arg_mount_where
);
1144 if (path_equal(arg_mount_where
, "/")) {
1145 log_error("Refusing to operate on root directory.");
1150 if (!path_is_safe(arg_mount_where
)) {
1151 log_error("Path is contains unsafe components.");
1156 if (streq_ptr(arg_mount_type
, "auto"))
1157 arg_mount_type
= mfree(arg_mount_type
);
1158 if (streq_ptr(arg_mount_options
, "defaults"))
1159 arg_mount_options
= mfree(arg_mount_options
);
1161 if (!is_device_path(arg_mount_what
))
1164 if (arg_fsck
&& arg_mount_type
&& arg_transport
== BUS_TRANSPORT_LOCAL
) {
1165 r
= fsck_exists(arg_mount_type
);
1167 log_warning_errno(r
, "Couldn't determine whether fsck for %s exists, proceeding anyway.", arg_mount_type
);
1169 log_debug("Disabling file system check as fsck for %s doesn't exist.", arg_mount_type
);
1170 arg_fsck
= false; /* fsck doesn't exist, let's not attempt it */
1174 r
= bus_connect_transport_systemd(arg_transport
, arg_host
, arg_user
, &bus
);
1176 log_error_errno(r
, "Failed to create bus connection: %m");
1180 switch (arg_action
) {
1183 case ACTION_DEFAULT
:
1184 r
= start_transient_mount(bus
, argv
+ optind
);
1187 case ACTION_AUTOMOUNT
:
1188 r
= start_transient_automount(bus
, argv
+ optind
);
1192 r
= stop_mounts(bus
, argv
+ optind
);
1196 assert_not_reached("Unexpected action.");
1200 bus
= sd_bus_flush_close_unref(bus
);
1204 free(arg_mount_what
);
1205 free(arg_mount_where
);
1206 free(arg_mount_type
);
1207 free(arg_mount_options
);
1208 free(arg_description
);
1209 strv_free(arg_property
);
1210 strv_free(arg_automount_property
);
1212 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;