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"
33 #include "fstab-util.h"
34 #include "mount-util.h"
36 #include "parse-util.h"
37 #include "path-util.h"
38 #include "spawn-polkit-agent.h"
39 #include "stat-util.h"
41 #include "udev-util.h"
42 #include "unit-name.h"
43 #include "terminal-util.h"
51 } arg_action
= ACTION_DEFAULT
;
53 static bool arg_no_block
= false;
54 static bool arg_no_pager
= false;
55 static bool arg_ask_password
= true;
56 static bool arg_quiet
= false;
57 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
58 static bool arg_user
= false;
59 static const char *arg_host
= NULL
;
60 static bool arg_discover
= false;
61 static char *arg_mount_what
= NULL
;
62 static char *arg_mount_where
= NULL
;
63 static char *arg_mount_type
= NULL
;
64 static char *arg_mount_options
= NULL
;
65 static char *arg_description
= NULL
;
66 static char **arg_property
= NULL
;
67 static usec_t arg_timeout_idle
= USEC_INFINITY
;
68 static bool arg_timeout_idle_set
= false;
69 static char **arg_automount_property
= NULL
;
70 static int arg_bind_device
= -1;
71 static bool arg_fsck
= true;
72 static bool arg_aggressive_gc
= false;
74 static void help(void) {
75 printf("systemd-mount [OPTIONS...] WHAT [WHERE]\n"
76 "systemd-mount [OPTIONS...] --list\n"
77 "%s [OPTIONS...] %sWHAT|WHERE...\n\n"
78 "Establish a mount or auto-mount point transiently.\n\n"
79 " -h --help Show this help\n"
80 " --version Show package version\n"
81 " --no-block Do not wait until operation finished\n"
82 " --no-pager Do not pipe output into a pager\n"
83 " --no-ask-password Do not prompt for password\n"
84 " -q --quiet Suppress information messages during runtime\n"
85 " --user Run as user unit\n"
86 " -H --host=[USER@]HOST Operate on remote host\n"
87 " -M --machine=CONTAINER Operate on local container\n"
88 " --discover Discover mount device metadata\n"
89 " -t --type=TYPE File system type\n"
90 " -o --options=OPTIONS Mount options\n"
91 " --fsck=no Don't run file system check before mount\n"
92 " --description=TEXT Description for unit\n"
93 " -p --property=NAME=VALUE Set mount unit property\n"
94 " -A --automount=BOOL Create an auto-mount point\n"
95 " --timeout-idle-sec=SEC Specify automount idle timeout\n"
96 " --automount-property=NAME=VALUE\n"
97 " Set automount unit property\n"
98 " --bind-device Bind automount unit to device\n"
99 " --list List mountable block devices\n"
100 " -u --umount Unmount mount points\n"
101 " -G --collect Unload unit after it stopped, even when failed\n",
102 program_invocation_short_name
,
103 streq(program_invocation_short_name
, "systemd-umount") ? "" : "--umount ");
106 static int parse_argv(int argc
, char *argv
[]) {
122 ARG_AUTOMOUNT_PROPERTY
,
127 static const struct option options
[] = {
128 { "help", no_argument
, NULL
, 'h' },
129 { "version", no_argument
, NULL
, ARG_VERSION
},
130 { "no-block", no_argument
, NULL
, ARG_NO_BLOCK
},
131 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
132 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
133 { "quiet", no_argument
, NULL
, 'q' },
134 { "user", no_argument
, NULL
, ARG_USER
},
135 { "system", no_argument
, NULL
, ARG_SYSTEM
},
136 { "host", required_argument
, NULL
, 'H' },
137 { "machine", required_argument
, NULL
, 'M' },
138 { "discover", no_argument
, NULL
, ARG_DISCOVER
},
139 { "type", required_argument
, NULL
, 't' },
140 { "options", required_argument
, NULL
, 'o' },
141 { "fsck", required_argument
, NULL
, ARG_FSCK
},
142 { "description", required_argument
, NULL
, ARG_DESCRIPTION
},
143 { "property", required_argument
, NULL
, 'p' },
144 { "automount", required_argument
, NULL
, ARG_AUTOMOUNT
},
145 { "timeout-idle-sec", required_argument
, NULL
, ARG_TIMEOUT_IDLE
},
146 { "automount-property", required_argument
, NULL
, ARG_AUTOMOUNT_PROPERTY
},
147 { "bind-device", no_argument
, NULL
, ARG_BIND_DEVICE
},
148 { "list", no_argument
, NULL
, ARG_LIST
},
149 { "umount", no_argument
, NULL
, 'u' },
150 { "unmount", no_argument
, NULL
, 'u' },
151 { "collect", no_argument
, NULL
, 'G' },
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:AuG", 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
;
279 arg_aggressive_gc
= true;
286 assert_not_reached("Unhandled option");
289 if (arg_user
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
290 log_error("Execution in user context is not supported on non-local systems.");
294 if (arg_action
== ACTION_LIST
) {
296 log_error("Too many arguments.");
300 if (arg_transport
!= BUS_TRANSPORT_LOCAL
) {
301 log_error("Listing devices only supported locally.");
304 } else if (arg_action
== ACTION_UMOUNT
) {
305 if (optind
>= argc
) {
306 log_error("At least one argument required.");
310 if (arg_transport
!= BUS_TRANSPORT_LOCAL
) {
313 for (i
= optind
; i
< argc
; i
++)
314 if (!path_is_absolute(argv
[i
]) ) {
315 log_error("Only absolute path is supported: %s", argv
[i
]);
320 if (optind
>= argc
) {
321 log_error("At least one argument required.");
325 if (argc
> optind
+2) {
326 log_error("At most two arguments required.");
330 if (arg_mount_type
&& (fstype_is_api_vfs(arg_mount_type
) || fstype_is_network(arg_mount_type
))) {
331 arg_mount_what
= strdup(argv
[optind
]);
335 } else if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
336 _cleanup_free_
char *u
= NULL
, *p
= NULL
;
338 u
= fstab_node_to_udev_node(argv
[optind
]);
342 r
= path_make_absolute_cwd(u
, &p
);
344 return log_error_errno(r
, "Failed to make path %s absolute: %m", u
);
346 arg_mount_what
= canonicalize_file_name(p
);
348 return log_error_errno(errno
, "Failed to canonicalize path %s: %m", p
);
350 arg_mount_what
= strdup(argv
[optind
]);
354 path_kill_slashes(arg_mount_what
);
356 if (!path_is_absolute(arg_mount_what
)) {
357 log_error("Only absolute path is supported: %s", arg_mount_what
);
362 if (argc
> optind
+1) {
363 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
364 _cleanup_free_
char *p
= NULL
;
366 r
= path_make_absolute_cwd(argv
[optind
+1], &p
);
368 return log_error_errno(r
, "Failed to make path %s absolute: %m", argv
[optind
+1]);
370 arg_mount_where
= canonicalize_file_name(p
);
371 if (!arg_mount_where
)
372 return log_error_errno(errno
, "Failed to canonicalize path %s: %m", p
);
375 arg_mount_where
= strdup(argv
[optind
+1]);
376 if (!arg_mount_where
)
379 path_kill_slashes(arg_mount_where
);
381 if (!path_is_absolute(arg_mount_where
)) {
382 log_error("Only absolute path is supported: %s", arg_mount_where
);
389 if (arg_discover
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
390 log_error("Automatic mount location discovery is only supported locally.");
398 static int transient_unit_set_properties(sd_bus_message
*m
, char **properties
) {
401 if (!isempty(arg_description
)) {
402 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", arg_description
);
407 if (arg_bind_device
&& is_device_path(arg_mount_what
)) {
408 _cleanup_free_
char *device_unit
= NULL
;
410 r
= unit_name_from_path(arg_mount_what
, ".device", &device_unit
);
414 r
= sd_bus_message_append(m
, "(sv)(sv)",
415 "After", "as", 1, device_unit
,
416 "BindsTo", "as", 1, device_unit
);
421 if (arg_aggressive_gc
) {
422 r
= sd_bus_message_append(m
, "(sv)", "CollectMode", "s", "inactive-or-failed");
427 r
= bus_append_unit_property_assignment_many(m
, properties
);
434 static int transient_mount_set_properties(sd_bus_message
*m
) {
439 r
= transient_unit_set_properties(m
, arg_property
);
443 if (arg_mount_what
) {
444 r
= sd_bus_message_append(m
, "(sv)", "What", "s", arg_mount_what
);
449 if (arg_mount_type
) {
450 r
= sd_bus_message_append(m
, "(sv)", "Type", "s", arg_mount_type
);
455 if (arg_mount_options
) {
456 r
= sd_bus_message_append(m
, "(sv)", "Options", "s", arg_mount_options
);
462 _cleanup_free_
char *fsck
= NULL
;
464 r
= unit_name_from_path_instance("systemd-fsck", arg_mount_what
, ".service", &fsck
);
468 r
= sd_bus_message_append(m
,
470 "Requires", "as", 1, fsck
,
471 "After", "as", 1, fsck
);
479 static int transient_automount_set_properties(sd_bus_message
*m
) {
484 r
= transient_unit_set_properties(m
, arg_automount_property
);
488 if (arg_timeout_idle
!= USEC_INFINITY
) {
489 r
= sd_bus_message_append(m
, "(sv)", "TimeoutIdleUSec", "t", arg_timeout_idle
);
497 static int start_transient_mount(
501 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
502 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
503 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
504 _cleanup_free_
char *mount_unit
= NULL
;
508 r
= bus_wait_for_jobs_new(bus
, &w
);
510 return log_error_errno(r
, "Could not watch jobs: %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.systemd1",
521 "/org/freedesktop/systemd1",
522 "org.freedesktop.systemd1.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", mount_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_mount_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_append(m
, "a(sa(sv))", 0);
552 return bus_log_create_error(r
);
554 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
556 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
558 return log_error_errno(r
, "Failed to start transient mount unit: %s", bus_error_message(&error
, r
));
563 r
= sd_bus_message_read(reply
, "o", &object
);
565 return bus_log_parse_error(r
);
567 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
573 log_info("Started unit %s%s%s for mount point: %s%s%s",
574 ansi_highlight(), mount_unit
, ansi_normal(),
575 ansi_highlight(), arg_mount_where
, ansi_normal());
580 static int start_transient_automount(
584 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
585 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
586 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
587 _cleanup_free_
char *automount_unit
= NULL
, *mount_unit
= NULL
;
591 r
= bus_wait_for_jobs_new(bus
, &w
);
593 return log_error_errno(r
, "Could not watch jobs: %m");
596 r
= unit_name_from_path(arg_mount_where
, ".automount", &automount_unit
);
598 return log_error_errno(r
, "Failed to make automount unit name: %m");
600 r
= unit_name_from_path(arg_mount_where
, ".mount", &mount_unit
);
602 return log_error_errno(r
, "Failed to make mount unit name: %m");
604 r
= sd_bus_message_new_method_call(
607 "org.freedesktop.systemd1",
608 "/org/freedesktop/systemd1",
609 "org.freedesktop.systemd1.Manager",
610 "StartTransientUnit");
612 return bus_log_create_error(r
);
614 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
616 return bus_log_create_error(r
);
619 r
= sd_bus_message_append(m
, "ss", automount_unit
, "fail");
621 return bus_log_create_error(r
);
624 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
626 return bus_log_create_error(r
);
628 r
= transient_automount_set_properties(m
);
630 return bus_log_create_error(r
);
632 r
= sd_bus_message_close_container(m
);
634 return bus_log_create_error(r
);
636 /* Auxiliary units */
637 r
= sd_bus_message_open_container(m
, 'a', "(sa(sv))");
639 return bus_log_create_error(r
);
641 r
= sd_bus_message_open_container(m
, 'r', "sa(sv)");
643 return bus_log_create_error(r
);
645 r
= sd_bus_message_append(m
, "s", mount_unit
);
647 return bus_log_create_error(r
);
649 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
651 return bus_log_create_error(r
);
653 r
= transient_mount_set_properties(m
);
655 return bus_log_create_error(r
);
657 r
= sd_bus_message_close_container(m
);
659 return bus_log_create_error(r
);
661 r
= sd_bus_message_close_container(m
);
663 return bus_log_create_error(r
);
665 r
= sd_bus_message_close_container(m
);
667 return bus_log_create_error(r
);
669 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
671 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
673 return log_error_errno(r
, "Failed to start transient automount unit: %s", bus_error_message(&error
, r
));
678 r
= sd_bus_message_read(reply
, "o", &object
);
680 return bus_log_parse_error(r
);
682 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
688 log_info("Started unit %s%s%s for mount point: %s%s%s",
689 ansi_highlight(), automount_unit
, ansi_normal(),
690 ansi_highlight(), arg_mount_where
, ansi_normal());
695 static int find_mount_points(const char *what
, char ***list
) {
696 _cleanup_fclose_
FILE *proc_self_mountinfo
= NULL
;
697 _cleanup_strv_free_
char **l
= NULL
;
698 size_t bufsize
= 0, n
= 0;
703 /* Returns all mount points obtained from /proc/self/mountinfo in *list,
704 * and the number of mount points as return value. */
706 proc_self_mountinfo
= fopen("/proc/self/mountinfo", "re");
707 if (!proc_self_mountinfo
)
708 return log_error_errno(errno
, "Can't open /proc/self/mountinfo: %m");
711 _cleanup_free_
char *path
= NULL
, *where
= NULL
, *dev
= NULL
;
714 r
= fscanf(proc_self_mountinfo
,
715 "%*s " /* (1) mount id */
716 "%*s " /* (2) parent id */
717 "%*s " /* (3) major:minor */
718 "%*s " /* (4) root */
719 "%ms " /* (5) mount point */
720 "%*s" /* (6) mount options */
721 "%*[^-]" /* (7) optional fields */
722 "- " /* (8) separator */
723 "%*s " /* (9) file system type */
724 "%ms" /* (10) mount source */
725 "%*s" /* (11) mount options 2 */
726 "%*[^\n]", /* some rubbish at the end */
735 if (!streq(what
, dev
))
738 r
= cunescape(path
, UNESCAPE_RELAX
, &where
);
742 /* one extra slot is needed for the terminating NULL */
743 if (!GREEDY_REALLOC(l
, bufsize
, n
+ 2))
750 if (!GREEDY_REALLOC(l
, bufsize
, n
+ 1))
755 l
= NULL
; /* avoid freeing */
760 static int find_loop_device(const char *backing_file
, char **loop_dev
) {
761 _cleanup_closedir_
DIR *d
= NULL
;
763 _cleanup_free_
char *l
= NULL
;
765 assert(backing_file
);
768 d
= opendir("/sys/devices/virtual/block");
772 FOREACH_DIRENT(de
, d
, return -errno
) {
773 _cleanup_free_
char *sys
= NULL
, *fname
= NULL
;
776 dirent_ensure_type(d
, de
);
778 if (de
->d_type
!= DT_DIR
)
781 if (!startswith(de
->d_name
, "loop"))
784 sys
= strjoin("/sys/devices/virtual/block/", de
->d_name
, "/loop/backing_file");
788 r
= read_one_line_file(sys
, &fname
);
790 log_debug_errno(r
, "Failed to read %s, ignoring: %m", sys
);
794 if (files_same(fname
, backing_file
, 0) <= 0)
797 l
= strjoin("/dev/", de
->d_name
);
808 l
= NULL
; /* avoid freeing */
813 static int stop_mount(
816 const char *suffix
) {
818 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
819 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
820 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
821 _cleanup_free_
char *mount_unit
= NULL
;
825 r
= bus_wait_for_jobs_new(bus
, &w
);
827 return log_error_errno(r
, "Could not watch jobs: %m");
830 r
= unit_name_from_path(where
, suffix
, &mount_unit
);
832 return log_error_errno(r
, "Failed to make mount unit name from path %s: %m", where
);
834 r
= sd_bus_message_new_method_call(
837 "org.freedesktop.systemd1",
838 "/org/freedesktop/systemd1",
839 "org.freedesktop.systemd1.Manager",
842 return bus_log_create_error(r
);
844 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
846 return bus_log_create_error(r
);
849 r
= sd_bus_message_append(m
, "ss", mount_unit
, "fail");
851 return bus_log_create_error(r
);
853 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
855 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
857 return log_error_errno(r
, "Failed to stop mount unit: %s", bus_error_message(&error
, r
));
862 r
= sd_bus_message_read(reply
, "o", &object
);
864 return bus_log_parse_error(r
);
866 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
872 log_info("Stopped unit %s%s%s for mount point: %s%s%s",
873 ansi_highlight(), mount_unit
, ansi_normal(),
874 ansi_highlight(), where
, ansi_normal());
879 static int stop_mounts(
885 if (path_equal(where
, "/")) {
886 log_error("Refusing to operate on root directory: %s", where
);
890 if (!path_is_safe(where
)) {
891 log_error("Path contains unsafe components: %s", where
);
895 r
= stop_mount(bus
, where
, ".mount");
899 r
= stop_mount(bus
, where
, ".automount");
906 static int umount_by_device(sd_bus
*bus
, const char *what
) {
907 _cleanup_udev_device_unref_
struct udev_device
*d
= NULL
;
908 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
909 _cleanup_strv_free_
char **list
= NULL
;
917 if (stat(what
, &st
) < 0)
918 return log_error_errno(errno
, "Can't stat %s: %m", what
);
920 if (!S_ISBLK(st
.st_mode
)) {
921 log_error("Not a block device: %s", what
);
929 d
= udev_device_new_from_devnum(udev
, 'b', st
.st_rdev
);
933 v
= udev_device_get_property_value(d
, "ID_FS_USAGE");
934 if (!streq_ptr(v
, "filesystem")) {
935 log_error("%s does not contain a known file system.", what
);
939 v
= udev_device_get_property_value(d
, "SYSTEMD_MOUNT_WHERE");
941 r2
= stop_mounts(bus
, v
);
943 r
= find_mount_points(what
, &list
);
947 for (l
= list
; *l
; l
++) {
948 r
= stop_mounts(bus
, *l
);
956 static int umount_loop(sd_bus
*bus
, const char *backing_file
) {
957 _cleanup_free_
char *loop_dev
= NULL
;
960 assert(backing_file
);
962 r
= find_loop_device(backing_file
, &loop_dev
);
964 return log_error_errno(r
, r
== -ENXIO
? "File %s is not mounted." : "Can't get loop device for %s: %m", backing_file
);
966 return umount_by_device(bus
, loop_dev
);
969 static int action_umount(
976 if (arg_transport
!= BUS_TRANSPORT_LOCAL
) {
977 for (i
= optind
; i
< argc
; i
++) {
978 _cleanup_free_
char *p
= NULL
;
984 path_kill_slashes(p
);
986 r
= stop_mounts(bus
, p
);
993 for (i
= optind
; i
< argc
; i
++) {
994 _cleanup_free_
char *u
= NULL
, *a
= NULL
, *p
= NULL
;
997 u
= fstab_node_to_udev_node(argv
[i
]);
1001 r
= path_make_absolute_cwd(u
, &a
);
1003 r2
= log_error_errno(r
, "Failed to make path %s absolute: %m", argv
[i
]);
1007 p
= canonicalize_file_name(a
);
1010 r2
= log_error_errno(errno
, "Failed to canonicalize path %s: %m", argv
[i
]);
1014 if (stat(p
, &st
) < 0)
1015 return log_error_errno(errno
, "Can't stat %s (from %s): %m", p
, argv
[i
]);
1017 if (S_ISBLK(st
.st_mode
))
1018 r
= umount_by_device(bus
, p
);
1019 else if (S_ISREG(st
.st_mode
))
1020 r
= umount_loop(bus
, p
);
1021 else if (S_ISDIR(st
.st_mode
))
1022 r
= stop_mounts(bus
, p
);
1024 log_error("Invalid file type: %s (from %s)", p
, argv
[i
]);
1035 static int acquire_mount_type(struct udev_device
*d
) {
1043 v
= udev_device_get_property_value(d
, "ID_FS_TYPE");
1047 arg_mount_type
= strdup(v
);
1048 if (!arg_mount_type
)
1051 log_debug("Discovered type=%s", arg_mount_type
);
1055 static int acquire_mount_options(struct udev_device
*d
) {
1058 if (arg_mount_options
)
1061 v
= udev_device_get_property_value(d
, "SYSTEMD_MOUNT_OPTIONS");
1065 arg_mount_options
= strdup(v
);
1066 if (!arg_mount_options
)
1069 log_debug("Discovered options=%s", arg_mount_options
);
1073 static const char *get_model(struct udev_device
*d
) {
1078 model
= udev_device_get_property_value(d
, "ID_MODEL_FROM_DATABASE");
1082 return udev_device_get_property_value(d
, "ID_MODEL");
1085 static const char* get_label(struct udev_device
*d
) {
1090 label
= udev_device_get_property_value(d
, "ID_FS_LABEL");
1094 return udev_device_get_property_value(d
, "ID_PART_ENTRY_NAME");
1097 static int acquire_mount_where(struct udev_device
*d
) {
1100 if (arg_mount_where
)
1103 v
= udev_device_get_property_value(d
, "SYSTEMD_MOUNT_WHERE");
1105 _cleanup_free_
char *escaped
= NULL
;
1108 name
= get_label(d
);
1110 name
= get_model(d
);
1114 dn
= udev_device_get_devnode(d
);
1118 name
= basename(dn
);
1121 escaped
= xescape(name
, "\\");
1124 if (!filename_is_valid(escaped
))
1127 arg_mount_where
= strjoin("/run/media/system/", escaped
);
1129 arg_mount_where
= strdup(v
);
1131 if (!arg_mount_where
)
1134 log_debug("Discovered where=%s", arg_mount_where
);
1138 static int acquire_mount_where_for_loop_dev(const char *loop_dev
) {
1139 _cleanup_strv_free_
char **list
= NULL
;
1142 if (arg_mount_where
)
1145 r
= find_mount_points(loop_dev
, &list
);
1149 log_error("Can't find mount point of %s. It is expected that %s is already mounted on a place.", loop_dev
, loop_dev
);
1151 } else if (r
>= 2) {
1152 log_error("%s is mounted on %d places. It is expected that %s is mounted on a place.", loop_dev
, r
, loop_dev
);
1156 arg_mount_where
= strdup(list
[0]);
1157 if (!arg_mount_where
)
1160 log_debug("Discovered where=%s", arg_mount_where
);
1164 static int acquire_description(struct udev_device
*d
) {
1165 const char *model
, *label
;
1167 if (arg_description
)
1170 model
= get_model(d
);
1172 label
= get_label(d
);
1174 label
= udev_device_get_property_value(d
, "ID_PART_ENTRY_NUMBER");
1177 arg_description
= strjoin(model
, " ", label
);
1179 arg_description
= strdup(label
);
1181 arg_description
= strdup(model
);
1185 if (!arg_description
)
1188 log_debug("Discovered description=%s", arg_description
);
1192 static int acquire_removable(struct udev_device
*d
) {
1195 /* Shortcut this if there's no reason to check it */
1196 if (arg_action
!= ACTION_DEFAULT
&& arg_timeout_idle_set
&& arg_bind_device
>= 0)
1200 v
= udev_device_get_sysattr_value(d
, "removable");
1204 d
= udev_device_get_parent(d
);
1208 if (!streq_ptr(udev_device_get_subsystem(d
), "block"))
1212 if (parse_boolean(v
) <= 0)
1215 log_debug("Discovered removable device.");
1217 if (arg_action
== ACTION_DEFAULT
) {
1218 log_debug("Automatically turning on automount.");
1219 arg_action
= ACTION_AUTOMOUNT
;
1222 if (!arg_timeout_idle_set
) {
1223 log_debug("Setting idle timeout to 1s.");
1224 arg_timeout_idle
= USEC_PER_SEC
;
1227 if (arg_bind_device
< 0) {
1228 log_debug("Binding automount unit to device.");
1229 arg_bind_device
= true;
1235 static int discover_loop_backing_file(void) {
1236 _cleanup_udev_device_unref_
struct udev_device
*d
= NULL
;
1237 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
1238 _cleanup_free_
char *loop_dev
= NULL
;
1243 r
= find_loop_device(arg_mount_what
, &loop_dev
);
1244 if (r
< 0 && r
!= -ENXIO
)
1245 return log_error_errno(errno
, "Can't get loop device for %s: %m", arg_mount_what
);
1248 _cleanup_free_
char *escaped
= NULL
;
1250 if (arg_mount_where
)
1253 escaped
= xescape(basename(arg_mount_what
), "\\");
1256 if (!filename_is_valid(escaped
)) {
1257 log_error("Escaped name %s is not a valid filename.", escaped
);
1261 arg_mount_where
= strjoin("/run/media/system/", escaped
);
1262 if (!arg_mount_where
)
1265 log_debug("Discovered where=%s", arg_mount_where
);
1269 if (stat(loop_dev
, &st
) < 0)
1270 return log_error_errno(errno
, "Can't stat %s: %m", loop_dev
);
1272 if (!S_ISBLK(st
.st_mode
)) {
1273 log_error("Invalid file type: %s", loop_dev
);
1281 d
= udev_device_new_from_devnum(udev
, 'b', st
.st_rdev
);
1285 v
= udev_device_get_property_value(d
, "ID_FS_USAGE");
1286 if (!streq_ptr(v
, "filesystem")) {
1287 log_error("%s does not contain a known file system.", arg_mount_what
);
1291 r
= acquire_mount_type(d
);
1295 r
= acquire_mount_options(d
);
1299 r
= acquire_mount_where_for_loop_dev(loop_dev
);
1303 r
= acquire_description(d
);
1310 static int discover_device(void) {
1311 _cleanup_udev_device_unref_
struct udev_device
*d
= NULL
;
1312 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
1317 if (stat(arg_mount_what
, &st
) < 0)
1318 return log_error_errno(errno
, "Can't stat %s: %m", arg_mount_what
);
1320 if (S_ISREG(st
.st_mode
))
1321 return discover_loop_backing_file();
1323 if (!S_ISBLK(st
.st_mode
)) {
1324 log_error("Invalid file type: %s", arg_mount_what
);
1332 d
= udev_device_new_from_devnum(udev
, 'b', st
.st_rdev
);
1336 v
= udev_device_get_property_value(d
, "ID_FS_USAGE");
1337 if (!streq_ptr(v
, "filesystem")) {
1338 log_error("%s does not contain a known file system.", arg_mount_what
);
1342 r
= acquire_mount_type(d
);
1346 r
= acquire_mount_options(d
);
1350 r
= acquire_mount_where(d
);
1354 r
= acquire_description(d
);
1358 r
= acquire_removable(d
);
1377 char* columns
[_COLUMN_MAX
];
1380 static int compare_item(const void *a
, const void *b
) {
1381 const struct item
*x
= a
, *y
= b
;
1383 if (x
->columns
[COLUMN_NODE
] == y
->columns
[COLUMN_NODE
])
1385 if (!x
->columns
[COLUMN_NODE
])
1387 if (!y
->columns
[COLUMN_NODE
])
1390 return path_compare(x
->columns
[COLUMN_NODE
], y
->columns
[COLUMN_NODE
]);
1393 static int list_devices(void) {
1395 static const char * const titles
[_COLUMN_MAX
] = {
1396 [COLUMN_NODE
] = "NODE",
1397 [COLUMN_PATH
] = "PATH",
1398 [COLUMN_MODEL
] = "MODEL",
1399 [COLUMN_WWN
] = "WWN",
1400 [COLUMN_FSTYPE
] = "TYPE",
1401 [COLUMN_LABEL
] = "LABEL",
1402 [COLUMN_UUID
] = "UUID"
1405 _cleanup_udev_enumerate_unref_
struct udev_enumerate
*e
= NULL
;
1406 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
1407 struct udev_list_entry
*item
= NULL
, *first
= NULL
;
1408 size_t n_allocated
= 0, n
= 0, i
;
1409 size_t column_width
[_COLUMN_MAX
];
1410 struct item
*items
= NULL
;
1414 for (c
= 0; c
< _COLUMN_MAX
; c
++)
1415 column_width
[c
] = strlen(titles
[c
]);
1421 e
= udev_enumerate_new(udev
);
1425 r
= udev_enumerate_add_match_subsystem(e
, "block");
1427 return log_error_errno(r
, "Failed to add block match: %m");
1429 r
= udev_enumerate_add_match_property(e
, "ID_FS_USAGE", "filesystem");
1431 return log_error_errno(r
, "Failed to add property match: %m");
1433 r
= udev_enumerate_scan_devices(e
);
1435 return log_error_errno(r
, "Failed to scan devices: %m");
1437 first
= udev_enumerate_get_list_entry(e
);
1438 udev_list_entry_foreach(item
, first
) {
1439 _cleanup_udev_device_unref_
struct udev_device
*d
;
1442 d
= udev_device_new_from_syspath(udev
, udev_list_entry_get_name(item
));
1448 if (!GREEDY_REALLOC0(items
, n_allocated
, n
+1)) {
1455 for (c
= 0; c
< _COLUMN_MAX
; c
++) {
1456 const char *x
= NULL
;
1462 x
= udev_device_get_devnode(d
);
1466 x
= udev_device_get_property_value(d
, "ID_PATH");
1474 x
= udev_device_get_property_value(d
, "ID_WWN");
1478 x
= udev_device_get_property_value(d
, "ID_FS_TYPE");
1486 x
= udev_device_get_property_value(d
, "ID_FS_UUID");
1493 j
->columns
[c
] = strdup(x
);
1494 if (!j
->columns
[c
]) {
1500 if (k
> column_width
[c
])
1501 column_width
[c
] = k
;
1506 log_info("No devices found.");
1510 qsort_safe(items
, n
, sizeof(struct item
), compare_item
);
1512 pager_open(arg_no_pager
, false);
1514 fputs(ansi_underline(), stdout
);
1515 for (c
= 0; c
< _COLUMN_MAX
; c
++) {
1519 printf("%-*s", (int) column_width
[c
], titles
[c
]);
1521 fputs(ansi_normal(), stdout
);
1522 fputc('\n', stdout
);
1524 for (i
= 0; i
< n
; i
++) {
1525 for (c
= 0; c
< _COLUMN_MAX
; c
++) {
1529 printf("%-*s", (int) column_width
[c
], strna(items
[i
].columns
[c
]));
1531 fputc('\n', stdout
);
1537 for (i
= 0; i
< n
; i
++)
1538 for (c
= 0; c
< _COLUMN_MAX
; c
++)
1539 free(items
[i
].columns
[c
]);
1545 int main(int argc
, char* argv
[]) {
1546 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1549 log_parse_environment();
1552 r
= parse_argv(argc
, argv
);
1556 if (arg_action
== ACTION_LIST
) {
1561 r
= bus_connect_transport_systemd(arg_transport
, arg_host
, arg_user
, &bus
);
1563 log_error_errno(r
, "Failed to create bus connection: %m");
1567 if (arg_action
== ACTION_UMOUNT
) {
1568 r
= action_umount(bus
, argc
, argv
);
1572 if (!path_is_safe(arg_mount_what
)) {
1573 log_error("Path contains unsafe components: %s", arg_mount_what
);
1579 r
= discover_device();
1584 if (!arg_mount_where
) {
1585 log_error("Can't figure out where to mount %s.", arg_mount_what
);
1590 if (path_equal(arg_mount_where
, "/")) {
1591 log_error("Refusing to operate on root directory.");
1596 if (!path_is_safe(arg_mount_where
)) {
1597 log_error("Path contains unsafe components: %s", arg_mount_where
);
1602 if (streq_ptr(arg_mount_type
, "auto"))
1603 arg_mount_type
= mfree(arg_mount_type
);
1604 if (streq_ptr(arg_mount_options
, "defaults"))
1605 arg_mount_options
= mfree(arg_mount_options
);
1607 if (!is_device_path(arg_mount_what
))
1610 if (arg_fsck
&& arg_mount_type
&& arg_transport
== BUS_TRANSPORT_LOCAL
) {
1611 r
= fsck_exists(arg_mount_type
);
1613 log_warning_errno(r
, "Couldn't determine whether fsck for %s exists, proceeding anyway.", arg_mount_type
);
1615 log_debug("Disabling file system check as fsck for %s doesn't exist.", arg_mount_type
);
1616 arg_fsck
= false; /* fsck doesn't exist, let's not attempt it */
1620 switch (arg_action
) {
1623 case ACTION_DEFAULT
:
1624 r
= start_transient_mount(bus
, argv
+ optind
);
1627 case ACTION_AUTOMOUNT
:
1628 r
= start_transient_automount(bus
, argv
+ optind
);
1632 assert_not_reached("Unexpected action.");
1638 free(arg_mount_what
);
1639 free(arg_mount_where
);
1640 free(arg_mount_type
);
1641 free(arg_mount_options
);
1642 free(arg_description
);
1643 strv_free(arg_property
);
1644 strv_free(arg_automount_property
);
1646 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;