chiark / gitweb /
ae1a0b75ea143286970cf52bf0b757c19858660e
[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         r = sd_bus_message_append(m, "(sv)", "Description", "s", arg_description);
323         if (r < 0)
324                 return r;
325
326         if (arg_bind_device && is_device_path(arg_mount_what)) {
327                 _cleanup_free_ char *device_unit = NULL;
328
329                 r = unit_name_from_path(arg_mount_what, ".device", &device_unit);
330                 if (r < 0)
331                         return r;
332
333                 r = sd_bus_message_append(m, "(sv)(sv)",
334                                           "After", "as", 1, device_unit,
335                                           "BindsTo", "as", 1, device_unit);
336                 if (r < 0)
337                         return r;
338         }
339
340         r = bus_append_unit_property_assignment_many(m, properties);
341         if (r < 0)
342                 return r;
343
344         return 0;
345 }
346
347 static int transient_mount_set_properties(sd_bus_message *m) {
348         int r;
349
350         assert(m);
351
352         r = transient_unit_set_properties(m, arg_property);
353         if (r < 0)
354                 return r;
355
356         if (arg_mount_what) {
357                 r = sd_bus_message_append(m, "(sv)", "What", "s", arg_mount_what);
358                 if (r < 0)
359                         return r;
360         }
361
362         if (arg_mount_type) {
363                 r = sd_bus_message_append(m, "(sv)", "Type", "s", arg_mount_type);
364                 if (r < 0)
365                         return r;
366         }
367
368         if (arg_mount_options) {
369                 r = sd_bus_message_append(m, "(sv)", "Options", "s", arg_mount_options);
370                 if (r < 0)
371                         return r;
372         }
373
374         if (arg_fsck) {
375                 _cleanup_free_ char *fsck = NULL;
376
377                 r = unit_name_from_path_instance("elogind-fsck", arg_mount_what, ".service", &fsck);
378                 if (r < 0)
379                         return r;
380
381                 r = sd_bus_message_append(m,
382                                           "(sv)(sv)",
383                                           "Requires", "as", 1, fsck,
384                                           "After", "as", 1, fsck);
385                 if (r < 0)
386                         return r;
387         }
388
389         return 0;
390 }
391
392 static int transient_automount_set_properties(sd_bus_message *m) {
393         int r;
394
395         assert(m);
396
397         r = transient_unit_set_properties(m, arg_automount_property);
398         if (r < 0)
399                 return r;
400
401         if (arg_timeout_idle != USEC_INFINITY) {
402                 r = sd_bus_message_append(m, "(sv)", "TimeoutIdleUSec", "t", arg_timeout_idle);
403                 if (r < 0)
404                         return r;
405         }
406
407         return 0;
408 }
409
410 static int start_transient_mount(
411                 sd_bus *bus,
412                 char **argv) {
413
414         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
415         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
416         _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
417         _cleanup_free_ char *mount_unit = NULL;
418         int r;
419
420         if (!arg_no_block) {
421                 r = bus_wait_for_jobs_new(bus, &w);
422                 if (r < 0)
423                         return log_error_errno(r, "Could not watch jobs: %m");
424         }
425
426         r = unit_name_from_path(arg_mount_where, ".mount", &mount_unit);
427         if (r < 0)
428                 return log_error_errno(r, "Failed to make mount unit name: %m");
429
430         r = sd_bus_message_new_method_call(
431                         bus,
432                         &m,
433                         "org.freedesktop.elogind1",
434                         "/org/freedesktop/elogind1",
435                         "org.freedesktop.elogind1.Manager",
436                         "StartTransientUnit");
437         if (r < 0)
438                 return bus_log_create_error(r);
439
440         r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
441         if (r < 0)
442                 return bus_log_create_error(r);
443
444         /* Name and mode */
445         r = sd_bus_message_append(m, "ss", mount_unit, "fail");
446         if (r < 0)
447                 return bus_log_create_error(r);
448
449         /* Properties */
450         r = sd_bus_message_open_container(m, 'a', "(sv)");
451         if (r < 0)
452                 return bus_log_create_error(r);
453
454         r = transient_mount_set_properties(m);
455         if (r < 0)
456                 return bus_log_create_error(r);
457
458         r = sd_bus_message_close_container(m);
459         if (r < 0)
460                 return bus_log_create_error(r);
461
462         /* Auxiliary units */
463         r = sd_bus_message_append(m, "a(sa(sv))", 0);
464         if (r < 0)
465                 return bus_log_create_error(r);
466
467         polkit_agent_open_if_enabled();
468
469         r = sd_bus_call(bus, m, 0, &error, &reply);
470         if (r < 0)
471                 return log_error_errno(r, "Failed to start transient mount unit: %s", bus_error_message(&error, r));
472
473         if (w) {
474                 const char *object;
475
476                 r = sd_bus_message_read(reply, "o", &object);
477                 if (r < 0)
478                         return bus_log_parse_error(r);
479
480                 r = bus_wait_for_jobs_one(w, object, arg_quiet);
481                 if (r < 0)
482                         return r;
483         }
484
485         if (!arg_quiet)
486                 log_info("Started unit %s%s%s for mount point: %s%s%s",
487                          ansi_highlight(), mount_unit, ansi_normal(),
488                          ansi_highlight(), arg_mount_where, ansi_normal());
489
490         return 0;
491 }
492
493 static int start_transient_automount(
494                 sd_bus *bus,
495                 char **argv) {
496
497         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
498         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
499         _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
500         _cleanup_free_ char *automount_unit = NULL, *mount_unit = NULL;
501         int r;
502
503         if (!arg_no_block) {
504                 r = bus_wait_for_jobs_new(bus, &w);
505                 if (r < 0)
506                         return log_error_errno(r, "Could not watch jobs: %m");
507         }
508
509         r = unit_name_from_path(arg_mount_where, ".automount", &automount_unit);
510         if (r < 0)
511                 return log_error_errno(r, "Failed to make automount unit name: %m");
512
513         r = unit_name_from_path(arg_mount_where, ".mount", &mount_unit);
514         if (r < 0)
515                 return log_error_errno(r, "Failed to make mount unit name: %m");
516
517         r = sd_bus_message_new_method_call(
518                         bus,
519                         &m,
520                         "org.freedesktop.elogind1",
521                         "/org/freedesktop/elogind1",
522                         "org.freedesktop.elogind1.Manager",
523                         "StartTransientUnit");
524         if (r < 0)
525                 return bus_log_create_error(r);
526
527         r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
528         if (r < 0)
529                 return bus_log_create_error(r);
530
531         /* Name and mode */
532         r = sd_bus_message_append(m, "ss", automount_unit, "fail");
533         if (r < 0)
534                 return bus_log_create_error(r);
535
536         /* Properties */
537         r = sd_bus_message_open_container(m, 'a', "(sv)");
538         if (r < 0)
539                 return bus_log_create_error(r);
540
541         r = transient_automount_set_properties(m);
542         if (r < 0)
543                 return bus_log_create_error(r);
544
545         r = sd_bus_message_close_container(m);
546         if (r < 0)
547                 return bus_log_create_error(r);
548
549         /* Auxiliary units */
550         r = sd_bus_message_open_container(m, 'a', "(sa(sv))");
551         if (r < 0)
552                 return bus_log_create_error(r);
553
554         r = sd_bus_message_open_container(m, 'r', "sa(sv)");
555         if (r < 0)
556                 return bus_log_create_error(r);
557
558         r = sd_bus_message_append(m, "s", mount_unit);
559         if (r < 0)
560                 return bus_log_create_error(r);
561
562         r = sd_bus_message_open_container(m, 'a', "(sv)");
563         if (r < 0)
564                 return bus_log_create_error(r);
565
566         r = transient_mount_set_properties(m);
567         if (r < 0)
568                 return bus_log_create_error(r);
569
570         r = sd_bus_message_close_container(m);
571         if (r < 0)
572                 return bus_log_create_error(r);
573
574         r = sd_bus_message_close_container(m);
575         if (r < 0)
576                 return bus_log_create_error(r);
577
578         r = sd_bus_message_close_container(m);
579         if (r < 0)
580                 return bus_log_create_error(r);
581
582         polkit_agent_open_if_enabled();
583
584         r = sd_bus_call(bus, m, 0, &error, &reply);
585         if (r < 0)
586                 return log_error_errno(r, "Failed to start transient automount unit: %s", bus_error_message(&error, r));
587
588         if (w) {
589                 const char *object;
590
591                 r = sd_bus_message_read(reply, "o", &object);
592                 if (r < 0)
593                         return bus_log_parse_error(r);
594
595                 r = bus_wait_for_jobs_one(w, object, arg_quiet);
596                 if (r < 0)
597                         return r;
598         }
599
600         if (!arg_quiet)
601                 log_info("Started unit %s%s%s for mount point: %s%s%s",
602                          ansi_highlight(), automount_unit, ansi_normal(),
603                          ansi_highlight(), arg_mount_where, ansi_normal());
604
605         return 0;
606 }
607
608 static int acquire_mount_type(struct udev_device *d) {
609         const char *v;
610
611         assert(d);
612
613         if (arg_mount_type)
614                 return 0;
615
616         v = udev_device_get_property_value(d, "ID_FS_TYPE");
617         if (isempty(v))
618                 return 0;
619
620         arg_mount_type = strdup(v);
621         if (!arg_mount_type)
622                 return log_oom();
623
624         log_debug("Discovered type=%s", arg_mount_type);
625         return 1;
626 }
627
628 static int acquire_mount_options(struct udev_device *d) {
629         const char *v;
630
631         if (arg_mount_options)
632                 return 0;
633
634         v = udev_device_get_property_value(d, "SYSTEMD_MOUNT_OPTIONS");
635         if (isempty(v))
636                 return 0;
637
638         arg_mount_options = strdup(v);
639         if (!arg_mount_options)
640                 return log_oom();
641
642         log_debug("Discovered options=%s", arg_mount_options);
643         return 1;
644 }
645
646 static const char *get_model(struct udev_device *d) {
647         const char *model;
648
649         assert(d);
650
651         model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
652         if (model)
653                 return model;
654
655         return udev_device_get_property_value(d, "ID_MODEL");
656 }
657
658 static const char* get_label(struct udev_device *d) {
659         const char *label;
660
661         assert(d);
662
663         label = udev_device_get_property_value(d, "ID_FS_LABEL");
664         if (label)
665                 return label;
666
667         return udev_device_get_property_value(d, "ID_PART_ENTRY_NAME");
668 }
669
670 static int acquire_mount_where(struct udev_device *d) {
671         const char *v;
672
673         if (arg_mount_where)
674                 return 0;
675
676         v = udev_device_get_property_value(d, "SYSTEMD_MOUNT_WHERE");
677         if (isempty(v)) {
678                 _cleanup_free_ char *escaped = NULL;
679                 const char *name;
680
681                 name = get_label(d);
682                 if (!name)
683                         name = get_model(d);
684                 if (!name) {
685                         const char *dn;
686
687                         dn = udev_device_get_devnode(d);
688                         if (!dn)
689                                 return 0;
690
691                         name = basename(dn);
692                 }
693
694                 escaped = xescape(name, "\\");
695                 if (!filename_is_valid(escaped))
696                         return 0;
697
698                 arg_mount_where = strjoin("/run/media/system/", escaped, NULL);
699         } else
700                 arg_mount_where = strdup(v);
701
702         if (!arg_mount_where)
703                 return log_oom();
704
705         log_debug("Discovered where=%s", arg_mount_where);
706         return 1;
707 }
708
709 static int acquire_description(struct udev_device *d) {
710         const char *model, *label;
711
712         if (arg_description)
713                 return 0;
714
715         model = get_model(d);
716
717         label = get_label(d);
718         if (!label)
719                 label = udev_device_get_property_value(d, "ID_PART_ENTRY_NUMBER");
720
721         if (model && label)
722                 arg_description = strjoin(model, " ", label, NULL);
723         else if (label)
724                 arg_description = strdup(label);
725         else if (model)
726                 arg_description = strdup(model);
727         else
728                 return NULL;
729
730         if (!arg_description)
731                 return log_oom();
732
733         log_debug("Discovered description=%s", arg_description);
734         return 1;
735 }
736
737 static int acquire_removable(struct udev_device *d) {
738         const char *v;
739
740         /* Shortcut this if there's no reason to check it */
741         if (arg_action != ACTION_DEFAULT && arg_timeout_idle_set && arg_bind_device >= 0)
742                 return 0;
743
744         for (;;) {
745                 v = udev_device_get_sysattr_value(d, "removable");
746                 if (v)
747                         break;
748
749                 d = udev_device_get_parent(d);
750                 if (!d)
751                         return 0;
752
753                 if (!streq_ptr(udev_device_get_subsystem(d), "block"))
754                         return 0;
755         }
756
757         if (parse_boolean(v) <= 0)
758                 return 0;
759
760         log_debug("Discovered removable device.");
761
762         if (arg_action == ACTION_DEFAULT) {
763                 log_debug("Automatically turning on automount.");
764                 arg_action = ACTION_AUTOMOUNT;
765         }
766
767         if (!arg_timeout_idle_set) {
768                 log_debug("Setting idle timeout to 1s.");
769                 arg_timeout_idle = USEC_PER_SEC;
770         }
771
772         if (arg_bind_device < 0) {
773                 log_debug("Binding automount unit to device.");
774                 arg_bind_device = true;
775         }
776
777         return 1;
778 }
779
780 static int discover_device(void) {
781         _cleanup_udev_device_unref_ struct udev_device *d = NULL;
782         _cleanup_udev_unref_ struct udev *udev = NULL;
783         struct stat st;
784         const char *v;
785         int r;
786
787         if (!arg_discover)
788                 return 0;
789
790         if (!is_device_path(arg_mount_what)) {
791                 log_error("Discovery only supported for block devices, don't know what to do.");
792                 return -EINVAL;
793         }
794
795         if (stat(arg_mount_what, &st) < 0)
796                 return log_error_errno(errno, "Can't stat %s: %m", arg_mount_what);
797
798         if (!S_ISBLK(st.st_mode)) {
799                 log_error("Path %s is not a block device, don't know what to do.", arg_mount_what);
800                 return -ENOTBLK;
801         }
802
803         udev = udev_new();
804         if (!udev)
805                 return log_oom();
806
807         d = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
808         if (!d)
809                 return log_oom();
810
811         v = udev_device_get_property_value(d, "ID_FS_USAGE");
812         if (!streq_ptr(v, "filesystem")) {
813                 log_error("%s does not contain a file system.", arg_mount_what);
814                 return -EINVAL;
815         }
816
817         r = acquire_mount_type(d);
818         if (r < 0)
819                 return r;
820
821         r = acquire_mount_options(d);
822         if (r < 0)
823                 return r;
824
825         r = acquire_mount_where(d);
826         if (r < 0)
827                 return r;
828
829         r = acquire_description(d);
830         if (r < 0)
831                 return r;
832
833         r = acquire_removable(d);
834         if (r < 0)
835                 return r;
836
837         return 0;
838 }
839
840 enum {
841         COLUMN_NODE,
842         COLUMN_PATH,
843         COLUMN_MODEL,
844         COLUMN_WWN,
845         COLUMN_FSTYPE,
846         COLUMN_LABEL,
847         COLUMN_UUID,
848         _COLUMN_MAX,
849 };
850
851 struct item {
852         char* columns[_COLUMN_MAX];
853 };
854
855 static int compare_item(const void *a, const void *b) {
856         const struct item *x = a, *y = b;
857
858         if (x->columns[COLUMN_NODE] == y->columns[COLUMN_NODE])
859                 return 0;
860         if (!x->columns[COLUMN_NODE])
861                 return 1;
862         if (!y->columns[COLUMN_NODE])
863                 return -1;
864
865         return path_compare(x->columns[COLUMN_NODE], y->columns[COLUMN_NODE]);
866 }
867
868 static int list_devices(void) {
869
870         static const char * const titles[_COLUMN_MAX] = {
871                 [COLUMN_NODE] = "NODE",
872                 [COLUMN_PATH] = "PATH",
873                 [COLUMN_MODEL] = "MODEL",
874                 [COLUMN_WWN] = "WWN",
875                 [COLUMN_FSTYPE] = "TYPE",
876                 [COLUMN_LABEL] = "LABEL",
877                 [COLUMN_UUID] = "UUID"
878         };
879
880         _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
881         _cleanup_udev_unref_ struct udev *udev = NULL;
882         struct udev_list_entry *item = NULL, *first = NULL;
883         size_t n_allocated = 0, n = 0, i;
884         size_t column_width[_COLUMN_MAX];
885         struct item *items = NULL;
886         unsigned c;
887         int r;
888
889         for (c = 0; c < _COLUMN_MAX; c++)
890                 column_width[c] = strlen(titles[c]);
891
892         udev = udev_new();
893         if (!udev)
894                 return log_oom();
895
896         e = udev_enumerate_new(udev);
897         if (!e)
898                 return log_oom();
899
900         r = udev_enumerate_add_match_subsystem(e, "block");
901         if (r < 0)
902                 return log_error_errno(r, "Failed to add block match: %m");
903
904         r = udev_enumerate_add_match_property(e, "ID_FS_USAGE", "filesystem");
905         if (r < 0)
906                 return log_error_errno(r, "Failed to add property match: %m");
907
908         r = udev_enumerate_scan_devices(e);
909         if (r < 0)
910                 return log_error_errno(r, "Failed to scan devices: %m");
911
912         first = udev_enumerate_get_list_entry(e);
913         udev_list_entry_foreach(item, first) {
914                 _cleanup_udev_device_unref_ struct udev_device *d;
915                 struct item *j;
916
917                 d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
918                 if (!d) {
919                         r = log_oom();
920                         goto finish;
921                 }
922
923                 if (!GREEDY_REALLOC0(items, n_allocated, n+1)) {
924                         r = log_oom();
925                         goto finish;
926                 }
927
928                 j = items + n++;
929
930                 for (c = 0; c < _COLUMN_MAX; c++) {
931                         const char *x;
932                         size_t k;
933
934                         switch (c) {
935
936                         case COLUMN_NODE:
937                                 x = udev_device_get_devnode(d);
938                                 break;
939
940                         case COLUMN_PATH:
941                                 x = udev_device_get_property_value(d, "ID_PATH");
942                                 break;
943
944                         case COLUMN_MODEL:
945                                 x = get_model(d);
946                                 break;
947
948                         case COLUMN_WWN:
949                                 x = udev_device_get_property_value(d, "ID_WWN");
950                                 break;
951
952                         case COLUMN_FSTYPE:
953                                 x = udev_device_get_property_value(d, "ID_FS_TYPE");
954                                 break;
955
956                         case COLUMN_LABEL:
957                                 x = get_label(d);
958                                 break;
959
960                         case COLUMN_UUID:
961                                 x = udev_device_get_property_value(d, "ID_FS_UUID");
962                                 break;
963                         }
964
965                         if (isempty(x))
966                                 continue;
967
968                         j->columns[c] = strdup(x);
969                         if (!j->columns[c]) {
970                                 r = log_oom();
971                                 goto finish;
972                         }
973
974                         k = strlen(x);
975                         if (k > column_width[c])
976                                 column_width[c] = k;
977                 }
978         }
979
980         if (n == 0) {
981                 log_info("No devices found.");
982                 goto finish;
983         }
984
985         qsort_safe(items, n, sizeof(struct item), compare_item);
986
987         pager_open(arg_no_pager, false);
988
989         fputs(ansi_underline(), stdout);
990         for (c = 0; c < _COLUMN_MAX; c++) {
991                 if (c > 0)
992                         fputc(' ', stdout);
993
994                 printf("%-*s", (int) column_width[c], titles[c]);
995         }
996         fputs(ansi_normal(), stdout);
997         fputc('\n', stdout);
998
999         for (i = 0; i < n; i++) {
1000                 for (c = 0; c < _COLUMN_MAX; c++) {
1001                         if (c > 0)
1002                                 fputc(' ', stdout);
1003
1004                         printf("%-*s", (int) column_width[c], strna(items[i].columns[c]));
1005                 }
1006                 fputc('\n', stdout);
1007         }
1008
1009         r = 0;
1010
1011 finish:
1012         for (i = 0; i < n; i++)
1013                 for (c = 0; c < _COLUMN_MAX; c++)
1014                         free(items[i].columns[c]);
1015
1016         free(items);
1017         return r;
1018 }
1019
1020 int main(int argc, char* argv[]) {
1021         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1022         int r;
1023
1024         log_parse_environment();
1025         log_open();
1026
1027         r = parse_argv(argc, argv);
1028         if (r <= 0)
1029                 goto finish;
1030
1031         if (arg_action == ACTION_LIST) {
1032                 r = list_devices();
1033                 goto finish;
1034         }
1035
1036         r = discover_device();
1037         if (r < 0)
1038                 goto finish;
1039         if (!arg_mount_where) {
1040                 log_error("Can't figure out where to mount %s.", arg_mount_what);
1041                 r = -EINVAL;
1042                 goto finish;
1043         }
1044
1045         path_kill_slashes(arg_mount_where);
1046
1047         if (path_equal(arg_mount_where, "/")) {
1048                 log_error("Refusing to operate on root directory.");
1049                 r = -EINVAL;
1050                 goto finish;
1051         }
1052
1053         if (!path_is_safe(arg_mount_where)) {
1054                 log_error("Path is contains unsafe components.");
1055                 r = -EINVAL;
1056                 goto finish;
1057         }
1058
1059         if (streq_ptr(arg_mount_type, "auto"))
1060                 arg_mount_type = mfree(arg_mount_type);
1061         if (streq_ptr(arg_mount_options, "defaults"))
1062                 arg_mount_options = mfree(arg_mount_options);
1063
1064         if (!is_device_path(arg_mount_what))
1065                 arg_fsck = false;
1066
1067         if (arg_fsck && arg_mount_type && arg_transport == BUS_TRANSPORT_LOCAL) {
1068                 r = fsck_exists(arg_mount_type);
1069                 if (r < 0)
1070                         log_warning_errno(r, "Couldn't determine whether fsck for %s exists, proceeding anyway.", arg_mount_type);
1071                 else if (r == 0) {
1072                         log_debug("Disabling file system check as fsck for %s doesn't exist.", arg_mount_type);
1073                         arg_fsck = false; /* fsck doesn't exist, let's not attempt it */
1074                 }
1075         }
1076
1077         r = bus_connect_transport_elogind(arg_transport, arg_host, arg_user, &bus);
1078         if (r < 0) {
1079                 log_error_errno(r, "Failed to create bus connection: %m");
1080                 goto finish;
1081         }
1082
1083         switch (arg_action) {
1084
1085         case ACTION_MOUNT:
1086         case ACTION_DEFAULT:
1087                 r = start_transient_mount(bus, argv + optind);
1088                 break;
1089
1090         case ACTION_AUTOMOUNT:
1091                 r = start_transient_automount(bus, argv + optind);
1092                 break;
1093
1094         default:
1095                 assert_not_reached("Unexpected action.");
1096         }
1097
1098 finish:
1099         bus = sd_bus_flush_close_unref(bus);
1100
1101         pager_close();
1102
1103         free(arg_mount_what);
1104         free(arg_mount_where);
1105         free(arg_mount_type);
1106         free(arg_mount_options);
1107         free(arg_description);
1108         strv_free(arg_property);
1109         strv_free(arg_automount_property);
1110
1111         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1112 }