]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/mount/mount-tool.c
systemd-mount: support unmounting devices on remote host
[thirdparty/systemd.git] / src / mount / mount-tool.c
CommitLineData
450442cf
LP
1/***
2 This file is part of systemd.
3
4 Copyright 2016 Lennart Poettering
5
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.
10
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.
15
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/>.
18***/
19
20#include <getopt.h>
21
22#include "libudev.h"
23#include "sd-bus.h"
24
25#include "bus-error.h"
26#include "bus-unit-util.h"
27#include "bus-util.h"
6f6165bf 28#include "dirent-util.h"
450442cf 29#include "escape.h"
9017f5d8 30#include "fd-util.h"
6f6165bf 31#include "fileio.h"
450442cf
LP
32#include "fstab-util.h"
33#include "pager.h"
34#include "parse-util.h"
35#include "path-util.h"
36#include "spawn-polkit-agent.h"
6f6165bf 37#include "stat-util.h"
450442cf
LP
38#include "strv.h"
39#include "udev-util.h"
40#include "unit-name.h"
41#include "terminal-util.h"
42
43enum {
44 ACTION_DEFAULT,
45 ACTION_MOUNT,
46 ACTION_AUTOMOUNT,
c37fb55b 47 ACTION_UMOUNT,
450442cf
LP
48 ACTION_LIST,
49} arg_action = ACTION_DEFAULT;
50
51static bool arg_no_block = false;
52static bool arg_no_pager = false;
53static bool arg_ask_password = true;
54static bool arg_quiet = false;
55static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
56static bool arg_user = false;
57static const char *arg_host = NULL;
58static bool arg_discover = false;
59static char *arg_mount_what = NULL;
60static char *arg_mount_where = NULL;
61static char *arg_mount_type = NULL;
62static char *arg_mount_options = NULL;
63static char *arg_description = NULL;
64static char **arg_property = NULL;
65static usec_t arg_timeout_idle = USEC_INFINITY;
66static bool arg_timeout_idle_set = false;
67static char **arg_automount_property = NULL;
68static int arg_bind_device = -1;
69static bool arg_fsck = true;
70
71static void polkit_agent_open_if_enabled(void) {
72
73 /* Open the polkit agent as a child process if necessary */
74 if (!arg_ask_password)
75 return;
76
77 if (arg_transport != BUS_TRANSPORT_LOCAL)
78 return;
79
80 polkit_agent_open();
81}
82
83static void help(void) {
9017f5d8
YW
84 printf("systemd-mount [OPTIONS...] WHAT [WHERE]\n"
85 "systemd-mount [OPTIONS...] --list\n"
86 "%s [OPTIONS...] %sWHAT|WHERE...\n\n"
450442cf
LP
87 "Establish a mount or auto-mount point transiently.\n\n"
88 " -h --help Show this help\n"
89 " --version Show package version\n"
90 " --no-block Do not wait until operation finished\n"
91 " --no-pager Do not pipe output into a pager\n"
92 " --no-ask-password Do not prompt for password\n"
93 " -q --quiet Suppress information messages during runtime\n"
94 " --user Run as user unit\n"
95 " -H --host=[USER@]HOST Operate on remote host\n"
96 " -M --machine=CONTAINER Operate on local container\n"
97 " --discover Discover mount device metadata\n"
98 " -t --type=TYPE File system type\n"
99 " -o --options=OPTIONS Mount options\n"
100 " --fsck=no Don't run file system check before mount\n"
101 " --description=TEXT Description for unit\n"
102 " -p --property=NAME=VALUE Set mount unit property\n"
103 " -A --automount=BOOL Create an auto-mount point\n"
104 " --timeout-idle-sec=SEC Specify automount idle timeout\n"
105 " --automount-property=NAME=VALUE\n"
106 " Set automount unit property\n"
107 " --bind-device Bind automount unit to device\n"
108 " --list List mountable block devices\n"
9017f5d8
YW
109 " -u --umount Unmount mount points\n",
110 program_invocation_short_name,
111 streq(program_invocation_short_name, "systemd-umount") ? "" : "--umount ");
450442cf
LP
112}
113
114static int parse_argv(int argc, char *argv[]) {
115
116 enum {
117 ARG_VERSION = 0x100,
118 ARG_NO_BLOCK,
119 ARG_NO_PAGER,
120 ARG_NO_ASK_PASSWORD,
121 ARG_USER,
122 ARG_SYSTEM,
123 ARG_DISCOVER,
124 ARG_MOUNT_TYPE,
125 ARG_MOUNT_OPTIONS,
126 ARG_FSCK,
127 ARG_DESCRIPTION,
128 ARG_TIMEOUT_IDLE,
129 ARG_AUTOMOUNT,
130 ARG_AUTOMOUNT_PROPERTY,
131 ARG_BIND_DEVICE,
132 ARG_LIST,
133 };
134
135 static const struct option options[] = {
136 { "help", no_argument, NULL, 'h' },
137 { "version", no_argument, NULL, ARG_VERSION },
138 { "no-block", no_argument, NULL, ARG_NO_BLOCK },
139 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
140 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
141 { "quiet", no_argument, NULL, 'q' },
142 { "user", no_argument, NULL, ARG_USER },
143 { "system", no_argument, NULL, ARG_SYSTEM },
144 { "host", required_argument, NULL, 'H' },
145 { "machine", required_argument, NULL, 'M' },
146 { "discover", no_argument, NULL, ARG_DISCOVER },
147 { "type", required_argument, NULL, 't' },
148 { "options", required_argument, NULL, 'o' },
0f923832 149 { "fsck", required_argument, NULL, ARG_FSCK },
450442cf
LP
150 { "description", required_argument, NULL, ARG_DESCRIPTION },
151 { "property", required_argument, NULL, 'p' },
152 { "automount", required_argument, NULL, ARG_AUTOMOUNT },
153 { "timeout-idle-sec", required_argument, NULL, ARG_TIMEOUT_IDLE },
154 { "automount-property", required_argument, NULL, ARG_AUTOMOUNT_PROPERTY },
155 { "bind-device", no_argument, NULL, ARG_BIND_DEVICE },
156 { "list", no_argument, NULL, ARG_LIST },
c37fb55b
LR
157 { "umount", no_argument, NULL, 'u' },
158 { "unmount", no_argument, NULL, 'u' },
450442cf
LP
159 {},
160 };
161
162 int r, c;
163
164 assert(argc >= 0);
165 assert(argv);
166
c37fb55b
LR
167 if (strstr(program_invocation_short_name, "systemd-umount"))
168 arg_action = ACTION_UMOUNT;
169
170 while ((c = getopt_long(argc, argv, "hqH:M:t:o:p:Au", options, NULL)) >= 0)
450442cf
LP
171
172 switch (c) {
173
174 case 'h':
175 help();
176 return 0;
177
178 case ARG_VERSION:
179 return version();
180
181 case ARG_NO_BLOCK:
182 arg_no_block = true;
183 break;
184
185 case ARG_NO_PAGER:
186 arg_no_pager = true;
187 break;
188
189 case ARG_NO_ASK_PASSWORD:
190 arg_ask_password = false;
191 break;
192
193 case 'q':
194 arg_quiet = true;
195 break;
196
197 case ARG_USER:
198 arg_user = true;
199 break;
200
201 case ARG_SYSTEM:
202 arg_user = false;
203 break;
204
205 case 'H':
206 arg_transport = BUS_TRANSPORT_REMOTE;
207 arg_host = optarg;
208 break;
209
210 case 'M':
211 arg_transport = BUS_TRANSPORT_MACHINE;
212 arg_host = optarg;
213 break;
214
215 case ARG_DISCOVER:
216 arg_discover = true;
217 break;
218
219 case 't':
220 if (free_and_strdup(&arg_mount_type, optarg) < 0)
221 return log_oom();
222 break;
223
224 case 'o':
225 if (free_and_strdup(&arg_mount_options, optarg) < 0)
226 return log_oom();
227 break;
228
229 case ARG_FSCK:
230 r = parse_boolean(optarg);
231 if (r < 0)
232 return log_error_errno(r, "Failed to parse --fsck= argument: %s", optarg);
233
234 arg_fsck = r;
235 break;
236
237 case ARG_DESCRIPTION:
238 if (free_and_strdup(&arg_description, optarg) < 0)
239 return log_oom();
240 break;
241
242 case 'p':
243 if (strv_extend(&arg_property, optarg) < 0)
244 return log_oom();
245
246 break;
247
248 case 'A':
249 arg_action = ACTION_AUTOMOUNT;
250 break;
251
252 case ARG_AUTOMOUNT:
253 r = parse_boolean(optarg);
254 if (r < 0)
255 return log_error_errno(r, "--automount= expects a valid boolean parameter: %s", optarg);
256
257 arg_action = r ? ACTION_AUTOMOUNT : ACTION_MOUNT;
258 break;
259
260 case ARG_TIMEOUT_IDLE:
261 r = parse_sec(optarg, &arg_timeout_idle);
262 if (r < 0)
263 return log_error_errno(r, "Failed to parse timeout: %s", optarg);
264
265 break;
266
267 case ARG_AUTOMOUNT_PROPERTY:
268 if (strv_extend(&arg_automount_property, optarg) < 0)
269 return log_oom();
270
271 break;
272
273 case ARG_BIND_DEVICE:
274 arg_bind_device = true;
275 break;
276
277 case ARG_LIST:
278 arg_action = ACTION_LIST;
279 break;
280
c37fb55b
LR
281 case 'u':
282 arg_action = ACTION_UMOUNT;
283 break;
284
450442cf
LP
285 case '?':
286 return -EINVAL;
287
288 default:
289 assert_not_reached("Unhandled option");
290 }
291
292 if (arg_user && arg_transport != BUS_TRANSPORT_LOCAL) {
293 log_error("Execution in user context is not supported on non-local systems.");
294 return -EINVAL;
295 }
296
297 if (arg_action == ACTION_LIST) {
298 if (optind < argc) {
299 log_error("Too many arguments.");
300 return -EINVAL;
301 }
302
303 if (arg_transport != BUS_TRANSPORT_LOCAL) {
304 log_error("Listing devices only supported locally.");
305 return -EOPNOTSUPP;
306 }
9017f5d8
YW
307 } else if (arg_action == ACTION_UMOUNT) {
308 if (optind >= argc) {
309 log_error("At least one argument required.");
310 return -EINVAL;
311 }
312
313 if (arg_transport != BUS_TRANSPORT_LOCAL) {
3747daa2
YW
314 int i;
315
316 for (i = optind; i < argc; i++)
317 if (!path_is_absolute(argv[i]) ) {
318 log_error("Only absolute path is supported: %s", argv[i]);
319 return -EINVAL;
320 }
9017f5d8 321 }
450442cf
LP
322 } else {
323 if (optind >= argc) {
324 log_error("At least one argument required.");
325 return -EINVAL;
326 }
327
328 if (argc > optind+2) {
329 log_error("At most two arguments required.");
330 return -EINVAL;
331 }
332
333 arg_mount_what = fstab_node_to_udev_node(argv[optind]);
334 if (!arg_mount_what)
335 return log_oom();
336
337 if (argc > optind+1) {
338 r = path_make_absolute_cwd(argv[optind+1], &arg_mount_where);
339 if (r < 0)
340 return log_error_errno(r, "Failed to make path absolute: %m");
341 } else
342 arg_discover = true;
343
344 if (arg_discover && arg_transport != BUS_TRANSPORT_LOCAL) {
345 log_error("Automatic mount location discovery is only supported locally.");
346 return -EOPNOTSUPP;
347 }
348 }
349
350 return 1;
351}
352
353static int transient_unit_set_properties(sd_bus_message *m, char **properties) {
354 int r;
355
05b4d3b5
AK
356 if (!isempty(arg_description)) {
357 r = sd_bus_message_append(m, "(sv)", "Description", "s", arg_description);
358 if (r < 0)
359 return r;
360 }
450442cf
LP
361
362 if (arg_bind_device && is_device_path(arg_mount_what)) {
363 _cleanup_free_ char *device_unit = NULL;
364
365 r = unit_name_from_path(arg_mount_what, ".device", &device_unit);
366 if (r < 0)
367 return r;
368
369 r = sd_bus_message_append(m, "(sv)(sv)",
370 "After", "as", 1, device_unit,
371 "BindsTo", "as", 1, device_unit);
372 if (r < 0)
373 return r;
374 }
375
376 r = bus_append_unit_property_assignment_many(m, properties);
377 if (r < 0)
378 return r;
379
380 return 0;
381}
382
383static int transient_mount_set_properties(sd_bus_message *m) {
384 int r;
385
386 assert(m);
387
388 r = transient_unit_set_properties(m, arg_property);
389 if (r < 0)
390 return r;
391
392 if (arg_mount_what) {
393 r = sd_bus_message_append(m, "(sv)", "What", "s", arg_mount_what);
394 if (r < 0)
395 return r;
396 }
397
398 if (arg_mount_type) {
399 r = sd_bus_message_append(m, "(sv)", "Type", "s", arg_mount_type);
400 if (r < 0)
401 return r;
402 }
403
404 if (arg_mount_options) {
405 r = sd_bus_message_append(m, "(sv)", "Options", "s", arg_mount_options);
406 if (r < 0)
407 return r;
408 }
409
410 if (arg_fsck) {
411 _cleanup_free_ char *fsck = NULL;
412
413 r = unit_name_from_path_instance("systemd-fsck", arg_mount_what, ".service", &fsck);
414 if (r < 0)
415 return r;
416
417 r = sd_bus_message_append(m,
418 "(sv)(sv)",
419 "Requires", "as", 1, fsck,
420 "After", "as", 1, fsck);
421 if (r < 0)
422 return r;
423 }
424
425 return 0;
426}
427
428static int transient_automount_set_properties(sd_bus_message *m) {
429 int r;
430
431 assert(m);
432
433 r = transient_unit_set_properties(m, arg_automount_property);
434 if (r < 0)
435 return r;
436
437 if (arg_timeout_idle != USEC_INFINITY) {
438 r = sd_bus_message_append(m, "(sv)", "TimeoutIdleUSec", "t", arg_timeout_idle);
439 if (r < 0)
440 return r;
441 }
442
443 return 0;
444}
445
446static int start_transient_mount(
447 sd_bus *bus,
448 char **argv) {
449
450 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
451 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
452 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
453 _cleanup_free_ char *mount_unit = NULL;
454 int r;
455
456 if (!arg_no_block) {
457 r = bus_wait_for_jobs_new(bus, &w);
458 if (r < 0)
459 return log_error_errno(r, "Could not watch jobs: %m");
460 }
461
462 r = unit_name_from_path(arg_mount_where, ".mount", &mount_unit);
463 if (r < 0)
464 return log_error_errno(r, "Failed to make mount unit name: %m");
465
466 r = sd_bus_message_new_method_call(
467 bus,
468 &m,
469 "org.freedesktop.systemd1",
470 "/org/freedesktop/systemd1",
471 "org.freedesktop.systemd1.Manager",
472 "StartTransientUnit");
473 if (r < 0)
474 return bus_log_create_error(r);
475
476 r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
477 if (r < 0)
478 return bus_log_create_error(r);
479
480 /* Name and mode */
481 r = sd_bus_message_append(m, "ss", mount_unit, "fail");
482 if (r < 0)
483 return bus_log_create_error(r);
484
485 /* Properties */
486 r = sd_bus_message_open_container(m, 'a', "(sv)");
487 if (r < 0)
488 return bus_log_create_error(r);
489
490 r = transient_mount_set_properties(m);
491 if (r < 0)
492 return bus_log_create_error(r);
493
494 r = sd_bus_message_close_container(m);
495 if (r < 0)
496 return bus_log_create_error(r);
497
498 /* Auxiliary units */
499 r = sd_bus_message_append(m, "a(sa(sv))", 0);
500 if (r < 0)
501 return bus_log_create_error(r);
502
503 polkit_agent_open_if_enabled();
504
505 r = sd_bus_call(bus, m, 0, &error, &reply);
506 if (r < 0)
507 return log_error_errno(r, "Failed to start transient mount unit: %s", bus_error_message(&error, r));
508
509 if (w) {
510 const char *object;
511
512 r = sd_bus_message_read(reply, "o", &object);
513 if (r < 0)
514 return bus_log_parse_error(r);
515
516 r = bus_wait_for_jobs_one(w, object, arg_quiet);
517 if (r < 0)
518 return r;
519 }
520
521 if (!arg_quiet)
522 log_info("Started unit %s%s%s for mount point: %s%s%s",
523 ansi_highlight(), mount_unit, ansi_normal(),
524 ansi_highlight(), arg_mount_where, ansi_normal());
525
526 return 0;
527}
528
529static int start_transient_automount(
530 sd_bus *bus,
531 char **argv) {
532
533 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
534 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
535 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
536 _cleanup_free_ char *automount_unit = NULL, *mount_unit = NULL;
537 int r;
538
539 if (!arg_no_block) {
540 r = bus_wait_for_jobs_new(bus, &w);
541 if (r < 0)
542 return log_error_errno(r, "Could not watch jobs: %m");
543 }
544
545 r = unit_name_from_path(arg_mount_where, ".automount", &automount_unit);
546 if (r < 0)
547 return log_error_errno(r, "Failed to make automount unit name: %m");
548
549 r = unit_name_from_path(arg_mount_where, ".mount", &mount_unit);
550 if (r < 0)
551 return log_error_errno(r, "Failed to make mount unit name: %m");
552
553 r = sd_bus_message_new_method_call(
554 bus,
555 &m,
556 "org.freedesktop.systemd1",
557 "/org/freedesktop/systemd1",
558 "org.freedesktop.systemd1.Manager",
559 "StartTransientUnit");
560 if (r < 0)
561 return bus_log_create_error(r);
562
563 r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
564 if (r < 0)
565 return bus_log_create_error(r);
566
567 /* Name and mode */
568 r = sd_bus_message_append(m, "ss", automount_unit, "fail");
569 if (r < 0)
570 return bus_log_create_error(r);
571
572 /* Properties */
573 r = sd_bus_message_open_container(m, 'a', "(sv)");
574 if (r < 0)
575 return bus_log_create_error(r);
576
577 r = transient_automount_set_properties(m);
578 if (r < 0)
579 return bus_log_create_error(r);
580
581 r = sd_bus_message_close_container(m);
582 if (r < 0)
583 return bus_log_create_error(r);
584
585 /* Auxiliary units */
586 r = sd_bus_message_open_container(m, 'a', "(sa(sv))");
587 if (r < 0)
588 return bus_log_create_error(r);
589
590 r = sd_bus_message_open_container(m, 'r', "sa(sv)");
591 if (r < 0)
592 return bus_log_create_error(r);
593
594 r = sd_bus_message_append(m, "s", mount_unit);
595 if (r < 0)
596 return bus_log_create_error(r);
597
598 r = sd_bus_message_open_container(m, 'a', "(sv)");
599 if (r < 0)
600 return bus_log_create_error(r);
601
602 r = transient_mount_set_properties(m);
603 if (r < 0)
604 return bus_log_create_error(r);
605
606 r = sd_bus_message_close_container(m);
607 if (r < 0)
608 return bus_log_create_error(r);
609
610 r = sd_bus_message_close_container(m);
611 if (r < 0)
612 return bus_log_create_error(r);
613
614 r = sd_bus_message_close_container(m);
615 if (r < 0)
616 return bus_log_create_error(r);
617
618 polkit_agent_open_if_enabled();
619
620 r = sd_bus_call(bus, m, 0, &error, &reply);
621 if (r < 0)
622 return log_error_errno(r, "Failed to start transient automount unit: %s", bus_error_message(&error, r));
623
624 if (w) {
625 const char *object;
626
627 r = sd_bus_message_read(reply, "o", &object);
628 if (r < 0)
629 return bus_log_parse_error(r);
630
631 r = bus_wait_for_jobs_one(w, object, arg_quiet);
632 if (r < 0)
633 return r;
634 }
635
636 if (!arg_quiet)
637 log_info("Started unit %s%s%s for mount point: %s%s%s",
638 ansi_highlight(), automount_unit, ansi_normal(),
639 ansi_highlight(), arg_mount_where, ansi_normal());
640
641 return 0;
642}
643
f0aac575
YW
644static int find_mount_points(const char *what, char ***list) {
645 _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
646 _cleanup_strv_free_ char **l = NULL;
647 size_t bufsize = 0, n = 0;
648
649 assert(what);
650 assert(list);
651
652 /* Returns all mount points obtained from /proc/self/mountinfo in *list,
653 * and the number of mount points as return value. */
654
655 proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
656 if (!proc_self_mountinfo)
657 return log_error_errno(errno, "Can't open /proc/self/mountinfo: %m");
658
659 for (;;) {
660 _cleanup_free_ char *path = NULL, *where = NULL, *dev = NULL;
661 int r;
662
663 r = fscanf(proc_self_mountinfo,
664 "%*s " /* (1) mount id */
665 "%*s " /* (2) parent id */
666 "%*s " /* (3) major:minor */
667 "%*s " /* (4) root */
668 "%ms " /* (5) mount point */
669 "%*s" /* (6) mount options */
670 "%*[^-]" /* (7) optional fields */
671 "- " /* (8) separator */
672 "%*s " /* (9) file system type */
673 "%ms" /* (10) mount source */
674 "%*s" /* (11) mount options 2 */
675 "%*[^\n]", /* some rubbish at the end */
676 &path, &dev);
677 if (r != 2) {
678 if (r == EOF)
679 break;
680
681 continue;
682 }
683
684 if (!streq(what, dev))
685 continue;
686
687 r = cunescape(path, UNESCAPE_RELAX, &where);
688 if (r < 0)
689 continue;
690
691 /* one extra slot is needed for the terminating NULL */
692 if (!GREEDY_REALLOC(l, bufsize, n + 2))
693 return log_oom();
694
695 l[n] = strdup(where);
696 if (!l[n])
697 return log_oom();
698
699 n++;
700 }
701
702 l[n] = NULL;
703 *list = l;
704 l = NULL; /* avoid freeing */
705
706 return n;
707}
708
709static int find_loop_device(const char *backing_file, char **loop_dev) {
710 _cleanup_closedir_ DIR *d = NULL;
711 struct dirent *de;
712 _cleanup_free_ char *l = NULL;
713
714 assert(backing_file);
715 assert(loop_dev);
716
717 d = opendir("/sys/devices/virtual/block");
718 if (!d) {
719 if (errno == ENOENT)
720 return -ENOENT;
721 return log_error_errno(errno, "Can't open directory /sys/devices/virtual/block: %m");
722 }
723
724 FOREACH_DIRENT(de, d, return -errno) {
725 _cleanup_free_ char *sys = NULL, *fname = NULL;
726 int r;
727
728 dirent_ensure_type(d, de);
729
730 if (de->d_type != DT_DIR)
731 continue;
732
733 if (!startswith(de->d_name, "loop"))
734 continue;
735
736 sys = strjoin("/sys/devices/virtual/block/", de->d_name, "/loop/backing_file");
737 if (!sys)
738 return log_oom();
739
740 r = read_one_line_file(sys, &fname);
741 if (r < 0)
742 continue;
743
744 if (files_same(fname, backing_file, 0) <= 0)
745 continue;
746
747 l = strjoin("/dev/", de->d_name);
748 if (!l)
749 return log_oom();
750
751 break;
752 }
753
754 if (!l)
755 return -ENOENT;
756
757 *loop_dev = l;
758 l = NULL; /* avoid freeing */
759
760 return 0;
761}
762
c37fb55b
LR
763static int stop_mount(
764 sd_bus *bus,
9017f5d8 765 const char *where,
6f6165bf 766 const char *suffix) {
c37fb55b
LR
767
768 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
769 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
770 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
771 _cleanup_free_ char *mount_unit = NULL;
772 int r;
773
774 if (!arg_no_block) {
775 r = bus_wait_for_jobs_new(bus, &w);
776 if (r < 0)
777 return log_error_errno(r, "Could not watch jobs: %m");
778 }
779
9017f5d8 780 r = unit_name_from_path(where, suffix, &mount_unit);
c37fb55b 781 if (r < 0)
9017f5d8 782 return log_error_errno(r, "Failed to make mount unit name from path %s: %m", where);
c37fb55b
LR
783
784 r = sd_bus_message_new_method_call(
785 bus,
786 &m,
787 "org.freedesktop.systemd1",
788 "/org/freedesktop/systemd1",
789 "org.freedesktop.systemd1.Manager",
790 "StopUnit");
791 if (r < 0)
792 return bus_log_create_error(r);
793
794 r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
795 if (r < 0)
796 return bus_log_create_error(r);
797
798 /* Name and mode */
799 r = sd_bus_message_append(m, "ss", mount_unit, "fail");
800 if (r < 0)
801 return bus_log_create_error(r);
802
803 polkit_agent_open_if_enabled();
804
805 r = sd_bus_call(bus, m, 0, &error, &reply);
6f6165bf
YW
806 if (r < 0)
807 return log_error_errno(r, "Failed to stop mount unit: %s", bus_error_message(&error, r));
c37fb55b
LR
808
809 if (w) {
810 const char *object;
811
812 r = sd_bus_message_read(reply, "o", &object);
813 if (r < 0)
814 return bus_log_parse_error(r);
815
816 r = bus_wait_for_jobs_one(w, object, arg_quiet);
817 if (r < 0)
818 return r;
819 }
820
821 if (!arg_quiet)
822 log_info("Stopped unit %s%s%s for mount point: %s%s%s",
823 ansi_highlight(), mount_unit, ansi_normal(),
9017f5d8 824 ansi_highlight(), where, ansi_normal());
c37fb55b
LR
825
826 return 0;
827}
828
829static int stop_mounts(
830 sd_bus *bus,
6f6165bf 831 const char *where) {
c37fb55b
LR
832
833 int r;
834
9017f5d8
YW
835 if (path_equal(where, "/")) {
836 log_error("Refusing to operate on root directory: %s", where);
837 return -EINVAL;
838 }
839
840 if (!path_is_safe(where)) {
841 log_error("Path contains unsafe components: %s", where);
842 return -EINVAL;
843 }
844
6f6165bf 845 r = stop_mount(bus, where, ".mount");
c37fb55b
LR
846 if (r < 0)
847 return r;
848
6f6165bf 849 r = stop_mount(bus, where, ".automount");
c37fb55b
LR
850 if (r < 0)
851 return r;
852
853 return 0;
854}
855
9017f5d8
YW
856static int umount_by_device(sd_bus *bus, const char *what) {
857 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
858 _cleanup_udev_unref_ struct udev *udev = NULL;
f0aac575 859 _cleanup_strv_free_ char **list = NULL;
9017f5d8
YW
860 struct stat st;
861 const char *v;
f0aac575 862 char **l;
6f6165bf 863 int r, r2 = 0;
9017f5d8
YW
864
865 assert(what);
866
867 if (stat(what, &st) < 0)
868 return log_error_errno(errno, "Can't stat %s: %m", what);
869
870 if (!S_ISBLK(st.st_mode)) {
6f6165bf 871 log_error("Not a block device: %s", what);
9017f5d8
YW
872 return -ENOTBLK;
873 }
874
875 udev = udev_new();
876 if (!udev)
877 return log_oom();
878
879 d = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
880 if (!d)
881 return log_oom();
882
883 v = udev_device_get_property_value(d, "ID_FS_USAGE");
884 if (!streq_ptr(v, "filesystem")) {
885 log_error("%s does not contain a known file system.", what);
886 return -EINVAL;
887 }
888
889 v = udev_device_get_property_value(d, "SYSTEMD_MOUNT_WHERE");
f0aac575
YW
890 if (!isempty(v))
891 r2 = stop_mounts(bus, v);
9017f5d8 892
f0aac575
YW
893 r = find_mount_points(what, &list);
894 if (r < 0)
895 return r;
896
897 for (l = list; *l; l++) {
898 r = stop_mounts(bus, *l);
6f6165bf 899 if (r < 0)
f0aac575 900 r2 = r;
9017f5d8
YW
901 }
902
6f6165bf
YW
903 return r2;
904}
905
906static int umount_loop(sd_bus *bus, const char *backing_file) {
f0aac575
YW
907 _cleanup_free_ char *loop_dev = NULL;
908 int r;
6f6165bf
YW
909
910 assert(backing_file);
911
f0aac575
YW
912 r = find_loop_device(backing_file, &loop_dev);
913 if (r < 0)
914 return log_error_errno(r, r == -ENOENT ? "File %s is not mounted." : "Can't get loop device for %s: %m", backing_file);
6f6165bf 915
f0aac575 916 return umount_by_device(bus, loop_dev);
9017f5d8
YW
917}
918
919static int action_umount(
920 sd_bus *bus,
921 int argc,
922 char **argv) {
923
924 int i, r, r2 = 0;
925
3747daa2
YW
926 if (arg_transport != BUS_TRANSPORT_LOCAL) {
927 for (i = optind; i < argc; i++) {
928 _cleanup_free_ char *p = NULL;
929
930 p = strdup(argv[i]);
931 if (!p)
932 return log_oom();
933
934 path_kill_slashes(p);
935
936 r = stop_mounts(bus, p);
937 if (r < 0)
938 r2 = r;
939 }
940 return r2;
941 }
942
9017f5d8 943 for (i = optind; i < argc; i++) {
6f6165bf
YW
944 _cleanup_free_ char *u = NULL, *p = NULL;
945 struct stat st;
9017f5d8
YW
946
947 u = fstab_node_to_udev_node(argv[i]);
948 if (!u)
949 return log_oom();
9017f5d8 950
6f6165bf 951 r = path_make_absolute_cwd(u, &p);
9017f5d8 952 if (r < 0) {
6f6165bf 953 r2 = log_error_errno(r, "Failed to make path absolute: %m");
9017f5d8
YW
954 continue;
955 }
956
6f6165bf 957 path_kill_slashes(p);
9017f5d8 958
6f6165bf
YW
959 if (stat(p, &st) < 0)
960 return log_error_errno(errno, "Can't stat %s: %m", p);
9017f5d8 961
6f6165bf
YW
962 if (S_ISBLK(st.st_mode))
963 r = umount_by_device(bus, p);
964 else if (S_ISREG(st.st_mode))
965 r = umount_loop(bus, p);
966 else if (S_ISDIR(st.st_mode))
967 r = stop_mounts(bus, p);
968 else {
969 log_error("Invalid file type: %s", p);
970 r = -EINVAL;
971 }
972
973 if (r < 0)
9017f5d8
YW
974 r2 = r;
975 }
976
977 return r2;
978}
979
450442cf
LP
980static int acquire_mount_type(struct udev_device *d) {
981 const char *v;
982
983 assert(d);
984
985 if (arg_mount_type)
986 return 0;
987
988 v = udev_device_get_property_value(d, "ID_FS_TYPE");
989 if (isempty(v))
990 return 0;
991
992 arg_mount_type = strdup(v);
993 if (!arg_mount_type)
994 return log_oom();
995
996 log_debug("Discovered type=%s", arg_mount_type);
997 return 1;
998}
999
1000static int acquire_mount_options(struct udev_device *d) {
1001 const char *v;
1002
1003 if (arg_mount_options)
1004 return 0;
1005
1006 v = udev_device_get_property_value(d, "SYSTEMD_MOUNT_OPTIONS");
1007 if (isempty(v))
1008 return 0;
1009
1010 arg_mount_options = strdup(v);
1011 if (!arg_mount_options)
1012 return log_oom();
1013
1014 log_debug("Discovered options=%s", arg_mount_options);
1015 return 1;
1016}
1017
1018static const char *get_model(struct udev_device *d) {
1019 const char *model;
1020
1021 assert(d);
1022
1023 model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
1024 if (model)
1025 return model;
1026
1027 return udev_device_get_property_value(d, "ID_MODEL");
1028}
1029
1030static const char* get_label(struct udev_device *d) {
1031 const char *label;
1032
1033 assert(d);
1034
1035 label = udev_device_get_property_value(d, "ID_FS_LABEL");
1036 if (label)
1037 return label;
1038
1039 return udev_device_get_property_value(d, "ID_PART_ENTRY_NAME");
1040}
1041
1042static int acquire_mount_where(struct udev_device *d) {
1043 const char *v;
1044
1045 if (arg_mount_where)
1046 return 0;
1047
1048 v = udev_device_get_property_value(d, "SYSTEMD_MOUNT_WHERE");
1049 if (isempty(v)) {
1050 _cleanup_free_ char *escaped = NULL;
1051 const char *name;
1052
1053 name = get_label(d);
1054 if (!name)
1055 name = get_model(d);
1056 if (!name) {
1057 const char *dn;
1058
1059 dn = udev_device_get_devnode(d);
1060 if (!dn)
1061 return 0;
1062
1063 name = basename(dn);
1064 }
1065
1066 escaped = xescape(name, "\\");
f0aac575
YW
1067 if (!escaped)
1068 return log_oom();
450442cf
LP
1069 if (!filename_is_valid(escaped))
1070 return 0;
1071
605405c6 1072 arg_mount_where = strjoin("/run/media/system/", escaped);
450442cf
LP
1073 } else
1074 arg_mount_where = strdup(v);
1075
1076 if (!arg_mount_where)
1077 return log_oom();
1078
1079 log_debug("Discovered where=%s", arg_mount_where);
1080 return 1;
1081}
1082
f0aac575
YW
1083static int acquire_mount_where_for_loop_dev(const char *loop_dev) {
1084 _cleanup_strv_free_ char **list = NULL;
1085 int r;
1086
1087 if (arg_mount_where)
1088 return 0;
1089
1090 r = find_mount_points(loop_dev, &list);
1091 if (r < 0)
1092 return r;
1093 else if (r == 0) {
1094 log_error("Can't find mount point of %s. It is expected that %s is already mounted on a place.", loop_dev, loop_dev);
1095 return -EINVAL;
1096 } else if (r >= 2) {
1097 log_error("%s is mounted on %d places. It is expected that %s is mounted on a place.", loop_dev, r, loop_dev);
1098 return -EINVAL;
1099 }
1100
1101 arg_mount_where = strdup(list[0]);
1102 if (!arg_mount_where)
1103 return log_oom();
1104
1105 log_debug("Discovered where=%s", arg_mount_where);
1106 return 1;
1107}
1108
450442cf
LP
1109static int acquire_description(struct udev_device *d) {
1110 const char *model, *label;
1111
1112 if (arg_description)
1113 return 0;
1114
1115 model = get_model(d);
1116
1117 label = get_label(d);
1118 if (!label)
1119 label = udev_device_get_property_value(d, "ID_PART_ENTRY_NUMBER");
1120
1121 if (model && label)
605405c6 1122 arg_description = strjoin(model, " ", label);
450442cf
LP
1123 else if (label)
1124 arg_description = strdup(label);
1125 else if (model)
1126 arg_description = strdup(model);
1127 else
05b4d3b5 1128 return 0;
450442cf
LP
1129
1130 if (!arg_description)
1131 return log_oom();
1132
1133 log_debug("Discovered description=%s", arg_description);
1134 return 1;
1135}
1136
1137static int acquire_removable(struct udev_device *d) {
1138 const char *v;
1139
1140 /* Shortcut this if there's no reason to check it */
1141 if (arg_action != ACTION_DEFAULT && arg_timeout_idle_set && arg_bind_device >= 0)
1142 return 0;
1143
1144 for (;;) {
1145 v = udev_device_get_sysattr_value(d, "removable");
1146 if (v)
1147 break;
1148
1149 d = udev_device_get_parent(d);
1150 if (!d)
1151 return 0;
1152
1153 if (!streq_ptr(udev_device_get_subsystem(d), "block"))
1154 return 0;
1155 }
1156
1157 if (parse_boolean(v) <= 0)
1158 return 0;
1159
1160 log_debug("Discovered removable device.");
1161
1162 if (arg_action == ACTION_DEFAULT) {
1163 log_debug("Automatically turning on automount.");
1164 arg_action = ACTION_AUTOMOUNT;
1165 }
1166
1167 if (!arg_timeout_idle_set) {
1168 log_debug("Setting idle timeout to 1s.");
1169 arg_timeout_idle = USEC_PER_SEC;
1170 }
1171
1172 if (arg_bind_device < 0) {
1173 log_debug("Binding automount unit to device.");
1174 arg_bind_device = true;
1175 }
1176
1177 return 1;
1178}
1179
f0aac575 1180static int discover_loop_backing_file(void) {
450442cf
LP
1181 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
1182 _cleanup_udev_unref_ struct udev *udev = NULL;
f0aac575 1183 _cleanup_free_ char *loop_dev = NULL;
450442cf
LP
1184 struct stat st;
1185 const char *v;
1186 int r;
1187
f0aac575
YW
1188 r = find_loop_device(arg_mount_what, &loop_dev);
1189 if (r < 0 && r != -ENOENT)
1190 return log_error_errno(errno, "Can't get loop device for %s: %m", arg_mount_what);
1191
1192 if (r == -ENOENT) {
1193 _cleanup_free_ char *escaped = NULL;
1194
1195 if (arg_mount_where)
1196 return 0;
1197
1198 escaped = xescape(basename(arg_mount_what), "\\");
1199 if (!escaped)
1200 return log_oom();
1201 if (!filename_is_valid(escaped))
1202 return -EINVAL;
1203
1204 arg_mount_where = strjoin("/run/media/system/", escaped);
1205 if (!arg_mount_where)
1206 return log_oom();
1207
1208 log_debug("Discovered where=%s", arg_mount_where);
450442cf 1209 return 0;
f0aac575
YW
1210 }
1211
1212 if (stat(loop_dev, &st) < 0)
1213 return log_error_errno(errno, "Can't stat %s: %m", loop_dev);
450442cf 1214
f0aac575
YW
1215 if (!S_ISBLK(st.st_mode)) {
1216 log_error("Invalid file type: %s", loop_dev);
450442cf
LP
1217 return -EINVAL;
1218 }
1219
f0aac575
YW
1220 udev = udev_new();
1221 if (!udev)
1222 return log_oom();
1223
1224 d = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
1225 if (!d)
1226 return log_oom();
1227
1228 v = udev_device_get_property_value(d, "ID_FS_USAGE");
1229 if (!streq_ptr(v, "filesystem")) {
1230 log_error("%s does not contain a known file system.", arg_mount_what);
1231 return -EINVAL;
1232 }
1233
1234 r = acquire_mount_type(d);
1235 if (r < 0)
1236 return r;
1237
1238 r = acquire_mount_options(d);
1239 if (r < 0)
1240 return r;
1241
1242 r = acquire_mount_where_for_loop_dev(loop_dev);
1243 if (r < 0)
1244 return r;
1245
1246 r = acquire_description(d);
1247 if (r < 0)
1248 return r;
1249
1250 return 0;
1251}
1252
1253static int discover_device(void) {
1254 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
1255 _cleanup_udev_unref_ struct udev *udev = NULL;
1256 struct stat st;
1257 const char *v;
1258 int r;
1259
450442cf
LP
1260 if (stat(arg_mount_what, &st) < 0)
1261 return log_error_errno(errno, "Can't stat %s: %m", arg_mount_what);
1262
f0aac575
YW
1263 if (S_ISREG(st.st_mode))
1264 return discover_loop_backing_file();
1265
450442cf 1266 if (!S_ISBLK(st.st_mode)) {
f0aac575
YW
1267 log_error("Invalid file type: %s", arg_mount_what);
1268 return -EINVAL;
450442cf
LP
1269 }
1270
1271 udev = udev_new();
1272 if (!udev)
1273 return log_oom();
1274
1275 d = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
1276 if (!d)
1277 return log_oom();
1278
1279 v = udev_device_get_property_value(d, "ID_FS_USAGE");
1280 if (!streq_ptr(v, "filesystem")) {
9017f5d8 1281 log_error("%s does not contain a known file system.", arg_mount_what);
450442cf
LP
1282 return -EINVAL;
1283 }
1284
1285 r = acquire_mount_type(d);
1286 if (r < 0)
1287 return r;
1288
1289 r = acquire_mount_options(d);
1290 if (r < 0)
1291 return r;
1292
1293 r = acquire_mount_where(d);
1294 if (r < 0)
1295 return r;
1296
1297 r = acquire_description(d);
1298 if (r < 0)
1299 return r;
1300
1301 r = acquire_removable(d);
1302 if (r < 0)
1303 return r;
1304
1305 return 0;
1306}
1307
1308enum {
1309 COLUMN_NODE,
1310 COLUMN_PATH,
1311 COLUMN_MODEL,
1312 COLUMN_WWN,
1313 COLUMN_FSTYPE,
1314 COLUMN_LABEL,
1315 COLUMN_UUID,
1316 _COLUMN_MAX,
1317};
1318
1319struct item {
1320 char* columns[_COLUMN_MAX];
1321};
1322
1323static int compare_item(const void *a, const void *b) {
1324 const struct item *x = a, *y = b;
1325
1326 if (x->columns[COLUMN_NODE] == y->columns[COLUMN_NODE])
1327 return 0;
1328 if (!x->columns[COLUMN_NODE])
1329 return 1;
1330 if (!y->columns[COLUMN_NODE])
1331 return -1;
1332
1333 return path_compare(x->columns[COLUMN_NODE], y->columns[COLUMN_NODE]);
1334}
1335
1336static int list_devices(void) {
1337
1338 static const char * const titles[_COLUMN_MAX] = {
1339 [COLUMN_NODE] = "NODE",
1340 [COLUMN_PATH] = "PATH",
1341 [COLUMN_MODEL] = "MODEL",
1342 [COLUMN_WWN] = "WWN",
1343 [COLUMN_FSTYPE] = "TYPE",
1344 [COLUMN_LABEL] = "LABEL",
1345 [COLUMN_UUID] = "UUID"
1346 };
1347
1348 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
1349 _cleanup_udev_unref_ struct udev *udev = NULL;
1350 struct udev_list_entry *item = NULL, *first = NULL;
1351 size_t n_allocated = 0, n = 0, i;
1352 size_t column_width[_COLUMN_MAX];
1353 struct item *items = NULL;
1354 unsigned c;
1355 int r;
1356
1357 for (c = 0; c < _COLUMN_MAX; c++)
1358 column_width[c] = strlen(titles[c]);
1359
1360 udev = udev_new();
1361 if (!udev)
1362 return log_oom();
1363
1364 e = udev_enumerate_new(udev);
1365 if (!e)
1366 return log_oom();
1367
1368 r = udev_enumerate_add_match_subsystem(e, "block");
1369 if (r < 0)
1370 return log_error_errno(r, "Failed to add block match: %m");
1371
1372 r = udev_enumerate_add_match_property(e, "ID_FS_USAGE", "filesystem");
1373 if (r < 0)
1374 return log_error_errno(r, "Failed to add property match: %m");
1375
1376 r = udev_enumerate_scan_devices(e);
1377 if (r < 0)
1378 return log_error_errno(r, "Failed to scan devices: %m");
1379
1380 first = udev_enumerate_get_list_entry(e);
1381 udev_list_entry_foreach(item, first) {
1382 _cleanup_udev_device_unref_ struct udev_device *d;
1383 struct item *j;
1384
1385 d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
1386 if (!d) {
1387 r = log_oom();
1388 goto finish;
1389 }
1390
1391 if (!GREEDY_REALLOC0(items, n_allocated, n+1)) {
1392 r = log_oom();
1393 goto finish;
1394 }
1395
1396 j = items + n++;
1397
1398 for (c = 0; c < _COLUMN_MAX; c++) {
6fd667e5 1399 const char *x = NULL;
450442cf
LP
1400 size_t k;
1401
1402 switch (c) {
1403
1404 case COLUMN_NODE:
1405 x = udev_device_get_devnode(d);
1406 break;
1407
1408 case COLUMN_PATH:
1409 x = udev_device_get_property_value(d, "ID_PATH");
1410 break;
1411
1412 case COLUMN_MODEL:
1413 x = get_model(d);
1414 break;
1415
1416 case COLUMN_WWN:
1417 x = udev_device_get_property_value(d, "ID_WWN");
1418 break;
1419
1420 case COLUMN_FSTYPE:
1421 x = udev_device_get_property_value(d, "ID_FS_TYPE");
1422 break;
1423
1424 case COLUMN_LABEL:
1425 x = get_label(d);
1426 break;
1427
1428 case COLUMN_UUID:
1429 x = udev_device_get_property_value(d, "ID_FS_UUID");
1430 break;
1431 }
1432
1433 if (isempty(x))
1434 continue;
1435
1436 j->columns[c] = strdup(x);
1437 if (!j->columns[c]) {
1438 r = log_oom();
1439 goto finish;
1440 }
1441
1442 k = strlen(x);
1443 if (k > column_width[c])
1444 column_width[c] = k;
1445 }
1446 }
1447
1448 if (n == 0) {
1449 log_info("No devices found.");
1450 goto finish;
1451 }
1452
1453 qsort_safe(items, n, sizeof(struct item), compare_item);
1454
1455 pager_open(arg_no_pager, false);
1456
1457 fputs(ansi_underline(), stdout);
1458 for (c = 0; c < _COLUMN_MAX; c++) {
1459 if (c > 0)
1460 fputc(' ', stdout);
1461
1462 printf("%-*s", (int) column_width[c], titles[c]);
1463 }
1464 fputs(ansi_normal(), stdout);
1465 fputc('\n', stdout);
1466
1467 for (i = 0; i < n; i++) {
1468 for (c = 0; c < _COLUMN_MAX; c++) {
1469 if (c > 0)
1470 fputc(' ', stdout);
1471
1472 printf("%-*s", (int) column_width[c], strna(items[i].columns[c]));
1473 }
1474 fputc('\n', stdout);
1475 }
1476
1477 r = 0;
1478
1479finish:
1480 for (i = 0; i < n; i++)
1481 for (c = 0; c < _COLUMN_MAX; c++)
1482 free(items[i].columns[c]);
1483
1484 free(items);
1485 return r;
1486}
1487
1488int main(int argc, char* argv[]) {
1489 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1490 int r;
1491
1492 log_parse_environment();
1493 log_open();
1494
1495 r = parse_argv(argc, argv);
1496 if (r <= 0)
1497 goto finish;
1498
1499 if (arg_action == ACTION_LIST) {
1500 r = list_devices();
1501 goto finish;
1502 }
1503
9017f5d8
YW
1504 r = bus_connect_transport_systemd(arg_transport, arg_host, arg_user, &bus);
1505 if (r < 0) {
1506 log_error_errno(r, "Failed to create bus connection: %m");
1507 goto finish;
1508 }
1509
1510 if (arg_action == ACTION_UMOUNT) {
1511 r = action_umount(bus, argc, argv);
1512 goto finish;
1513 }
1514
f0aac575
YW
1515 path_kill_slashes(arg_mount_what);
1516
1517 if (!path_is_safe(arg_mount_what)) {
1518 log_error("Path contains unsafe components: %s", arg_mount_what);
1519 r = -EINVAL;
450442cf 1520 goto finish;
f0aac575
YW
1521 }
1522
1523 if (arg_discover) {
1524 r = discover_device();
1525 if (r < 0)
1526 goto finish;
1527 }
1528
450442cf
LP
1529 if (!arg_mount_where) {
1530 log_error("Can't figure out where to mount %s.", arg_mount_what);
1531 r = -EINVAL;
1532 goto finish;
1533 }
1534
1535 path_kill_slashes(arg_mount_where);
1536
1537 if (path_equal(arg_mount_where, "/")) {
1538 log_error("Refusing to operate on root directory.");
1539 r = -EINVAL;
1540 goto finish;
1541 }
1542
1543 if (!path_is_safe(arg_mount_where)) {
f0aac575 1544 log_error("Path contains unsafe components: %s", arg_mount_where);
450442cf
LP
1545 r = -EINVAL;
1546 goto finish;
1547 }
1548
1549 if (streq_ptr(arg_mount_type, "auto"))
1550 arg_mount_type = mfree(arg_mount_type);
1551 if (streq_ptr(arg_mount_options, "defaults"))
1552 arg_mount_options = mfree(arg_mount_options);
1553
1554 if (!is_device_path(arg_mount_what))
1555 arg_fsck = false;
1556
1557 if (arg_fsck && arg_mount_type && arg_transport == BUS_TRANSPORT_LOCAL) {
1558 r = fsck_exists(arg_mount_type);
1559 if (r < 0)
1560 log_warning_errno(r, "Couldn't determine whether fsck for %s exists, proceeding anyway.", arg_mount_type);
1561 else if (r == 0) {
1562 log_debug("Disabling file system check as fsck for %s doesn't exist.", arg_mount_type);
1563 arg_fsck = false; /* fsck doesn't exist, let's not attempt it */
1564 }
1565 }
1566
450442cf
LP
1567 switch (arg_action) {
1568
1569 case ACTION_MOUNT:
1570 case ACTION_DEFAULT:
1571 r = start_transient_mount(bus, argv + optind);
1572 break;
1573
1574 case ACTION_AUTOMOUNT:
1575 r = start_transient_automount(bus, argv + optind);
1576 break;
1577
1578 default:
1579 assert_not_reached("Unexpected action.");
1580 }
1581
1582finish:
1583 bus = sd_bus_flush_close_unref(bus);
1584
1585 pager_close();
1586
1587 free(arg_mount_what);
1588 free(arg_mount_where);
1589 free(arg_mount_type);
1590 free(arg_mount_options);
1591 free(arg_description);
1592 strv_free(arg_property);
1593 strv_free(arg_automount_property);
1594
1595 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1596}