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