1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2016 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include "bus-error.h"
27 #include "bus-unit-util.h"
29 #include "dirent-util.h"
34 #include "fstab-util.h"
35 #include "mount-util.h"
37 #include "parse-util.h"
38 #include "path-util.h"
39 #include "spawn-polkit-agent.h"
40 #include "stat-util.h"
42 #include "udev-util.h"
43 #include "unit-name.h"
44 #include "terminal-util.h"
52 } arg_action
= ACTION_DEFAULT
;
54 static bool arg_no_block
= false;
55 static bool arg_no_pager
= false;
56 static bool arg_ask_password
= true;
57 static bool arg_quiet
= false;
58 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
59 static bool arg_user
= false;
60 static const char *arg_host
= NULL
;
61 static bool arg_discover
= false;
62 static char *arg_mount_what
= NULL
;
63 static char *arg_mount_where
= NULL
;
64 static char *arg_mount_type
= NULL
;
65 static char *arg_mount_options
= NULL
;
66 static char *arg_description
= NULL
;
67 static char **arg_property
= NULL
;
68 static usec_t arg_timeout_idle
= USEC_INFINITY
;
69 static bool arg_timeout_idle_set
= false;
70 static char **arg_automount_property
= NULL
;
71 static int arg_bind_device
= -1;
72 static bool arg_fsck
= true;
73 static bool arg_aggressive_gc
= false;
75 static void help(void) {
76 printf("systemd-mount [OPTIONS...] WHAT [WHERE]\n"
77 "systemd-mount [OPTIONS...] --list\n"
78 "%s [OPTIONS...] %sWHAT|WHERE...\n\n"
79 "Establish a mount or auto-mount point transiently.\n\n"
80 " -h --help Show this help\n"
81 " --version Show package version\n"
82 " --no-block Do not wait until operation finished\n"
83 " --no-pager Do not pipe output into a pager\n"
84 " --no-ask-password Do not prompt for password\n"
85 " -q --quiet Suppress information messages during runtime\n"
86 " --user Run as user unit\n"
87 " -H --host=[USER@]HOST Operate on remote host\n"
88 " -M --machine=CONTAINER Operate on local container\n"
89 " --discover Discover mount device metadata\n"
90 " -t --type=TYPE File system type\n"
91 " -o --options=OPTIONS Mount options\n"
92 " --fsck=no Don't run file system check before mount\n"
93 " --description=TEXT Description for unit\n"
94 " -p --property=NAME=VALUE Set mount unit property\n"
95 " -A --automount=BOOL Create an auto-mount point\n"
96 " --timeout-idle-sec=SEC Specify automount idle timeout\n"
97 " --automount-property=NAME=VALUE\n"
98 " Set automount unit property\n"
99 " --bind-device Bind automount unit to device\n"
100 " --list List mountable block devices\n"
101 " -u --umount Unmount mount points\n"
102 " -G --collect Unload unit after it stopped, even when failed\n",
103 program_invocation_short_name
,
104 streq(program_invocation_short_name
, "systemd-umount") ? "" : "--umount ");
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' },
152 { "collect", no_argument
, NULL
, 'G' },
161 if (strstr(program_invocation_short_name
, "systemd-umount"))
162 arg_action
= ACTION_UMOUNT
;
164 while ((c
= getopt_long(argc
, argv
, "hqH:M:t:o:p:AuG", options
, NULL
)) >= 0)
183 case ARG_NO_ASK_PASSWORD
:
184 arg_ask_password
= false;
200 arg_transport
= BUS_TRANSPORT_REMOTE
;
205 arg_transport
= BUS_TRANSPORT_MACHINE
;
214 if (free_and_strdup(&arg_mount_type
, optarg
) < 0)
219 if (free_and_strdup(&arg_mount_options
, optarg
) < 0)
224 r
= parse_boolean(optarg
);
226 return log_error_errno(r
, "Failed to parse --fsck= argument: %s", optarg
);
231 case ARG_DESCRIPTION
:
232 if (free_and_strdup(&arg_description
, optarg
) < 0)
237 if (strv_extend(&arg_property
, optarg
) < 0)
243 arg_action
= ACTION_AUTOMOUNT
;
247 r
= parse_boolean(optarg
);
249 return log_error_errno(r
, "--automount= expects a valid boolean parameter: %s", optarg
);
251 arg_action
= r
? ACTION_AUTOMOUNT
: ACTION_MOUNT
;
254 case ARG_TIMEOUT_IDLE
:
255 r
= parse_sec(optarg
, &arg_timeout_idle
);
257 return log_error_errno(r
, "Failed to parse timeout: %s", optarg
);
261 case ARG_AUTOMOUNT_PROPERTY
:
262 if (strv_extend(&arg_automount_property
, optarg
) < 0)
267 case ARG_BIND_DEVICE
:
268 arg_bind_device
= true;
272 arg_action
= ACTION_LIST
;
276 arg_action
= ACTION_UMOUNT
;
280 arg_aggressive_gc
= true;
287 assert_not_reached("Unhandled option");
290 if (arg_user
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
291 log_error("Execution in user context is not supported on non-local systems.");
295 if (arg_action
== ACTION_LIST
) {
297 log_error("Too many arguments.");
301 if (arg_transport
!= BUS_TRANSPORT_LOCAL
) {
302 log_error("Listing devices only supported locally.");
305 } else if (arg_action
== ACTION_UMOUNT
) {
306 if (optind
>= argc
) {
307 log_error("At least one argument required.");
311 if (arg_transport
!= BUS_TRANSPORT_LOCAL
) {
314 for (i
= optind
; i
< argc
; i
++)
315 if (!path_is_absolute(argv
[i
]) ) {
316 log_error("Only absolute path is supported: %s", argv
[i
]);
321 if (optind
>= argc
) {
322 log_error("At least one argument required.");
326 if (argc
> optind
+2) {
327 log_error("At most two arguments required.");
331 if (arg_mount_type
&& (fstype_is_api_vfs(arg_mount_type
) || fstype_is_network(arg_mount_type
))) {
332 arg_mount_what
= strdup(argv
[optind
]);
336 } else if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
337 _cleanup_free_
char *u
= NULL
;
339 u
= fstab_node_to_udev_node(argv
[optind
]);
343 r
= chase_symlinks(u
, NULL
, 0, &arg_mount_what
);
345 return log_error_errno(r
, "Failed to make path %s absolute: %m", u
);
347 arg_mount_what
= strdup(argv
[optind
]);
351 path_kill_slashes(arg_mount_what
);
353 if (!path_is_absolute(arg_mount_what
)) {
354 log_error("Only absolute path is supported: %s", arg_mount_what
);
359 if (argc
> optind
+1) {
360 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
361 r
= chase_symlinks(argv
[optind
+1], NULL
, CHASE_NONEXISTENT
, &arg_mount_where
);
363 return log_error_errno(r
, "Failed to make path %s absolute: %m", argv
[optind
+1]);
365 arg_mount_where
= strdup(argv
[optind
+1]);
366 if (!arg_mount_where
)
369 path_kill_slashes(arg_mount_where
);
371 if (!path_is_absolute(arg_mount_where
)) {
372 log_error("Only absolute path is supported: %s", arg_mount_where
);
379 if (arg_discover
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
380 log_error("Automatic mount location discovery is only supported locally.");
388 static int transient_unit_set_properties(sd_bus_message
*m
, char **properties
) {
391 if (!isempty(arg_description
)) {
392 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", arg_description
);
397 if (arg_bind_device
&& is_device_path(arg_mount_what
)) {
398 _cleanup_free_
char *device_unit
= NULL
;
400 r
= unit_name_from_path(arg_mount_what
, ".device", &device_unit
);
404 r
= sd_bus_message_append(m
, "(sv)(sv)",
405 "After", "as", 1, device_unit
,
406 "BindsTo", "as", 1, device_unit
);
411 if (arg_aggressive_gc
) {
412 r
= sd_bus_message_append(m
, "(sv)", "CollectMode", "s", "inactive-or-failed");
417 r
= bus_append_unit_property_assignment_many(m
, properties
);
424 static int transient_mount_set_properties(sd_bus_message
*m
) {
429 r
= transient_unit_set_properties(m
, arg_property
);
433 if (arg_mount_what
) {
434 r
= sd_bus_message_append(m
, "(sv)", "What", "s", arg_mount_what
);
439 if (arg_mount_type
) {
440 r
= sd_bus_message_append(m
, "(sv)", "Type", "s", arg_mount_type
);
445 if (arg_mount_options
) {
446 r
= sd_bus_message_append(m
, "(sv)", "Options", "s", arg_mount_options
);
452 _cleanup_free_
char *fsck
= NULL
;
454 r
= unit_name_from_path_instance("systemd-fsck", arg_mount_what
, ".service", &fsck
);
458 r
= sd_bus_message_append(m
,
460 "Requires", "as", 1, fsck
,
461 "After", "as", 1, fsck
);
469 static int transient_automount_set_properties(sd_bus_message
*m
) {
474 r
= transient_unit_set_properties(m
, arg_automount_property
);
478 if (arg_timeout_idle
!= USEC_INFINITY
) {
479 r
= sd_bus_message_append(m
, "(sv)", "TimeoutIdleUSec", "t", arg_timeout_idle
);
487 static int start_transient_mount(
491 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
492 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
493 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
494 _cleanup_free_
char *mount_unit
= NULL
;
498 r
= bus_wait_for_jobs_new(bus
, &w
);
500 return log_error_errno(r
, "Could not watch jobs: %m");
503 r
= unit_name_from_path(arg_mount_where
, ".mount", &mount_unit
);
505 return log_error_errno(r
, "Failed to make mount unit name: %m");
507 r
= sd_bus_message_new_method_call(
510 "org.freedesktop.systemd1",
511 "/org/freedesktop/systemd1",
512 "org.freedesktop.systemd1.Manager",
513 "StartTransientUnit");
515 return bus_log_create_error(r
);
517 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
519 return bus_log_create_error(r
);
522 r
= sd_bus_message_append(m
, "ss", mount_unit
, "fail");
524 return bus_log_create_error(r
);
527 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
529 return bus_log_create_error(r
);
531 r
= transient_mount_set_properties(m
);
533 return bus_log_create_error(r
);
535 r
= sd_bus_message_close_container(m
);
537 return bus_log_create_error(r
);
539 /* Auxiliary units */
540 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
542 return bus_log_create_error(r
);
544 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
546 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
548 return log_error_errno(r
, "Failed to start transient mount unit: %s", bus_error_message(&error
, r
));
553 r
= sd_bus_message_read(reply
, "o", &object
);
555 return bus_log_parse_error(r
);
557 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
563 log_info("Started unit %s%s%s for mount point: %s%s%s",
564 ansi_highlight(), mount_unit
, ansi_normal(),
565 ansi_highlight(), arg_mount_where
, ansi_normal());
570 static int start_transient_automount(
574 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
575 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
576 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
577 _cleanup_free_
char *automount_unit
= NULL
, *mount_unit
= NULL
;
581 r
= bus_wait_for_jobs_new(bus
, &w
);
583 return log_error_errno(r
, "Could not watch jobs: %m");
586 r
= unit_name_from_path(arg_mount_where
, ".automount", &automount_unit
);
588 return log_error_errno(r
, "Failed to make automount unit name: %m");
590 r
= unit_name_from_path(arg_mount_where
, ".mount", &mount_unit
);
592 return log_error_errno(r
, "Failed to make mount unit name: %m");
594 r
= sd_bus_message_new_method_call(
597 "org.freedesktop.systemd1",
598 "/org/freedesktop/systemd1",
599 "org.freedesktop.systemd1.Manager",
600 "StartTransientUnit");
602 return bus_log_create_error(r
);
604 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
606 return bus_log_create_error(r
);
609 r
= sd_bus_message_append(m
, "ss", automount_unit
, "fail");
611 return bus_log_create_error(r
);
614 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
616 return bus_log_create_error(r
);
618 r
= transient_automount_set_properties(m
);
620 return bus_log_create_error(r
);
622 r
= sd_bus_message_close_container(m
);
624 return bus_log_create_error(r
);
626 /* Auxiliary units */
627 r
= sd_bus_message_open_container(m
, 'a', "(sa(sv))");
629 return bus_log_create_error(r
);
631 r
= sd_bus_message_open_container(m
, 'r', "sa(sv)");
633 return bus_log_create_error(r
);
635 r
= sd_bus_message_append(m
, "s", mount_unit
);
637 return bus_log_create_error(r
);
639 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
641 return bus_log_create_error(r
);
643 r
= transient_mount_set_properties(m
);
645 return bus_log_create_error(r
);
647 r
= sd_bus_message_close_container(m
);
649 return bus_log_create_error(r
);
651 r
= sd_bus_message_close_container(m
);
653 return bus_log_create_error(r
);
655 r
= sd_bus_message_close_container(m
);
657 return bus_log_create_error(r
);
659 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
661 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
663 return log_error_errno(r
, "Failed to start transient automount unit: %s", bus_error_message(&error
, r
));
668 r
= sd_bus_message_read(reply
, "o", &object
);
670 return bus_log_parse_error(r
);
672 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
678 log_info("Started unit %s%s%s for mount point: %s%s%s",
679 ansi_highlight(), automount_unit
, ansi_normal(),
680 ansi_highlight(), arg_mount_where
, ansi_normal());
685 static int find_mount_points(const char *what
, char ***list
) {
686 _cleanup_fclose_
FILE *proc_self_mountinfo
= NULL
;
687 _cleanup_strv_free_
char **l
= NULL
;
688 size_t bufsize
= 0, n
= 0;
693 /* Returns all mount points obtained from /proc/self/mountinfo in *list,
694 * and the number of mount points as return value. */
696 proc_self_mountinfo
= fopen("/proc/self/mountinfo", "re");
697 if (!proc_self_mountinfo
)
698 return log_error_errno(errno
, "Can't open /proc/self/mountinfo: %m");
701 _cleanup_free_
char *path
= NULL
, *where
= NULL
, *dev
= NULL
;
704 r
= fscanf(proc_self_mountinfo
,
705 "%*s " /* (1) mount id */
706 "%*s " /* (2) parent id */
707 "%*s " /* (3) major:minor */
708 "%*s " /* (4) root */
709 "%ms " /* (5) mount point */
710 "%*s" /* (6) mount options */
711 "%*[^-]" /* (7) optional fields */
712 "- " /* (8) separator */
713 "%*s " /* (9) file system type */
714 "%ms" /* (10) mount source */
715 "%*s" /* (11) mount options 2 */
716 "%*[^\n]", /* some rubbish at the end */
725 if (!streq(what
, dev
))
728 r
= cunescape(path
, UNESCAPE_RELAX
, &where
);
732 /* one extra slot is needed for the terminating NULL */
733 if (!GREEDY_REALLOC(l
, bufsize
, n
+ 2))
740 if (!GREEDY_REALLOC(l
, bufsize
, n
+ 1))
745 l
= NULL
; /* avoid freeing */
750 static int find_loop_device(const char *backing_file
, char **loop_dev
) {
751 _cleanup_closedir_
DIR *d
= NULL
;
753 _cleanup_free_
char *l
= NULL
;
755 assert(backing_file
);
758 d
= opendir("/sys/devices/virtual/block");
762 FOREACH_DIRENT(de
, d
, return -errno
) {
763 _cleanup_free_
char *sys
= NULL
, *fname
= NULL
;
766 dirent_ensure_type(d
, de
);
768 if (de
->d_type
!= DT_DIR
)
771 if (!startswith(de
->d_name
, "loop"))
774 sys
= strjoin("/sys/devices/virtual/block/", de
->d_name
, "/loop/backing_file");
778 r
= read_one_line_file(sys
, &fname
);
780 log_debug_errno(r
, "Failed to read %s, ignoring: %m", sys
);
784 if (files_same(fname
, backing_file
, 0) <= 0)
787 l
= strjoin("/dev/", de
->d_name
);
798 l
= NULL
; /* avoid freeing */
803 static int stop_mount(
806 const char *suffix
) {
808 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
809 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
810 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
811 _cleanup_free_
char *mount_unit
= NULL
;
815 r
= bus_wait_for_jobs_new(bus
, &w
);
817 return log_error_errno(r
, "Could not watch jobs: %m");
820 r
= unit_name_from_path(where
, suffix
, &mount_unit
);
822 return log_error_errno(r
, "Failed to make %s unit name from path %s: %m", suffix
+ 1, where
);
824 r
= sd_bus_message_new_method_call(
827 "org.freedesktop.systemd1",
828 "/org/freedesktop/systemd1",
829 "org.freedesktop.systemd1.Manager",
832 return bus_log_create_error(r
);
834 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
836 return bus_log_create_error(r
);
839 r
= sd_bus_message_append(m
, "ss", mount_unit
, "fail");
841 return bus_log_create_error(r
);
843 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
845 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
847 if (streq(suffix
, ".automount") &&
848 sd_bus_error_has_name(&error
, "org.freedesktop.systemd1.NoSuchUnit"))
850 return log_error_errno(r
, "Failed to stop %s unit: %s", suffix
+ 1, bus_error_message(&error
, r
));
856 r
= sd_bus_message_read(reply
, "o", &object
);
858 return bus_log_parse_error(r
);
860 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
866 log_info("Stopped unit %s%s%s for mount point: %s%s%s",
867 ansi_highlight(), mount_unit
, ansi_normal(),
868 ansi_highlight(), where
, ansi_normal());
873 static int stop_mounts(
879 if (path_equal(where
, "/")) {
880 log_error("Refusing to operate on root directory: %s", where
);
884 if (!path_is_normalized(where
)) {
885 log_error("Path contains non-normalized components: %s", where
);
889 r
= stop_mount(bus
, where
, ".mount");
893 r
= stop_mount(bus
, where
, ".automount");
900 static int umount_by_device(sd_bus
*bus
, const char *what
) {
901 _cleanup_udev_device_unref_
struct udev_device
*d
= NULL
;
902 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
903 _cleanup_strv_free_
char **list
= NULL
;
911 if (stat(what
, &st
) < 0)
912 return log_error_errno(errno
, "Can't stat %s: %m", what
);
914 if (!S_ISBLK(st
.st_mode
)) {
915 log_error("Not a block device: %s", what
);
923 d
= udev_device_new_from_devnum(udev
, 'b', st
.st_rdev
);
927 v
= udev_device_get_property_value(d
, "ID_FS_USAGE");
928 if (!streq_ptr(v
, "filesystem")) {
929 log_error("%s does not contain a known file system.", what
);
933 v
= udev_device_get_property_value(d
, "SYSTEMD_MOUNT_WHERE");
935 r2
= stop_mounts(bus
, v
);
937 r
= find_mount_points(what
, &list
);
941 for (l
= list
; *l
; l
++) {
942 r
= stop_mounts(bus
, *l
);
950 static int umount_loop(sd_bus
*bus
, const char *backing_file
) {
951 _cleanup_free_
char *loop_dev
= NULL
;
954 assert(backing_file
);
956 r
= find_loop_device(backing_file
, &loop_dev
);
958 return log_error_errno(r
, r
== -ENXIO
? "File %s is not mounted." : "Can't get loop device for %s: %m", backing_file
);
960 return umount_by_device(bus
, loop_dev
);
963 static int action_umount(
970 if (arg_transport
!= BUS_TRANSPORT_LOCAL
) {
971 for (i
= optind
; i
< argc
; i
++) {
972 _cleanup_free_
char *p
= NULL
;
978 path_kill_slashes(p
);
980 r
= stop_mounts(bus
, p
);
987 for (i
= optind
; i
< argc
; i
++) {
988 _cleanup_free_
char *u
= NULL
, *p
= NULL
;
991 u
= fstab_node_to_udev_node(argv
[i
]);
995 r
= chase_symlinks(u
, NULL
, 0, &p
);
997 r2
= log_error_errno(r
, "Failed to make path %s absolute: %m", argv
[i
]);
1001 if (stat(p
, &st
) < 0)
1002 return log_error_errno(errno
, "Can't stat %s (from %s): %m", p
, argv
[i
]);
1004 if (S_ISBLK(st
.st_mode
))
1005 r
= umount_by_device(bus
, p
);
1006 else if (S_ISREG(st
.st_mode
))
1007 r
= umount_loop(bus
, p
);
1008 else if (S_ISDIR(st
.st_mode
))
1009 r
= stop_mounts(bus
, p
);
1011 log_error("Invalid file type: %s (from %s)", p
, argv
[i
]);
1022 static int acquire_mount_type(struct udev_device
*d
) {
1030 v
= udev_device_get_property_value(d
, "ID_FS_TYPE");
1034 arg_mount_type
= strdup(v
);
1035 if (!arg_mount_type
)
1038 log_debug("Discovered type=%s", arg_mount_type
);
1042 static int acquire_mount_options(struct udev_device
*d
) {
1045 if (arg_mount_options
)
1048 v
= udev_device_get_property_value(d
, "SYSTEMD_MOUNT_OPTIONS");
1052 arg_mount_options
= strdup(v
);
1053 if (!arg_mount_options
)
1056 log_debug("Discovered options=%s", arg_mount_options
);
1060 static const char *get_model(struct udev_device
*d
) {
1065 model
= udev_device_get_property_value(d
, "ID_MODEL_FROM_DATABASE");
1069 return udev_device_get_property_value(d
, "ID_MODEL");
1072 static const char* get_label(struct udev_device
*d
) {
1077 label
= udev_device_get_property_value(d
, "ID_FS_LABEL");
1081 return udev_device_get_property_value(d
, "ID_PART_ENTRY_NAME");
1084 static int acquire_mount_where(struct udev_device
*d
) {
1087 if (arg_mount_where
)
1090 v
= udev_device_get_property_value(d
, "SYSTEMD_MOUNT_WHERE");
1092 _cleanup_free_
char *escaped
= NULL
;
1095 name
= get_label(d
);
1097 name
= get_model(d
);
1101 dn
= udev_device_get_devnode(d
);
1105 name
= basename(dn
);
1108 escaped
= xescape(name
, "\\");
1111 if (!filename_is_valid(escaped
))
1114 arg_mount_where
= strjoin("/run/media/system/", escaped
);
1116 arg_mount_where
= strdup(v
);
1118 if (!arg_mount_where
)
1121 log_debug("Discovered where=%s", arg_mount_where
);
1125 static int acquire_mount_where_for_loop_dev(const char *loop_dev
) {
1126 _cleanup_strv_free_
char **list
= NULL
;
1129 if (arg_mount_where
)
1132 r
= find_mount_points(loop_dev
, &list
);
1136 log_error("Can't find mount point of %s. It is expected that %s is already mounted on a place.", loop_dev
, loop_dev
);
1138 } else if (r
>= 2) {
1139 log_error("%s is mounted on %d places. It is expected that %s is mounted on a place.", loop_dev
, r
, loop_dev
);
1143 arg_mount_where
= strdup(list
[0]);
1144 if (!arg_mount_where
)
1147 log_debug("Discovered where=%s", arg_mount_where
);
1151 static int acquire_description(struct udev_device
*d
) {
1152 const char *model
, *label
;
1154 if (arg_description
)
1157 model
= get_model(d
);
1159 label
= get_label(d
);
1161 label
= udev_device_get_property_value(d
, "ID_PART_ENTRY_NUMBER");
1164 arg_description
= strjoin(model
, " ", label
);
1166 arg_description
= strdup(label
);
1168 arg_description
= strdup(model
);
1172 if (!arg_description
)
1175 log_debug("Discovered description=%s", arg_description
);
1179 static int acquire_removable(struct udev_device
*d
) {
1182 /* Shortcut this if there's no reason to check it */
1183 if (arg_action
!= ACTION_DEFAULT
&& arg_timeout_idle_set
&& arg_bind_device
>= 0)
1187 v
= udev_device_get_sysattr_value(d
, "removable");
1191 d
= udev_device_get_parent(d
);
1195 if (!streq_ptr(udev_device_get_subsystem(d
), "block"))
1199 if (parse_boolean(v
) <= 0)
1202 log_debug("Discovered removable device.");
1204 if (arg_action
== ACTION_DEFAULT
) {
1205 log_debug("Automatically turning on automount.");
1206 arg_action
= ACTION_AUTOMOUNT
;
1209 if (!arg_timeout_idle_set
) {
1210 log_debug("Setting idle timeout to 1s.");
1211 arg_timeout_idle
= USEC_PER_SEC
;
1214 if (arg_bind_device
< 0) {
1215 log_debug("Binding automount unit to device.");
1216 arg_bind_device
= true;
1222 static int discover_loop_backing_file(void) {
1223 _cleanup_udev_device_unref_
struct udev_device
*d
= NULL
;
1224 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
1225 _cleanup_free_
char *loop_dev
= NULL
;
1230 r
= find_loop_device(arg_mount_what
, &loop_dev
);
1231 if (r
< 0 && r
!= -ENXIO
)
1232 return log_error_errno(errno
, "Can't get loop device for %s: %m", arg_mount_what
);
1235 _cleanup_free_
char *escaped
= NULL
;
1237 if (arg_mount_where
)
1240 escaped
= xescape(basename(arg_mount_what
), "\\");
1243 if (!filename_is_valid(escaped
)) {
1244 log_error("Escaped name %s is not a valid filename.", escaped
);
1248 arg_mount_where
= strjoin("/run/media/system/", escaped
);
1249 if (!arg_mount_where
)
1252 log_debug("Discovered where=%s", arg_mount_where
);
1256 if (stat(loop_dev
, &st
) < 0)
1257 return log_error_errno(errno
, "Can't stat %s: %m", loop_dev
);
1259 if (!S_ISBLK(st
.st_mode
)) {
1260 log_error("Invalid file type: %s", loop_dev
);
1268 d
= udev_device_new_from_devnum(udev
, 'b', st
.st_rdev
);
1272 v
= udev_device_get_property_value(d
, "ID_FS_USAGE");
1273 if (!streq_ptr(v
, "filesystem")) {
1274 log_error("%s does not contain a known file system.", arg_mount_what
);
1278 r
= acquire_mount_type(d
);
1282 r
= acquire_mount_options(d
);
1286 r
= acquire_mount_where_for_loop_dev(loop_dev
);
1290 r
= acquire_description(d
);
1297 static int discover_device(void) {
1298 _cleanup_udev_device_unref_
struct udev_device
*d
= NULL
;
1299 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
1304 if (stat(arg_mount_what
, &st
) < 0)
1305 return log_error_errno(errno
, "Can't stat %s: %m", arg_mount_what
);
1307 if (S_ISREG(st
.st_mode
))
1308 return discover_loop_backing_file();
1310 if (!S_ISBLK(st
.st_mode
)) {
1311 log_error("Invalid file type: %s", arg_mount_what
);
1319 d
= udev_device_new_from_devnum(udev
, 'b', st
.st_rdev
);
1323 v
= udev_device_get_property_value(d
, "ID_FS_USAGE");
1324 if (!streq_ptr(v
, "filesystem")) {
1325 log_error("%s does not contain a known file system.", arg_mount_what
);
1329 r
= acquire_mount_type(d
);
1333 r
= acquire_mount_options(d
);
1337 r
= acquire_mount_where(d
);
1341 r
= acquire_description(d
);
1345 r
= acquire_removable(d
);
1364 char* columns
[_COLUMN_MAX
];
1367 static int compare_item(const void *a
, const void *b
) {
1368 const struct item
*x
= a
, *y
= b
;
1370 if (x
->columns
[COLUMN_NODE
] == y
->columns
[COLUMN_NODE
])
1372 if (!x
->columns
[COLUMN_NODE
])
1374 if (!y
->columns
[COLUMN_NODE
])
1377 return path_compare(x
->columns
[COLUMN_NODE
], y
->columns
[COLUMN_NODE
]);
1380 static int list_devices(void) {
1382 static const char * const titles
[_COLUMN_MAX
] = {
1383 [COLUMN_NODE
] = "NODE",
1384 [COLUMN_PATH
] = "PATH",
1385 [COLUMN_MODEL
] = "MODEL",
1386 [COLUMN_WWN
] = "WWN",
1387 [COLUMN_FSTYPE
] = "TYPE",
1388 [COLUMN_LABEL
] = "LABEL",
1389 [COLUMN_UUID
] = "UUID"
1392 _cleanup_udev_enumerate_unref_
struct udev_enumerate
*e
= NULL
;
1393 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
1394 struct udev_list_entry
*item
= NULL
, *first
= NULL
;
1395 size_t n_allocated
= 0, n
= 0, i
;
1396 size_t column_width
[_COLUMN_MAX
];
1397 struct item
*items
= NULL
;
1401 for (c
= 0; c
< _COLUMN_MAX
; c
++)
1402 column_width
[c
] = strlen(titles
[c
]);
1408 e
= udev_enumerate_new(udev
);
1412 r
= udev_enumerate_add_match_subsystem(e
, "block");
1414 return log_error_errno(r
, "Failed to add block match: %m");
1416 r
= udev_enumerate_add_match_property(e
, "ID_FS_USAGE", "filesystem");
1418 return log_error_errno(r
, "Failed to add property match: %m");
1420 r
= udev_enumerate_scan_devices(e
);
1422 return log_error_errno(r
, "Failed to scan devices: %m");
1424 first
= udev_enumerate_get_list_entry(e
);
1425 udev_list_entry_foreach(item
, first
) {
1426 _cleanup_udev_device_unref_
struct udev_device
*d
;
1429 d
= udev_device_new_from_syspath(udev
, udev_list_entry_get_name(item
));
1435 if (!GREEDY_REALLOC0(items
, n_allocated
, n
+1)) {
1442 for (c
= 0; c
< _COLUMN_MAX
; c
++) {
1443 const char *x
= NULL
;
1449 x
= udev_device_get_devnode(d
);
1453 x
= udev_device_get_property_value(d
, "ID_PATH");
1461 x
= udev_device_get_property_value(d
, "ID_WWN");
1465 x
= udev_device_get_property_value(d
, "ID_FS_TYPE");
1473 x
= udev_device_get_property_value(d
, "ID_FS_UUID");
1480 j
->columns
[c
] = strdup(x
);
1481 if (!j
->columns
[c
]) {
1487 if (k
> column_width
[c
])
1488 column_width
[c
] = k
;
1493 log_info("No devices found.");
1497 qsort_safe(items
, n
, sizeof(struct item
), compare_item
);
1499 pager_open(arg_no_pager
, false);
1501 fputs(ansi_underline(), stdout
);
1502 for (c
= 0; c
< _COLUMN_MAX
; c
++) {
1506 printf("%-*s", (int) column_width
[c
], titles
[c
]);
1508 fputs(ansi_normal(), stdout
);
1509 fputc('\n', stdout
);
1511 for (i
= 0; i
< n
; i
++) {
1512 for (c
= 0; c
< _COLUMN_MAX
; c
++) {
1516 printf("%-*s", (int) column_width
[c
], strna(items
[i
].columns
[c
]));
1518 fputc('\n', stdout
);
1524 for (i
= 0; i
< n
; i
++)
1525 for (c
= 0; c
< _COLUMN_MAX
; c
++)
1526 free(items
[i
].columns
[c
]);
1532 int main(int argc
, char* argv
[]) {
1533 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1536 log_parse_environment();
1539 r
= parse_argv(argc
, argv
);
1543 if (arg_action
== ACTION_LIST
) {
1548 r
= bus_connect_transport_systemd(arg_transport
, arg_host
, arg_user
, &bus
);
1550 log_error_errno(r
, "Failed to create bus connection: %m");
1554 if (arg_action
== ACTION_UMOUNT
) {
1555 r
= action_umount(bus
, argc
, argv
);
1559 if (!path_is_normalized(arg_mount_what
)) {
1560 log_error("Path contains non-normalized components: %s", arg_mount_what
);
1566 r
= discover_device();
1571 if (!arg_mount_where
) {
1572 log_error("Can't figure out where to mount %s.", arg_mount_what
);
1577 if (path_equal(arg_mount_where
, "/")) {
1578 log_error("Refusing to operate on root directory.");
1583 if (!path_is_normalized(arg_mount_where
)) {
1584 log_error("Path contains non-normalized components: %s", arg_mount_where
);
1589 if (streq_ptr(arg_mount_type
, "auto"))
1590 arg_mount_type
= mfree(arg_mount_type
);
1591 if (streq_ptr(arg_mount_options
, "defaults"))
1592 arg_mount_options
= mfree(arg_mount_options
);
1594 if (!is_device_path(arg_mount_what
))
1597 if (arg_fsck
&& arg_mount_type
&& arg_transport
== BUS_TRANSPORT_LOCAL
) {
1598 r
= fsck_exists(arg_mount_type
);
1600 log_warning_errno(r
, "Couldn't determine whether fsck for %s exists, proceeding anyway.", arg_mount_type
);
1602 log_debug("Disabling file system check as fsck for %s doesn't exist.", arg_mount_type
);
1603 arg_fsck
= false; /* fsck doesn't exist, let's not attempt it */
1607 switch (arg_action
) {
1610 case ACTION_DEFAULT
:
1611 r
= start_transient_mount(bus
, argv
+ optind
);
1614 case ACTION_AUTOMOUNT
:
1615 r
= start_transient_automount(bus
, argv
+ optind
);
1619 assert_not_reached("Unexpected action.");
1625 free(arg_mount_what
);
1626 free(arg_mount_where
);
1627 free(arg_mount_type
);
1628 free(arg_mount_options
);
1629 free(arg_description
);
1630 strv_free(arg_property
);
1631 strv_free(arg_automount_property
);
1633 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;