chiark / gitweb /
Prep v232: Add libelogind.sym entries for version 232.
[elogind.git] / src / mount / mount-tool.c
1 /***
2   This file is part of elogind.
3
4   Copyright 2016 Lennart Poettering
5
6   elogind 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   elogind 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 elogind; 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"
28 #include "escape.h"
29 #include "fstab-util.h"
30 #include "pager.h"
31 #include "parse-util.h"
32 #include "path-util.h"
33 #include "spawn-polkit-agent.h"
34 #include "strv.h"
35 #include "udev-util.h"
36 #include "unit-name.h"
37 #include "terminal-util.h"
38
39 enum {
40         ACTION_DEFAULT,
41         ACTION_MOUNT,
42         ACTION_AUTOMOUNT,
43         ACTION_LIST,
44 } arg_action = ACTION_DEFAULT;
45
46 static bool arg_no_block = false;
47 static bool arg_no_pager = false;
48 static bool arg_ask_password = true;
49 static bool arg_quiet = false;
50 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
51 static bool arg_user = false;
52 static const char *arg_host = NULL;
53 static bool arg_discover = false;
54 static char *arg_mount_what = NULL;
55 static char *arg_mount_where = NULL;
56 static char *arg_mount_type = NULL;
57 static char *arg_mount_options = NULL;
58 static char *arg_description = NULL;
59 static char **arg_property = NULL;
60 static usec_t arg_timeout_idle = USEC_INFINITY;
61 static bool arg_timeout_idle_set = false;
62 static char **arg_automount_property = NULL;
63 static int arg_bind_device = -1;
64 static bool arg_fsck = true;
65
66 static void polkit_agent_open_if_enabled(void) {
67
68         /* Open the polkit agent as a child process if necessary */
69         if (!arg_ask_password)
70                 return;
71
72         if (arg_transport != BUS_TRANSPORT_LOCAL)
73                 return;
74
75         polkit_agent_open();
76 }
77
78 static void help(void) {
79         printf("%s [OPTIONS...] WHAT [WHERE]\n\n"
80                "Establish a mount or auto-mount point transiently.\n\n"
81                "  -h --help                       Show this help\n"
82                "     --version                    Show package version\n"
83                "     --no-block                   Do not wait until operation finished\n"
84                "     --no-pager                   Do not pipe output into a pager\n"
85                "     --no-ask-password            Do not prompt for password\n"
86                "  -q --quiet                      Suppress information messages during runtime\n"
87                "     --user                       Run as user unit\n"
88                "  -H --host=[USER@]HOST           Operate on remote host\n"
89                "  -M --machine=CONTAINER          Operate on local container\n"
90                "     --discover                   Discover mount device metadata\n"
91                "  -t --type=TYPE                  File system type\n"
92                "  -o --options=OPTIONS            Mount options\n"
93                "     --fsck=no                    Don't run file system check before mount\n"
94                "     --description=TEXT           Description for unit\n"
95                "  -p --property=NAME=VALUE        Set mount unit property\n"
96                "  -A --automount=BOOL             Create an auto-mount point\n"
97                "     --timeout-idle-sec=SEC       Specify automount idle timeout\n"
98                "     --automount-property=NAME=VALUE\n"
99                "                                  Set automount unit property\n"
100                "     --bind-device                Bind automount unit to device\n"
101                "     --list                       List mountable block devices\n"
102                , program_invocation_short_name);
103 }
104
105 static int parse_argv(int argc, char *argv[]) {
106
107         enum {
108                 ARG_VERSION = 0x100,
109                 ARG_NO_BLOCK,
110                 ARG_NO_PAGER,
111                 ARG_NO_ASK_PASSWORD,
112                 ARG_USER,
113                 ARG_SYSTEM,
114                 ARG_DISCOVER,
115                 ARG_MOUNT_TYPE,
116                 ARG_MOUNT_OPTIONS,
117                 ARG_FSCK,
118                 ARG_DESCRIPTION,
119                 ARG_TIMEOUT_IDLE,
120                 ARG_AUTOMOUNT,
121                 ARG_AUTOMOUNT_PROPERTY,
122                 ARG_BIND_DEVICE,
123                 ARG_LIST,
124         };
125
126         static const struct option options[] = {
127                 { "help",               no_argument,       NULL, 'h'                    },
128                 { "version",            no_argument,       NULL, ARG_VERSION            },
129                 { "no-block",           no_argument,       NULL, ARG_NO_BLOCK           },
130                 { "no-pager",           no_argument,       NULL, ARG_NO_PAGER           },
131                 { "no-ask-password",    no_argument,       NULL, ARG_NO_ASK_PASSWORD    },
132                 { "quiet",              no_argument,       NULL, 'q'                    },
133                 { "user",               no_argument,       NULL, ARG_USER               },
134                 { "system",             no_argument,       NULL, ARG_SYSTEM             },
135                 { "host",               required_argument, NULL, 'H'                    },
136                 { "machine",            required_argument, NULL, 'M'                    },
137                 { "discover",           no_argument,       NULL, ARG_DISCOVER           },
138                 { "type",               required_argument, NULL, 't'                    },
139                 { "options",            required_argument, NULL, 'o'                    },
140                 { "description",        required_argument, NULL, ARG_DESCRIPTION        },
141                 { "property",           required_argument, NULL, 'p'                    },
142                 { "automount",          required_argument, NULL, ARG_AUTOMOUNT          },
143                 { "timeout-idle-sec",   required_argument, NULL, ARG_TIMEOUT_IDLE       },
144                 { "automount-property", required_argument, NULL, ARG_AUTOMOUNT_PROPERTY },
145                 { "bind-device",        no_argument,       NULL, ARG_BIND_DEVICE        },
146                 { "list",               no_argument,       NULL, ARG_LIST               },
147                 {},
148         };
149
150         int r, c;
151
152         assert(argc >= 0);
153         assert(argv);
154
155         while ((c = getopt_long(argc, argv, "hqH:M:t:o:p:A", options, NULL)) >= 0)
156
157                 switch (c) {
158
159                 case 'h':
160                         help();
161                         return 0;
162
163                 case ARG_VERSION:
164                         return version();
165
166                 case ARG_NO_BLOCK:
167                         arg_no_block = true;
168                         break;
169
170                 case ARG_NO_PAGER:
171                         arg_no_pager = true;
172                         break;
173
174                 case ARG_NO_ASK_PASSWORD:
175                         arg_ask_password = false;
176                         break;
177
178                 case 'q':
179                         arg_quiet = true;
180                         break;
181
182                 case ARG_USER:
183                         arg_user = true;
184                         break;
185
186                 case ARG_SYSTEM:
187                         arg_user = false;
188                         break;
189
190                 case 'H':
191                         arg_transport = BUS_TRANSPORT_REMOTE;
192                         arg_host = optarg;
193                         break;
194
195                 case 'M':
196                         arg_transport = BUS_TRANSPORT_MACHINE;
197                         arg_host = optarg;
198                         break;
199
200                 case ARG_DISCOVER:
201                         arg_discover = true;
202                         break;
203
204                 case 't':
205                         if (free_and_strdup(&arg_mount_type, optarg) < 0)
206                                 return log_oom();
207                         break;
208
209                 case 'o':
210                         if (free_and_strdup(&arg_mount_options, optarg) < 0)
211                                 return log_oom();
212                         break;
213
214                 case ARG_FSCK:
215                         r = parse_boolean(optarg);
216                         if (r < 0)
217                                 return log_error_errno(r, "Failed to parse --fsck= argument: %s", optarg);
218
219                         arg_fsck = r;
220                         break;
221
222                 case ARG_DESCRIPTION:
223                         if (free_and_strdup(&arg_description, optarg) < 0)
224                                 return log_oom();
225                         break;
226
227                 case 'p':
228                         if (strv_extend(&arg_property, optarg) < 0)
229                                 return log_oom();
230
231                         break;
232
233                 case 'A':
234                         arg_action = ACTION_AUTOMOUNT;
235                         break;
236
237                 case ARG_AUTOMOUNT:
238                         r = parse_boolean(optarg);
239                         if (r < 0)
240                                 return log_error_errno(r, "--automount= expects a valid boolean parameter: %s", optarg);
241
242                         arg_action = r ? ACTION_AUTOMOUNT : ACTION_MOUNT;
243                         break;
244
245                 case ARG_TIMEOUT_IDLE:
246                         r = parse_sec(optarg, &arg_timeout_idle);
247                         if (r < 0)
248                                 return log_error_errno(r, "Failed to parse timeout: %s", optarg);
249
250                         break;
251
252                 case ARG_AUTOMOUNT_PROPERTY:
253                         if (strv_extend(&arg_automount_property, optarg) < 0)
254                                 return log_oom();
255
256                         break;
257
258                 case ARG_BIND_DEVICE:
259                         arg_bind_device = true;
260                         break;
261
262                 case ARG_LIST:
263                         arg_action = ACTION_LIST;
264                         break;
265
266                 case '?':
267                         return -EINVAL;
268
269                 default:
270                         assert_not_reached("Unhandled option");
271                 }
272
273         if (arg_user && arg_transport != BUS_TRANSPORT_LOCAL) {
274                 log_error("Execution in user context is not supported on non-local systems.");
275                 return -EINVAL;
276         }
277
278         if (arg_action == ACTION_LIST) {
279                 if (optind < argc) {
280                         log_error("Too many arguments.");
281                         return -EINVAL;
282                 }
283
284                 if (arg_transport != BUS_TRANSPORT_LOCAL) {
285                         log_error("Listing devices only supported locally.");
286                         return -EOPNOTSUPP;
287                 }
288         } else {
289                 if (optind >= argc) {
290                         log_error("At least one argument required.");
291                         return -EINVAL;
292                 }
293
294                 if (argc > optind+2) {
295                         log_error("At most two arguments required.");
296                         return -EINVAL;
297                 }
298
299                 arg_mount_what = fstab_node_to_udev_node(argv[optind]);
300                 if (!arg_mount_what)
301                         return log_oom();
302
303                 if (argc > optind+1) {
304                         r = path_make_absolute_cwd(argv[optind+1], &arg_mount_where);
305                         if (r < 0)
306                                 return log_error_errno(r, "Failed to make path absolute: %m");
307                 } else
308                         arg_discover = true;
309
310                 if (arg_discover && arg_transport != BUS_TRANSPORT_LOCAL) {
311                         log_error("Automatic mount location discovery is only supported locally.");
312                         return -EOPNOTSUPP;
313                 }
314         }
315
316         return 1;
317 }
318
319 static int transient_unit_set_properties(sd_bus_message *m, char **properties) {
320         int r;
321
322         if (!isempty(arg_description)) {
323                 r = sd_bus_message_append(m, "(sv)", "Description", "s", arg_description);
324                 if (r < 0)
325                         return r;
326         }
327
328         if (arg_bind_device && is_device_path(arg_mount_what)) {
329                 _cleanup_free_ char *device_unit = NULL;
330
331                 r = unit_name_from_path(arg_mount_what, ".device", &device_unit);
332                 if (r < 0)
333                         return r;
334
335                 r = sd_bus_message_append(m, "(sv)(sv)",
336                                           "After", "as", 1, device_unit,
337                                           "BindsTo", "as", 1, device_unit);
338                 if (r < 0)
339                         return r;
340         }
341
342         r = bus_append_unit_property_assignment_many(m, properties);
343         if (r < 0)
344                 return r;
345
346         return 0;
347 }
348
349 static int transient_mount_set_properties(sd_bus_message *m) {
350         int r;
351
352         assert(m);
353
354         r = transient_unit_set_properties(m, arg_property);
355         if (r < 0)
356                 return r;
357
358         if (arg_mount_what) {
359                 r = sd_bus_message_append(m, "(sv)", "What", "s", arg_mount_what);
360                 if (r < 0)
361                         return r;
362         }
363
364         if (arg_mount_type) {
365                 r = sd_bus_message_append(m, "(sv)", "Type", "s", arg_mount_type);
366                 if (r < 0)
367                         return r;
368         }
369
370         if (arg_mount_options) {
371                 r = sd_bus_message_append(m, "(sv)", "Options", "s", arg_mount_options);
372                 if (r < 0)
373                         return r;
374         }
375
376         if (arg_fsck) {
377                 _cleanup_free_ char *fsck = NULL;
378
379                 r = unit_name_from_path_instance("elogind-fsck", arg_mount_what, ".service", &fsck);
380                 if (r < 0)
381                         return r;
382
383                 r = sd_bus_message_append(m,
384                                           "(sv)(sv)",
385                                           "Requires", "as", 1, fsck,
386                                           "After", "as", 1, fsck);
387                 if (r < 0)
388                         return r;
389         }
390
391         return 0;
392 }
393
394 static int transient_automount_set_properties(sd_bus_message *m) {
395         int r;
396
397         assert(m);
398
399         r = transient_unit_set_properties(m, arg_automount_property);
400         if (r < 0)
401                 return r;
402
403         if (arg_timeout_idle != USEC_INFINITY) {
404                 r = sd_bus_message_append(m, "(sv)", "TimeoutIdleUSec", "t", arg_timeout_idle);
405                 if (r < 0)
406                         return r;
407         }
408
409         return 0;
410 }
411
412 static int start_transient_mount(
413                 sd_bus *bus,
414                 char **argv) {
415
416         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
417         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
418         _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
419         _cleanup_free_ char *mount_unit = NULL;
420         int r;
421
422         if (!arg_no_block) {
423                 r = bus_wait_for_jobs_new(bus, &w);
424                 if (r < 0)
425                         return log_error_errno(r, "Could not watch jobs: %m");
426         }
427
428         r = unit_name_from_path(arg_mount_where, ".mount", &mount_unit);
429         if (r < 0)
430                 return log_error_errno(r, "Failed to make mount unit name: %m");
431
432         r = sd_bus_message_new_method_call(
433                         bus,
434                         &m,
435                         "org.freedesktop.elogind1",
436                         "/org/freedesktop/elogind1",
437                         "org.freedesktop.elogind1.Manager",
438                         "StartTransientUnit");
439         if (r < 0)
440                 return bus_log_create_error(r);
441
442         r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
443         if (r < 0)
444                 return bus_log_create_error(r);
445
446         /* Name and mode */
447         r = sd_bus_message_append(m, "ss", mount_unit, "fail");
448         if (r < 0)
449                 return bus_log_create_error(r);
450
451         /* Properties */
452         r = sd_bus_message_open_container(m, 'a', "(sv)");
453         if (r < 0)
454                 return bus_log_create_error(r);
455
456         r = transient_mount_set_properties(m);
457         if (r < 0)
458                 return bus_log_create_error(r);
459
460         r = sd_bus_message_close_container(m);
461         if (r < 0)
462                 return bus_log_create_error(r);
463
464         /* Auxiliary units */
465         r = sd_bus_message_append(m, "a(sa(sv))", 0);
466         if (r < 0)
467                 return bus_log_create_error(r);
468
469         polkit_agent_open_if_enabled();
470
471         r = sd_bus_call(bus, m, 0, &error, &reply);
472         if (r < 0)
473                 return log_error_errno(r, "Failed to start transient mount unit: %s", bus_error_message(&error, r));
474
475         if (w) {
476                 const char *object;
477
478                 r = sd_bus_message_read(reply, "o", &object);
479                 if (r < 0)
480                         return bus_log_parse_error(r);
481
482                 r = bus_wait_for_jobs_one(w, object, arg_quiet);
483                 if (r < 0)
484                         return r;
485         }
486
487         if (!arg_quiet)
488                 log_info("Started unit %s%s%s for mount point: %s%s%s",
489                          ansi_highlight(), mount_unit, ansi_normal(),
490                          ansi_highlight(), arg_mount_where, ansi_normal());
491
492         return 0;
493 }
494
495 static int start_transient_automount(
496                 sd_bus *bus,
497                 char **argv) {
498
499         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
500         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
501         _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
502         _cleanup_free_ char *automount_unit = NULL, *mount_unit = NULL;
503         int r;
504
505         if (!arg_no_block) {
506                 r = bus_wait_for_jobs_new(bus, &w);
507                 if (r < 0)
508                         return log_error_errno(r, "Could not watch jobs: %m");
509         }
510
511         r = unit_name_from_path(arg_mount_where, ".automount", &automount_unit);
512         if (r < 0)
513                 return log_error_errno(r, "Failed to make automount unit name: %m");
514
515         r = unit_name_from_path(arg_mount_where, ".mount", &mount_unit);
516         if (r < 0)
517                 return log_error_errno(r, "Failed to make mount unit name: %m");
518
519         r = sd_bus_message_new_method_call(
520                         bus,
521                         &m,
522                         "org.freedesktop.elogind1",
523                         "/org/freedesktop/elogind1",
524                         "org.freedesktop.elogind1.Manager",
525                         "StartTransientUnit");
526         if (r < 0)
527                 return bus_log_create_error(r);
528
529         r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
530         if (r < 0)
531                 return bus_log_create_error(r);
532
533         /* Name and mode */
534         r = sd_bus_message_append(m, "ss", automount_unit, "fail");
535         if (r < 0)
536                 return bus_log_create_error(r);
537
538         /* Properties */
539         r = sd_bus_message_open_container(m, 'a', "(sv)");
540         if (r < 0)
541                 return bus_log_create_error(r);
542
543         r = transient_automount_set_properties(m);
544         if (r < 0)
545                 return bus_log_create_error(r);
546
547         r = sd_bus_message_close_container(m);
548         if (r < 0)
549                 return bus_log_create_error(r);
550
551         /* Auxiliary units */
552         r = sd_bus_message_open_container(m, 'a', "(sa(sv))");
553         if (r < 0)
554                 return bus_log_create_error(r);
555
556         r = sd_bus_message_open_container(m, 'r', "sa(sv)");
557         if (r < 0)
558                 return bus_log_create_error(r);
559
560         r = sd_bus_message_append(m, "s", mount_unit);
561         if (r < 0)
562                 return bus_log_create_error(r);
563
564         r = sd_bus_message_open_container(m, 'a', "(sv)");
565         if (r < 0)
566                 return bus_log_create_error(r);
567
568         r = transient_mount_set_properties(m);
569         if (r < 0)
570                 return bus_log_create_error(r);
571
572         r = sd_bus_message_close_container(m);
573         if (r < 0)
574                 return bus_log_create_error(r);
575
576         r = sd_bus_message_close_container(m);
577         if (r < 0)
578                 return bus_log_create_error(r);
579
580         r = sd_bus_message_close_container(m);
581         if (r < 0)
582                 return bus_log_create_error(r);
583
584         polkit_agent_open_if_enabled();
585
586         r = sd_bus_call(bus, m, 0, &error, &reply);
587         if (r < 0)
588                 return log_error_errno(r, "Failed to start transient automount unit: %s", bus_error_message(&error, r));
589
590         if (w) {
591                 const char *object;
592
593                 r = sd_bus_message_read(reply, "o", &object);
594                 if (r < 0)
595                         return bus_log_parse_error(r);
596
597                 r = bus_wait_for_jobs_one(w, object, arg_quiet);
598                 if (r < 0)
599                         return r;
600         }
601
602         if (!arg_quiet)
603                 log_info("Started unit %s%s%s for mount point: %s%s%s",
604                          ansi_highlight(), automount_unit, ansi_normal(),
605                          ansi_highlight(), arg_mount_where, ansi_normal());
606
607         return 0;
608 }
609
610 static int acquire_mount_type(struct udev_device *d) {
611         const char *v;
612
613         assert(d);
614
615         if (arg_mount_type)
616                 return 0;
617
618         v = udev_device_get_property_value(d, "ID_FS_TYPE");
619         if (isempty(v))
620                 return 0;
621
622         arg_mount_type = strdup(v);
623         if (!arg_mount_type)
624                 return log_oom();
625
626         log_debug("Discovered type=%s", arg_mount_type);
627         return 1;
628 }
629
630 static int acquire_mount_options(struct udev_device *d) {
631         const char *v;
632
633         if (arg_mount_options)
634                 return 0;
635
636         v = udev_device_get_property_value(d, "SYSTEMD_MOUNT_OPTIONS");
637         if (isempty(v))
638                 return 0;
639
640         arg_mount_options = strdup(v);
641         if (!arg_mount_options)
642                 return log_oom();
643
644         log_debug("Discovered options=%s", arg_mount_options);
645         return 1;
646 }
647
648 static const char *get_model(struct udev_device *d) {
649         const char *model;
650
651         assert(d);
652
653         model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
654         if (model)
655                 return model;
656
657         return udev_device_get_property_value(d, "ID_MODEL");
658 }
659
660 static const char* get_label(struct udev_device *d) {
661         const char *label;
662
663         assert(d);
664
665         label = udev_device_get_property_value(d, "ID_FS_LABEL");
666         if (label)
667                 return label;
668
669         return udev_device_get_property_value(d, "ID_PART_ENTRY_NAME");
670 }
671
672 static int acquire_mount_where(struct udev_device *d) {
673         const char *v;
674
675         if (arg_mount_where)
676                 return 0;
677
678         v = udev_device_get_property_value(d, "SYSTEMD_MOUNT_WHERE");
679         if (isempty(v)) {
680                 _cleanup_free_ char *escaped = NULL;
681                 const char *name;
682
683                 name = get_label(d);
684                 if (!name)
685                         name = get_model(d);
686                 if (!name) {
687                         const char *dn;
688
689                         dn = udev_device_get_devnode(d);
690                         if (!dn)
691                                 return 0;
692
693                         name = basename(dn);
694                 }
695
696                 escaped = xescape(name, "\\");
697                 if (!filename_is_valid(escaped))
698                         return 0;
699
700                 arg_mount_where = strjoin("/run/media/system/", escaped, NULL);
701         } else
702                 arg_mount_where = strdup(v);
703
704         if (!arg_mount_where)
705                 return log_oom();
706
707         log_debug("Discovered where=%s", arg_mount_where);
708         return 1;
709 }
710
711 static int acquire_description(struct udev_device *d) {
712         const char *model, *label;
713
714         if (arg_description)
715                 return 0;
716
717         model = get_model(d);
718
719         label = get_label(d);
720         if (!label)
721                 label = udev_device_get_property_value(d, "ID_PART_ENTRY_NUMBER");
722
723         if (model && label)
724                 arg_description = strjoin(model, " ", label, NULL);
725         else if (label)
726                 arg_description = strdup(label);
727         else if (model)
728                 arg_description = strdup(model);
729         else
730                 return 0;
731
732         if (!arg_description)
733                 return log_oom();
734
735         log_debug("Discovered description=%s", arg_description);
736         return 1;
737 }
738
739 static int acquire_removable(struct udev_device *d) {
740         const char *v;
741
742         /* Shortcut this if there's no reason to check it */
743         if (arg_action != ACTION_DEFAULT && arg_timeout_idle_set && arg_bind_device >= 0)
744                 return 0;
745
746         for (;;) {
747                 v = udev_device_get_sysattr_value(d, "removable");
748                 if (v)
749                         break;
750
751                 d = udev_device_get_parent(d);
752                 if (!d)
753                         return 0;
754
755                 if (!streq_ptr(udev_device_get_subsystem(d), "block"))
756                         return 0;
757         }
758
759         if (parse_boolean(v) <= 0)
760                 return 0;
761
762         log_debug("Discovered removable device.");
763
764         if (arg_action == ACTION_DEFAULT) {
765                 log_debug("Automatically turning on automount.");
766                 arg_action = ACTION_AUTOMOUNT;
767         }
768
769         if (!arg_timeout_idle_set) {
770                 log_debug("Setting idle timeout to 1s.");
771                 arg_timeout_idle = USEC_PER_SEC;
772         }
773
774         if (arg_bind_device < 0) {
775                 log_debug("Binding automount unit to device.");
776                 arg_bind_device = true;
777         }
778
779         return 1;
780 }
781
782 static int discover_device(void) {
783         _cleanup_udev_device_unref_ struct udev_device *d = NULL;
784         _cleanup_udev_unref_ struct udev *udev = NULL;
785         struct stat st;
786         const char *v;
787         int r;
788
789         if (!arg_discover)
790                 return 0;
791
792         if (!is_device_path(arg_mount_what)) {
793                 log_error("Discovery only supported for block devices, don't know what to do.");
794                 return -EINVAL;
795         }
796
797         if (stat(arg_mount_what, &st) < 0)
798                 return log_error_errno(errno, "Can't stat %s: %m", arg_mount_what);
799
800         if (!S_ISBLK(st.st_mode)) {
801                 log_error("Path %s is not a block device, don't know what to do.", arg_mount_what);
802                 return -ENOTBLK;
803         }
804
805         udev = udev_new();
806         if (!udev)
807                 return log_oom();
808
809         d = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
810         if (!d)
811                 return log_oom();
812
813         v = udev_device_get_property_value(d, "ID_FS_USAGE");
814         if (!streq_ptr(v, "filesystem")) {
815                 log_error("%s does not contain a file system.", arg_mount_what);
816                 return -EINVAL;
817         }
818
819         r = acquire_mount_type(d);
820         if (r < 0)
821                 return r;
822
823         r = acquire_mount_options(d);
824         if (r < 0)
825                 return r;
826
827         r = acquire_mount_where(d);
828         if (r < 0)
829                 return r;
830
831         r = acquire_description(d);
832         if (r < 0)
833                 return r;
834
835         r = acquire_removable(d);
836         if (r < 0)
837                 return r;
838
839         return 0;
840 }
841
842 enum {
843         COLUMN_NODE,
844         COLUMN_PATH,
845         COLUMN_MODEL,
846         COLUMN_WWN,
847         COLUMN_FSTYPE,
848         COLUMN_LABEL,
849         COLUMN_UUID,
850         _COLUMN_MAX,
851 };
852
853 struct item {
854         char* columns[_COLUMN_MAX];
855 };
856
857 static int compare_item(const void *a, const void *b) {
858         const struct item *x = a, *y = b;
859
860         if (x->columns[COLUMN_NODE] == y->columns[COLUMN_NODE])
861                 return 0;
862         if (!x->columns[COLUMN_NODE])
863                 return 1;
864         if (!y->columns[COLUMN_NODE])
865                 return -1;
866
867         return path_compare(x->columns[COLUMN_NODE], y->columns[COLUMN_NODE]);
868 }
869
870 static int list_devices(void) {
871
872         static const char * const titles[_COLUMN_MAX] = {
873                 [COLUMN_NODE] = "NODE",
874                 [COLUMN_PATH] = "PATH",
875                 [COLUMN_MODEL] = "MODEL",
876                 [COLUMN_WWN] = "WWN",
877                 [COLUMN_FSTYPE] = "TYPE",
878                 [COLUMN_LABEL] = "LABEL",
879                 [COLUMN_UUID] = "UUID"
880         };
881
882         _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
883         _cleanup_udev_unref_ struct udev *udev = NULL;
884         struct udev_list_entry *item = NULL, *first = NULL;
885         size_t n_allocated = 0, n = 0, i;
886         size_t column_width[_COLUMN_MAX];
887         struct item *items = NULL;
888         unsigned c;
889         int r;
890
891         for (c = 0; c < _COLUMN_MAX; c++)
892                 column_width[c] = strlen(titles[c]);
893
894         udev = udev_new();
895         if (!udev)
896                 return log_oom();
897
898         e = udev_enumerate_new(udev);
899         if (!e)
900                 return log_oom();
901
902         r = udev_enumerate_add_match_subsystem(e, "block");
903         if (r < 0)
904                 return log_error_errno(r, "Failed to add block match: %m");
905
906         r = udev_enumerate_add_match_property(e, "ID_FS_USAGE", "filesystem");
907         if (r < 0)
908                 return log_error_errno(r, "Failed to add property match: %m");
909
910         r = udev_enumerate_scan_devices(e);
911         if (r < 0)
912                 return log_error_errno(r, "Failed to scan devices: %m");
913
914         first = udev_enumerate_get_list_entry(e);
915         udev_list_entry_foreach(item, first) {
916                 _cleanup_udev_device_unref_ struct udev_device *d;
917                 struct item *j;
918
919                 d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
920                 if (!d) {
921                         r = log_oom();
922                         goto finish;
923                 }
924
925                 if (!GREEDY_REALLOC0(items, n_allocated, n+1)) {
926                         r = log_oom();
927                         goto finish;
928                 }
929
930                 j = items + n++;
931
932                 for (c = 0; c < _COLUMN_MAX; c++) {
933                         const char *x;
934                         size_t k;
935
936                         switch (c) {
937
938                         case COLUMN_NODE:
939                                 x = udev_device_get_devnode(d);
940                                 break;
941
942                         case COLUMN_PATH:
943                                 x = udev_device_get_property_value(d, "ID_PATH");
944                                 break;
945
946                         case COLUMN_MODEL:
947                                 x = get_model(d);
948                                 break;
949
950                         case COLUMN_WWN:
951                                 x = udev_device_get_property_value(d, "ID_WWN");
952                                 break;
953
954                         case COLUMN_FSTYPE:
955                                 x = udev_device_get_property_value(d, "ID_FS_TYPE");
956                                 break;
957
958                         case COLUMN_LABEL:
959                                 x = get_label(d);
960                                 break;
961
962                         case COLUMN_UUID:
963                                 x = udev_device_get_property_value(d, "ID_FS_UUID");
964                                 break;
965                         }
966
967                         if (isempty(x))
968                                 continue;
969
970                         j->columns[c] = strdup(x);
971                         if (!j->columns[c]) {
972                                 r = log_oom();
973                                 goto finish;
974                         }
975
976                         k = strlen(x);
977                         if (k > column_width[c])
978                                 column_width[c] = k;
979                 }
980         }
981
982         if (n == 0) {
983                 log_info("No devices found.");
984                 goto finish;
985         }
986
987         qsort_safe(items, n, sizeof(struct item), compare_item);
988
989         pager_open(arg_no_pager, false);
990
991         fputs(ansi_underline(), stdout);
992         for (c = 0; c < _COLUMN_MAX; c++) {
993                 if (c > 0)
994                         fputc(' ', stdout);
995
996                 printf("%-*s", (int) column_width[c], titles[c]);
997         }
998         fputs(ansi_normal(), stdout);
999         fputc('\n', stdout);
1000
1001         for (i = 0; i < n; i++) {
1002                 for (c = 0; c < _COLUMN_MAX; c++) {
1003                         if (c > 0)
1004                                 fputc(' ', stdout);
1005
1006                         printf("%-*s", (int) column_width[c], strna(items[i].columns[c]));
1007                 }
1008                 fputc('\n', stdout);
1009         }
1010
1011         r = 0;
1012
1013 finish:
1014         for (i = 0; i < n; i++)
1015                 for (c = 0; c < _COLUMN_MAX; c++)
1016                         free(items[i].columns[c]);
1017
1018         free(items);
1019         return r;
1020 }
1021
1022 int main(int argc, char* argv[]) {
1023         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1024         int r;
1025
1026         log_parse_environment();
1027         log_open();
1028
1029         r = parse_argv(argc, argv);
1030         if (r <= 0)
1031                 goto finish;
1032
1033         if (arg_action == ACTION_LIST) {
1034                 r = list_devices();
1035                 goto finish;
1036         }
1037
1038         r = discover_device();
1039         if (r < 0)
1040                 goto finish;
1041         if (!arg_mount_where) {
1042                 log_error("Can't figure out where to mount %s.", arg_mount_what);
1043                 r = -EINVAL;
1044                 goto finish;
1045         }
1046
1047         path_kill_slashes(arg_mount_where);
1048
1049         if (path_equal(arg_mount_where, "/")) {
1050                 log_error("Refusing to operate on root directory.");
1051                 r = -EINVAL;
1052                 goto finish;
1053         }
1054
1055         if (!path_is_safe(arg_mount_where)) {
1056                 log_error("Path is contains unsafe components.");
1057                 r = -EINVAL;
1058                 goto finish;
1059         }
1060
1061         if (streq_ptr(arg_mount_type, "auto"))
1062                 arg_mount_type = mfree(arg_mount_type);
1063         if (streq_ptr(arg_mount_options, "defaults"))
1064                 arg_mount_options = mfree(arg_mount_options);
1065
1066         if (!is_device_path(arg_mount_what))
1067                 arg_fsck = false;
1068
1069         if (arg_fsck && arg_mount_type && arg_transport == BUS_TRANSPORT_LOCAL) {
1070                 r = fsck_exists(arg_mount_type);
1071                 if (r < 0)
1072                         log_warning_errno(r, "Couldn't determine whether fsck for %s exists, proceeding anyway.", arg_mount_type);
1073                 else if (r == 0) {
1074                         log_debug("Disabling file system check as fsck for %s doesn't exist.", arg_mount_type);
1075                         arg_fsck = false; /* fsck doesn't exist, let's not attempt it */
1076                 }
1077         }
1078
1079         r = bus_connect_transport_elogind(arg_transport, arg_host, arg_user, &bus);
1080         if (r < 0) {
1081                 log_error_errno(r, "Failed to create bus connection: %m");
1082                 goto finish;
1083         }
1084
1085         switch (arg_action) {
1086
1087         case ACTION_MOUNT:
1088         case ACTION_DEFAULT:
1089                 r = start_transient_mount(bus, argv + optind);
1090                 break;
1091
1092         case ACTION_AUTOMOUNT:
1093                 r = start_transient_automount(bus, argv + optind);
1094                 break;
1095
1096         default:
1097                 assert_not_reached("Unexpected action.");
1098         }
1099
1100 finish:
1101         bus = sd_bus_flush_close_unref(bus);
1102
1103         pager_close();
1104
1105         free(arg_mount_what);
1106         free(arg_mount_where);
1107         free(arg_mount_type);
1108         free(arg_mount_options);
1109         free(arg_description);
1110         strv_free(arg_property);
1111         strv_free(arg_automount_property);
1112
1113         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1114 }