]> git.ipfire.org Git - thirdparty/openembedded/openembedded-core-contrib.git/commitdiff
systemd: backport transient mounts from 232
authorAndreas Oberritter <obi@opendreambox.org>
Sat, 28 Jan 2017 20:49:24 +0000 (21:49 +0100)
committerAndreas Oberritter <obi@opendreambox.org>
Tue, 17 Oct 2017 02:38:27 +0000 (04:38 +0200)
Signed-off-by: Andreas Oberritter <obi@opendreambox.org>
meta/recipes-core/systemd/systemd/0026-automount-implement-transient-automounts.patch [new file with mode: 0644]
meta/recipes-core/systemd/systemd/0027-mount-use-get_mount_parameters_fragment-consistently.patch [new file with mode: 0644]
meta/recipes-core/systemd/systemd/0028-mount-write-drop-in-file-when-setting-transient-prop.patch [new file with mode: 0644]
meta/recipes-core/systemd/systemd/0029-bus-util-unify-loop-around-bus_append_unit_property_.patch [new file with mode: 0644]
meta/recipes-core/systemd/systemd/0030-run-various-minor-improvements.patch [new file with mode: 0644]
meta/recipes-core/systemd/systemd/0031-add-a-new-tool-for-creating-transient-mount-and-auto.patch [new file with mode: 0644]
meta/recipes-core/systemd/systemd_230.bb

diff --git a/meta/recipes-core/systemd/systemd/0026-automount-implement-transient-automounts.patch b/meta/recipes-core/systemd/systemd/0026-automount-implement-transient-automounts.patch
new file mode 100644 (file)
index 0000000..11a8f07
--- /dev/null
@@ -0,0 +1,98 @@
+From fb7177b2a03f7456c3ea5b2b2c3b51835eff70fd Mon Sep 17 00:00:00 2001
+From: Michael Olbrich <m.olbrich@pengutronix.de>
+Date: Wed, 9 Dec 2015 15:46:46 +0100
+Subject: [PATCH] automount: implement transient automounts
+
+(cherry picked from commit afb14803b34a9f4abf5265365aebe9a3132344c2)
+---
+ src/core/automount.c      |  3 +++
+ src/core/dbus-automount.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++
+ src/core/dbus-automount.h |  2 ++
+ 3 files changed, 59 insertions(+)
+
+diff --git a/src/core/automount.c b/src/core/automount.c
+index a9d0d7a..b8d385d 100644
+--- a/src/core/automount.c
++++ b/src/core/automount.c
+@@ -1110,6 +1110,9 @@ const UnitVTable automount_vtable = {
+         .reset_failed = automount_reset_failed,
+         .bus_vtable = bus_automount_vtable,
++        .bus_set_property = bus_automount_set_property,
++
++        .can_transient = true,
+         .shutdown = automount_shutdown,
+         .supported = automount_supported,
+diff --git a/src/core/dbus-automount.c b/src/core/dbus-automount.c
+index b2806ad..26212b3 100644
+--- a/src/core/dbus-automount.c
++++ b/src/core/dbus-automount.c
+@@ -32,3 +32,57 @@ const sd_bus_vtable bus_automount_vtable[] = {
+         SD_BUS_PROPERTY("TimeoutIdleUSec", "t", bus_property_get_usec, offsetof(Automount, timeout_idle_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+         SD_BUS_VTABLE_END
+ };
++
++static int bus_automount_set_transient_property(
++                Automount *a,
++                const char *name,
++                sd_bus_message *message,
++                UnitSetPropertiesMode mode,
++                sd_bus_error *error) {
++
++        int r;
++
++        assert(a);
++        assert(name);
++        assert(message);
++
++        if (streq(name, "TimeoutIdleUSec")) {
++                usec_t timeout_idle_usec;
++                r = sd_bus_message_read(message, "t", &timeout_idle_usec);
++                if (r < 0)
++                        return r;
++
++                if (mode != UNIT_CHECK) {
++                        char time[FORMAT_TIMESPAN_MAX];
++
++                        a->timeout_idle_usec = timeout_idle_usec;
++                        unit_write_drop_in_format(UNIT(a), mode, name, "[Automount]\nTimeoutIdleSec=%s\n",
++                                format_timespan(time, sizeof(time), timeout_idle_usec, USEC_PER_MSEC));
++                }
++        } else
++                return 0;
++
++        return 1;
++}
++
++int bus_automount_set_property(
++                Unit *u,
++                const char *name,
++                sd_bus_message *message,
++                UnitSetPropertiesMode mode,
++                sd_bus_error *error) {
++
++        Automount *a = AUTOMOUNT(u);
++        int r = 0;
++
++        assert(a);
++        assert(name);
++        assert(message);
++
++        if (u->transient && u->load_state == UNIT_STUB)
++                /* This is a transient unit, let's load a little more */
++
++                r = bus_automount_set_transient_property(a, name, message, mode, error);
++
++        return r;
++}
+diff --git a/src/core/dbus-automount.h b/src/core/dbus-automount.h
+index 7b51eb9..f41adda 100644
+--- a/src/core/dbus-automount.h
++++ b/src/core/dbus-automount.h
+@@ -21,3 +21,5 @@
+ extern const sd_bus_vtable bus_automount_vtable[];
++
++int bus_automount_set_property(Unit *u, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error);
diff --git a/meta/recipes-core/systemd/systemd/0027-mount-use-get_mount_parameters_fragment-consistently.patch b/meta/recipes-core/systemd/systemd/0027-mount-use-get_mount_parameters_fragment-consistently.patch
new file mode 100644 (file)
index 0000000..440e96a
--- /dev/null
@@ -0,0 +1,114 @@
+From 7f38735fa33f37ebe547b8849c1e5be8a1182693 Mon Sep 17 00:00:00 2001
+From: Michael Olbrich <m.olbrich@pengutronix.de>
+Date: Wed, 9 Dec 2015 16:02:10 +0100
+Subject: [PATCH] mount: use get_mount_parameters_fragment() consistently
+
+There are multiple different checks, that all mean the same thing:
+Is it a explicitly configured mount unit where actions need to be taken to
+mount it, or is is just mirroring 'mountinfo':
+'from_fragment' to set if fragment_path is not NULL, and
+get_mount_parameters_fragment() just wraps that and returns fragment_path.
+
+Use get_mount_parameters_fragment() everywhere to be consistent.
+This is just a cleanup without functional change.
+
+(cherry picked from commit b294b79fb0f9749afa53624c8f06b145ea2c1525)
+---
+ src/core/mount.c | 34 ++++++++++++++++------------------
+ 1 file changed, 16 insertions(+), 18 deletions(-)
+
+diff --git a/src/core/mount.c b/src/core/mount.c
+index 665a60b..7b20892 100644
+--- a/src/core/mount.c
++++ b/src/core/mount.c
+@@ -482,6 +482,7 @@ static int mount_add_default_dependencies(Mount *m) {
+ static int mount_verify(Mount *m) {
+         _cleanup_free_ char *e = NULL;
++        MountParameters *p;
+         int r;
+         assert(m);
+@@ -506,7 +507,8 @@ static int mount_verify(Mount *m) {
+                 return -EINVAL;
+         }
+-        if (UNIT(m)->fragment_path && !m->parameters_fragment.what) {
++        p = get_mount_parameters_fragment(m);
++        if (p && !p->what) {
+                 log_unit_error(UNIT(m), "What= setting is missing. Refusing.");
+                 return -EBADMSG;
+         }
+@@ -850,11 +852,6 @@ fail:
+         mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
+ }
+-static int mount_get_opts(Mount *m, char **ret) {
+-        return fstab_filter_options(m->parameters_fragment.options,
+-                                    "nofail\0" "noauto\0" "auto\0", NULL, NULL, ret);
+-}
+-
+ static void mount_enter_mounting(Mount *m) {
+         int r;
+         MountParameters *p;
+@@ -877,19 +874,18 @@ static void mount_enter_mounting(Mount *m) {
+         if (p && mount_is_bind(p))
+                 (void) mkdir_p_label(p->what, m->directory_mode);
+-        if (m->from_fragment) {
++        if (p) {
+                 _cleanup_free_ char *opts = NULL;
+-                r = mount_get_opts(m, &opts);
++                r = fstab_filter_options(p->options, "nofail\0" "noauto\0" "auto\0", NULL, NULL, &opts);
+                 if (r < 0)
+                         goto fail;
+-                r = exec_command_set(m->control_command, MOUNT_PATH,
+-                                     m->parameters_fragment.what, m->where, NULL);
++                r = exec_command_set(m->control_command, MOUNT_PATH, p->what, m->where, NULL);
+                 if (r >= 0 && m->sloppy_options)
+                         r = exec_command_append(m->control_command, "-s", NULL);
+-                if (r >= 0 && m->parameters_fragment.fstype)
+-                        r = exec_command_append(m->control_command, "-t", m->parameters_fragment.fstype, NULL);
++                if (r >= 0 && p->fstype)
++                        r = exec_command_append(m->control_command, "-t", p->fstype, NULL);
+                 if (r >= 0 && !isempty(opts))
+                         r = exec_command_append(m->control_command, "-o", opts, NULL);
+         } else
+@@ -915,27 +911,29 @@ fail:
+ static void mount_enter_remounting(Mount *m) {
+         int r;
++        MountParameters *p;
+         assert(m);
+         m->control_command_id = MOUNT_EXEC_REMOUNT;
+         m->control_command = m->exec_command + MOUNT_EXEC_REMOUNT;
+-        if (m->from_fragment) {
++        p = get_mount_parameters_fragment(m);
++        if (p) {
+                 const char *o;
+-                if (m->parameters_fragment.options)
+-                        o = strjoina("remount,", m->parameters_fragment.options);
++                if (p->options)
++                        o = strjoina("remount,", p->options);
+                 else
+                         o = "remount";
+                 r = exec_command_set(m->control_command, MOUNT_PATH,
+-                                     m->parameters_fragment.what, m->where,
++                                     p->what, m->where,
+                                      "-o", o, NULL);
+                 if (r >= 0 && m->sloppy_options)
+                         r = exec_command_append(m->control_command, "-s", NULL);
+-                if (r >= 0 && m->parameters_fragment.fstype)
+-                        r = exec_command_append(m->control_command, "-t", m->parameters_fragment.fstype, NULL);
++                if (r >= 0 && p->fstype)
++                        r = exec_command_append(m->control_command, "-t", p->fstype, NULL);
+         } else
+                 r = -ENOENT;
diff --git a/meta/recipes-core/systemd/systemd/0028-mount-write-drop-in-file-when-setting-transient-prop.patch b/meta/recipes-core/systemd/systemd/0028-mount-write-drop-in-file-when-setting-transient-prop.patch
new file mode 100644 (file)
index 0000000..8580529
--- /dev/null
@@ -0,0 +1,29 @@
+From 26aed187f452644b833e061d28029b675ff32d04 Mon Sep 17 00:00:00 2001
+From: Michael Olbrich <m.olbrich@pengutronix.de>
+Date: Wed, 9 Dec 2015 16:02:51 +0100
+Subject: [PATCH] mount: write drop-in file when setting transient properties
+
+This fixes transient mount units in general. With this change,
+'from_fragment' is for transient mount units. As a result, the normal logic
+for 'fragment' mount units vs. 'mountinfo'  mount units works for transient
+mount units as well.
+
+(cherry picked from commit 96f5957f1f0d98584bb463d73616a6755e02624b)
+---
+ src/core/dbus-mount.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c
+index 935db7c..b4bbee0 100644
+--- a/src/core/dbus-mount.c
++++ b/src/core/dbus-mount.c
+@@ -157,6 +157,9 @@ static int bus_mount_set_transient_property(
+                 if (!p)
+                         return -ENOMEM;
++                unit_write_drop_in_format(UNIT(m), mode, name, "[Mount]\n%s=%s\n",
++                        name, new_property);
++
+                 free(*property);
+                 *property = p;
+         }
diff --git a/meta/recipes-core/systemd/systemd/0029-bus-util-unify-loop-around-bus_append_unit_property_.patch b/meta/recipes-core/systemd/systemd/0029-bus-util-unify-loop-around-bus_append_unit_property_.patch
new file mode 100644 (file)
index 0000000..f4c03e7
--- /dev/null
@@ -0,0 +1,136 @@
+From 76fdcb03aaa2fc8cd7483e628eef8a089afc1dfd Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Fri, 5 Aug 2016 18:32:42 +0200
+Subject: [PATCH] bus-util: unify loop around
+ bus_append_unit_property_assignment()
+
+This is done exactly the same way a couple of times at various places, let's
+unify this into one version.
+
+(cherry picked from commit 8673cf13c08998b50818346b703ad91fe5facfdf)
+---
+ src/nspawn/nspawn-register.c |  9 +++------
+ src/run/run.c                |  9 +++------
+ src/shared/bus-unit-util.c   | 15 +++++++++++++++
+ src/shared/bus-unit-util.h   |  1 +
+ src/systemctl/systemctl.c    |  9 +++------
+ 5 files changed, 25 insertions(+), 18 deletions(-)
+
+diff --git a/src/nspawn/nspawn-register.c b/src/nspawn/nspawn-register.c
+index 20103c5..3022184 100644
+--- a/src/nspawn/nspawn-register.c
++++ b/src/nspawn/nspawn-register.c
+@@ -68,7 +68,6 @@ int register_machine(
+                                 local_ifindex > 0 ? 1 : 0, local_ifindex);
+         } else {
+                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+-                char **i;
+                 unsigned j;
+                 r = sd_bus_message_new_method_call(
+@@ -164,11 +163,9 @@ int register_machine(
+                                 return bus_log_create_error(r);
+                 }
+-                STRV_FOREACH(i, properties) {
+-                        r = bus_append_unit_property_assignment(m, *i);
+-                        if (r < 0)
+-                                return r;
+-                }
++                r = bus_append_unit_property_assignment_many(m, properties);
++                if (r < 0)
++                        return r;
+                 r = sd_bus_message_close_container(m);
+                 if (r < 0)
+diff --git a/src/run/run.c b/src/run/run.c
+index d6c9b6d..4b22cb7 100644
+--- a/src/run/run.c
++++ b/src/run/run.c
+@@ -412,18 +412,15 @@ static int parse_argv(int argc, char *argv[]) {
+ }
+ static int transient_unit_set_properties(sd_bus_message *m, char **properties) {
+-        char **i;
+         int r;
+         r = sd_bus_message_append(m, "(sv)", "Description", "s", arg_description);
+         if (r < 0)
+                 return r;
+-        STRV_FOREACH(i, properties) {
+-                r = bus_append_unit_property_assignment(m, *i);
+-                if (r < 0)
+-                        return r;
+-        }
++        r = bus_append_unit_property_assignment_many(m, properties);
++        if (r < 0)
++                return r;
+         return 0;
+ }
+diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
+index f6559cd..53cb293 100644
+--- a/src/shared/bus-unit-util.c
++++ b/src/shared/bus-unit-util.c
+@@ -542,6 +542,21 @@ finish:
+         return 0;
+ }
++int bus_append_unit_property_assignment_many(sd_bus_message *m, char **l) {
++        char **i;
++        int r;
++
++        assert(m);
++
++        STRV_FOREACH(i, l) {
++                r = bus_append_unit_property_assignment(m, *i);
++                if (r < 0)
++                        return r;
++        }
++
++        return 0;
++}
++
+ typedef struct BusWaitForJobs {
+         sd_bus *bus;
+         Set *jobs;
+diff --git a/src/shared/bus-unit-util.h b/src/shared/bus-unit-util.h
+index c0c172f..d102ea1 100644
+--- a/src/shared/bus-unit-util.h
++++ b/src/shared/bus-unit-util.h
+@@ -41,6 +41,7 @@ typedef struct UnitInfo {
+ int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u);
+ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment);
++int bus_append_unit_property_assignment_many(sd_bus_message *m, char **l);
+ typedef struct BusWaitForJobs BusWaitForJobs;
+diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
+index b943c68..4e2da68 100644
+--- a/src/systemctl/systemctl.c
++++ b/src/systemctl/systemctl.c
+@@ -4922,7 +4922,6 @@ static int set_property(int argc, char *argv[], void *userdata) {
+         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+         _cleanup_free_ char *n = NULL;
+         sd_bus *bus;
+-        char **i;
+         int r;
+         polkit_agent_open_if_enabled();
+@@ -4953,11 +4952,9 @@ static int set_property(int argc, char *argv[], void *userdata) {
+         if (r < 0)
+                 return bus_log_create_error(r);
+-        STRV_FOREACH(i, strv_skip(argv, 2)) {
+-                r = bus_append_unit_property_assignment(m, *i);
+-                if (r < 0)
+-                        return r;
+-        }
++        r = bus_append_unit_property_assignment_many(m, strv_skip(argv, 2));
++        if (r < 0)
++                return r;
+         r = sd_bus_message_close_container(m);
+         if (r < 0)
diff --git a/meta/recipes-core/systemd/systemd/0030-run-various-minor-improvements.patch b/meta/recipes-core/systemd/systemd/0030-run-various-minor-improvements.patch
new file mode 100644 (file)
index 0000000..297bc2f
--- /dev/null
@@ -0,0 +1,104 @@
+From 8fd26d09a3ec01e09be6ba86b4c6390f6cff6165 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Sat, 6 Aug 2016 00:30:12 +0200
+Subject: [PATCH] run: various minor improvements
+
+Let's improve the --help text a bit, and other changes.
+
+(cherry picked from commit ad2c17019a2a25ace8d604b069124b361874139a)
+---
+ man/systemd-run.xml |  2 +-
+ src/run/run.c       | 22 ++++++++++------------
+ 2 files changed, 11 insertions(+), 13 deletions(-)
+
+diff --git a/man/systemd-run.xml b/man/systemd-run.xml
+index 9c1a292..1a30c07 100644
+--- a/man/systemd-run.xml
++++ b/man/systemd-run.xml
+@@ -45,7 +45,7 @@
+   <refnamediv>
+     <refname>systemd-run</refname>
+-    <refpurpose>Run programs in transient scope or service or timer units</refpurpose>
++    <refpurpose>Run programs in transient scope units, service units, or timer-scheduled service units</refpurpose>
+   </refnamediv>
+   <refsynopsisdiv>
+diff --git a/src/run/run.c b/src/run/run.c
+index 4b22cb7..f9a73f4 100644
+--- a/src/run/run.c
++++ b/src/run/run.c
+@@ -83,9 +83,7 @@ static void polkit_agent_open_if_enabled(void) {
+ static void help(void) {
+         printf("%s [OPTIONS...] {COMMAND} [ARGS...]\n\n"
+-               "Run the specified command in a transient scope or service or timer\n"
+-               "unit. If a timer option is specified and the unit specified with\n"
+-               "the --unit option exists, the command can be omitted.\n\n"
++               "Run the specified command in a transient scope or service.\n\n"
+                "  -h --help                       Show this help\n"
+                "     --version                    Show package version\n"
+                "     --no-ask-password            Do not prompt for password\n"
+@@ -94,7 +92,7 @@ static void help(void) {
+                "  -M --machine=CONTAINER          Operate on local container\n"
+                "     --scope                      Run this as scope rather than service\n"
+                "     --unit=UNIT                  Run under the specified unit name\n"
+-               "  -p --property=NAME=VALUE        Set unit property\n"
++               "  -p --property=NAME=VALUE        Set service or scope unit property\n"
+                "     --description=TEXT           Description for unit\n"
+                "     --slice=SLICE                Run in the specified slice\n"
+                "     --no-block                   Do not wait until operation finished\n"
+@@ -107,15 +105,15 @@ static void help(void) {
+                "  -E --setenv=NAME=VALUE          Set environment\n"
+                "  -t --pty                        Run service on pseudo tty\n"
+                "  -q --quiet                      Suppress information messages during runtime\n\n"
+-               "Timer options:\n\n"
++               "Timer options:\n"
+                "     --on-active=SECONDS          Run after SECONDS delay\n"
+                "     --on-boot=SECONDS            Run SECONDS after machine was booted up\n"
+                "     --on-startup=SECONDS         Run SECONDS after systemd activation\n"
+                "     --on-unit-active=SECONDS     Run SECONDS after the last activation\n"
+                "     --on-unit-inactive=SECONDS   Run SECONDS after the last deactivation\n"
+                "     --on-calendar=SPEC           Realtime timer\n"
+-               "     --timer-property=NAME=VALUE  Set timer unit property\n",
+-               program_invocation_short_name);
++               "     --timer-property=NAME=VALUE  Set timer unit property\n"
++               , program_invocation_short_name);
+ }
+ static bool with_timer(void) {
+@@ -178,7 +176,7 @@ static int parse_argv(int argc, char *argv[]) {
+                 { "on-calendar",       required_argument, NULL, ARG_ON_CALENDAR      },
+                 { "timer-property",    required_argument, NULL, ARG_TIMER_PROPERTY   },
+                 { "no-block",          no_argument,       NULL, ARG_NO_BLOCK         },
+-                { "no-ask-password",   no_argument,       NULL, ARG_NO_ASK_PASSWORD },
++                { "no-ask-password",   no_argument,       NULL, ARG_NO_ASK_PASSWORD  },
+                 {},
+         };
+@@ -195,13 +193,13 @@ static int parse_argv(int argc, char *argv[]) {
+                         help();
+                         return 0;
++                case ARG_VERSION:
++                        return version();
++
+                 case ARG_NO_ASK_PASSWORD:
+                         arg_ask_password = false;
+                         break;
+-                case ARG_VERSION:
+-                        return version();
+-
+                 case ARG_USER:
+                         arg_user = true;
+                         break;
+@@ -1143,7 +1141,7 @@ static int start_transient_timer(
+         if (r < 0)
+                 return bus_log_create_error(r);
+-        if (argv[0]) {
++        if (!strv_isempty(argv)) {
+                 r = sd_bus_message_open_container(m, 'r', "sa(sv)");
+                 if (r < 0)
+                         return bus_log_create_error(r);
diff --git a/meta/recipes-core/systemd/systemd/0031-add-a-new-tool-for-creating-transient-mount-and-auto.patch b/meta/recipes-core/systemd/systemd/0031-add-a-new-tool-for-creating-transient-mount-and-auto.patch
new file mode 100644 (file)
index 0000000..86e401b
--- /dev/null
@@ -0,0 +1,1572 @@
+From 2e4f639b0f4aab11f2bbc173f26d90f7d75a5432 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Sat, 6 Aug 2016 00:32:46 +0200
+Subject: [PATCH] add a new tool for creating transient mount and automount
+ units
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This adds "systemd-mount" which is for transient mount and automount units what
+"systemd-run" is for transient service, scope and timer units.
+
+The tool allows establishing mounts and automounts during runtime. It is very
+similar to the usual /bin/mount commands, but can pull in additional
+dependenices on access (for example, it pulls in fsck automatically), an take
+benefit of the automount logic.
+
+This tool is particularly useful for mount removable file systems (such as USB
+sticks), as the automount logic (together with automatic unmount-on-idle), as
+well as automatic fsck on first access ensure that the removable file system
+has a high chance to remain in a fully clean state even when it is unplugged
+abruptly, and returns to a clean state on the next re-plug.
+
+This is a follow-up for #2471, as it adds a simple client-side for the
+transient automount logic added in that PR.
+
+In later work it might make sense to invoke this tool automatically from udev
+rules in order to implement a simpler and safer version of removable media
+management Ã¡ la udisks.
+
+(cherry picked from commit 450442cf93375af58161c1a9b973e3dfba60cba0)
+---
+ .gitignore               |    1 +
+ Makefile-man.am          |    2 +
+ Makefile.am              |    8 +
+ man/standard-options.xml |    6 +
+ man/systemd-mount.xml    |  295 ++++++++++++
+ man/systemd-run.xml      |    1 +
+ src/basic/mount-util.c   |    1 -
+ src/mount/Makefile       |    1 +
+ src/mount/mount-tool.c   | 1112 ++++++++++++++++++++++++++++++++++++++++++++++
+ 9 files changed, 1426 insertions(+), 1 deletion(-)
+ create mode 100644 man/systemd-mount.xml
+ create mode 120000 src/mount/Makefile
+ create mode 100644 src/mount/mount-tool.c
+
+diff --git a/.gitignore b/.gitignore
+index 091b400..0afe09e 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -89,6 +89,7 @@
+ /systemd-machine-id-setup
+ /systemd-machined
+ /systemd-modules-load
++/systemd-mount
+ /systemd-networkd
+ /systemd-networkd-wait-online
+ /systemd-notify
+diff --git a/Makefile-man.am b/Makefile-man.am
+index d5b328d..56a7384 100644
+--- a/Makefile-man.am
++++ b/Makefile-man.am
+@@ -116,6 +116,7 @@ MANPAGES += \
+       man/systemd-journald.service.8 \
+       man/systemd-machine-id-commit.service.8 \
+       man/systemd-machine-id-setup.1 \
++      man/systemd-mount.1 \
+       man/systemd-notify.1 \
+       man/systemd-nspawn.1 \
+       man/systemd-path.1 \
+@@ -2631,6 +2632,7 @@ EXTRA_DIST += \
+       man/systemd-machine-id-setup.xml \
+       man/systemd-machined.service.xml \
+       man/systemd-modules-load.service.xml \
++      man/systemd-mount.xml \
+       man/systemd-networkd-wait-online.service.xml \
+       man/systemd-networkd.service.xml \
+       man/systemd-notify.xml \
+diff --git a/Makefile.am b/Makefile.am
+index 305099a..fbdda0d 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -376,6 +376,7 @@ bin_PROGRAMS = \
+       systemd-delta \
+       systemd-analyze \
+       systemd-run \
++      systemd-mount \
+       systemd-stdio-bridge \
+       systemd-path
+@@ -3070,6 +3071,13 @@ systemd_run_LDADD = \
+       libshared.la
+ # ------------------------------------------------------------------------------
++systemd_mount_SOURCES = \
++      src/mount/mount-tool.c
++
++systemd_mount_LDADD = \
++      libshared.la
++
++# ------------------------------------------------------------------------------
+ systemd_stdio_bridge_SOURCES = \
+       src/stdio-bridge/stdio-bridge.c
+diff --git a/man/standard-options.xml b/man/standard-options.xml
+index f214463..f718451 100644
+--- a/man/standard-options.xml
++++ b/man/standard-options.xml
+@@ -28,6 +28,12 @@
+     </listitem>
+   </varlistentry>
++  <varlistentry id='no-ask-password'>
++    <term><option>--no-ask-password</option></term>
++
++    <listitem><para>Do not query the user for authentication for privileged operations.</para></listitem>
++  </varlistentry>
++
+   <varlistentry id='no-legend'>
+     <term><option>--no-legend</option></term>
+diff --git a/man/systemd-mount.xml b/man/systemd-mount.xml
+new file mode 100644
+index 0000000..e6c0786
+--- /dev/null
++++ b/man/systemd-mount.xml
+@@ -0,0 +1,295 @@
++<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
++"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
++
++<!--
++  This file is part of systemd.
++
++  Copyright 2016 Lennart Poettering
++
++  systemd is free software; you can redistribute it and/or modify it
++  under the terms of the GNU Lesser General Public License as published by
++  the Free Software Foundation; either version 2.1 of the License, or
++  (at your option) any later version.
++
++  systemd is distributed in the hope that it will be useful, but
++  WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public License
++  along with systemd; If not, see <http://www.gnu.org/licenses/>.
++-->
++
++<refentry id="systemd-mount"
++          xmlns:xi="http://www.w3.org/2001/XInclude">
++
++  <refentryinfo>
++    <title>systemd-mount</title>
++    <productname>systemd</productname>
++
++    <authorgroup>
++      <author>
++        <contrib>Developer</contrib>
++        <firstname>Lennart</firstname>
++        <surname>Poettering</surname>
++        <email>lennart@poettering.net</email>
++      </author>
++    </authorgroup>
++  </refentryinfo>
++
++  <refmeta>
++    <refentrytitle>systemd-mount</refentrytitle>
++    <manvolnum>1</manvolnum>
++  </refmeta>
++
++  <refnamediv>
++    <refname>systemd-mount</refname>
++    <refpurpose>Establish a mount or auto-mount point transiently</refpurpose>
++  </refnamediv>
++
++  <refsynopsisdiv>
++    <cmdsynopsis>
++      <command>systemd-mount</command>
++      <arg choice="opt" rep="repeat"><replaceable>OPTIONS</replaceable></arg>
++      <arg choice="plain"><replaceable>WHAT</replaceable></arg>
++      <arg choice="opt"><replaceable>WHERE</replaceable></arg>
++    </cmdsynopsis>
++    <cmdsynopsis>
++      <command>systemd-mount</command>
++      <arg choice="opt" rep="repeat"><replaceable>OPTIONS</replaceable></arg>
++      <arg choice="plain"><option>--list</option></arg>
++    </cmdsynopsis>
++  </refsynopsisdiv>
++
++  <refsect1>
++    <title>Description</title>
++
++    <para><command>systemd-mount</command> may be used to create and start a transient <filename>.mount</filename> or
++    <filename>.automount</filename> unit of the file system <replaceable>WHAT</replaceable> on the mount point
++    <replaceable>WHERE</replaceable>.</para>
++
++    <para>In many ways, <command>systemd-mount</command> is similar to the lower-level
++    <citerefentry><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry> command, however instead
++    of executing the mount operation directly and immediately, <command>systemd-mount</command> schedules it through
++    the service manager job queue, so that it may pull in further dependencies (such as parent mounts, or a file system
++    checker to execute a priori), and may make use of the auto-mounting logic.</para>
++
++    <para>The command takes either one or two arguments. If only one argument is specified it should refer to a block
++    device containing a file system (e.g. <literal>/dev/sdb1</literal>), which is then probed for a label and other
++    metadata, and is mounted to a directory whose name is generated from the label. In this mode the block device must
++    exist at the time of invocation of the command, so that it may be probed. If the device is found to be a removable
++    block device (e.g. a USB stick) an automount point instead of a regular mount point is created (i.e. the
++    <option>--automount=</option> option is implied, see below).</para>
++
++    <para>If two arguments are specified the first indicates the mount source (the <replaceable>WHAT</replaceable>) and
++    the second indicates the path to mount it on (the <replaceable>WHERE</replaceable>). In this mode no probing of the
++    source is attempted, and a backing device node doesn't have to exist yet. However, if this mode is combined with
++    <option>--discover</option>, device node probing for additional metadata is enabled, and â€“ much like in the
++    single-argument case discussed above â€“ the specified device has to exist at the time of invocation of the
++    command.</para>
++
++    <para>Use the <option>--list</option> command to show a terse table of all local, known block devices with file
++    systems that may be mounted with this command.</para>
++  </refsect1>
++
++  <refsect1>
++    <title>Options</title>
++
++    <para>The following options are understood:</para>
++
++    <variablelist>
++
++      <varlistentry>
++        <term><option>--no-block</option></term>
++
++        <listitem>
++          <para>Do not synchronously wait for the requested operation to finish. If this is not specified, the job will
++          be verified, enqueued and <command>systemd-mount</command> will wait until the mount or automount unit's
++          start-up is completed. By passing this argument, it is only verified and enqueued.</para>
++        </listitem>
++      </varlistentry>
++
++      <xi:include href="standard-options.xml" xpointer="no-pager"/>
++      <xi:include href="standard-options.xml" xpointer="no-ask-password"/>
++
++      <varlistentry>
++        <term><option>--quiet</option></term>
++        <term><option>-q</option></term>
++
++        <listitem><para>Suppresses additional informational output while running.</para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><option>--discover</option></term>
++
++        <listitem><para>Enable probing of the mount source. This switch is implied if a single argument is specified on
++        the command line. If passed, additional metadata is read from the device to enhance the unit to create. For
++        example, a descriptive string for the transient units is generated from the file system label and device
++        model. Moreover if a removable block device (e.g. USB stick) is detected an automount unit instead of a regular
++        mount unit is created, with a short idle time-out, in order to ensure the file-system is placed in a clean
++        state quickly after each access.</para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><option>--type=</option></term>
++        <term><option>-t</option></term>
++
++        <listitem><para>Specifies the file system type to mount (e.g. <literal>vfat</literal>, <literal>ext4</literal>,
++        â€¦). If omitted (or set to <literal>auto</literal>) the file system is determined automatically.</para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><option>--options=</option></term>
++        <term><option>-o</option></term>
++
++        <listitem><para>Additional mount options for the mount point.</para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><option>--fsck=</option></term>
++
++        <listitem><para>Takes a boolean argument, defaults to on. Controls whether to run a file system check
++        immediately before the mount operation. In the automount case (see <option>--automount=</option> below) the
++        check will be run the moment the first access to the device is made, which might slightly delay the
++        access.</para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><option>--description=</option></term>
++
++        <listitem><para>Provide a description for the mount or automount unit. See <varname>Description=</varname> in
++        <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
++        </para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><option>--property=</option></term>
++        <term><option>-p</option></term>
++
++        <listitem><para>Sets a unit property for the mount unit that is created. This takes an assignment in the same
++        format as <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
++        <command>set-property</command> command.</para>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><option>--automount=</option></term>
++
++        <listitem><para>Takes a boolean argument. Controls whether to create an automount point or a regular mount
++        point. If true an automount point is created that is backed by the actual file system at the time of first
++        access. If false a plain mount point is created that is backed by the actual file system immediately. Automount
++        points have the benefit that the file system stays unmounted and hence in clean state until it is first
++        accessed. In automount mode the <option>--timeout-idle-sec=</option> switch (see below) may be used to ensure
++        the mount point is unmounted automatically after the last access and an idle period passed.</para>
++
++        <para>If this switch is not specified it defaults to false. If not specified and <option>--discover</option> is
++        used (or only a single argument passed, which implies <option>--discover</option>, see above), and the file
++        system block device is detected to be removable, it is set to true, in order to increase the chance that the
++        file system is in a fully clean state if the device is unplugged abruptly.</para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><option>-A</option></term>
++
++        <listitem><para>Equivalent to <option>--automount=yes</option>.</para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><option>--timeout-idle-sec=</option></term>
++
++        <listitem><para>Takes a time value that controls the idle timeout in automount mode. If set to
++        <literal>infinity</literal> (the default) no automatic unmounts are done. Otherwise the file system backing the
++        automount point is detached after the last access and the idle timeout passed. See
++        <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry> for details on
++        the time syntax supported. This option has no effect if only a regular mount is established, and automounting
++        is not used.</para>
++
++        <para>Note that if <option>--discover</option> is used (or only a single argument passed, which implies
++        <option>--discover</option>, see above), and the file system block device is detected to be removable,
++        <option>--timeout-idle-sec=1s</option> is implied.</para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><option>--automount-property=</option></term>
++
++        <listitem><para>Similar to <option>--property=</option>, but applies additional properties to the automount
++        unit created, instead of the mount unit.</para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><option>--bind-device=</option></term>
++
++        <listitem><para>Takes a boolean argument, defaults to off. This option only has an effect in automount mode,
++        and controls whether the automount unit shall be bound to the backing device's lifetime. If enabled, the
++        automount point will be removed automatically when the backing device vanishes. If disabled the automount point
++        stays around, and subsequent accesses will block until backing device is replugged. This option has no effect
++        in case of non-device mounts, such as network or virtual file system mounts.</para>
++
++        <para>Note that if <option>--discover</option> is used (or only a single argument passed, which implies
++        <option>--discover</option>, see above), and the file system block device is detected to be removable, this
++        option is implied.</para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><option>--list</option></term>
++
++        <listitem><para>Instead of establishing a mount or automount point, print a terse list of block devices
++        containing file systems that may be mounted with <literal>systemd-mount</literal>, along with useful metadata
++        such as labels, etc.</para></listitem>
++      </varlistentry>
++
++      <xi:include href="user-system-options.xml" xpointer="user" />
++      <xi:include href="user-system-options.xml" xpointer="system" />
++      <xi:include href="user-system-options.xml" xpointer="host" />
++      <xi:include href="user-system-options.xml" xpointer="machine" />
++
++      <xi:include href="standard-options.xml" xpointer="help" />
++      <xi:include href="standard-options.xml" xpointer="version" />
++    </variablelist>
++
++  </refsect1>
++
++  <refsect1>
++    <title>Exit status</title>
++
++    <para>On success, 0 is returned, a non-zero failure
++    code otherwise.</para>
++  </refsect1>
++
++  <refsect1>
++    <title>The udev Database</title>
++
++    <para>If <option>--discover</option> is used, <command>systemd-mount</command> honours a couple of additional udev
++    properties of block devices:</para>
++
++    <variablelist class='udev-directives'>
++      <varlistentry>
++        <term><varname>SYSTEMD_MOUNT_OPTIONS=</varname></term>
++
++        <listitem><para>The mount options to use, if <option>--options=</option> is not used.</para></listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><varname>SYSTEMD_MOUNT_WHERE=</varname></term>
++
++        <listitem><para>The file system path to place the mount point at, instead of the automatically generated
++        one.</para></listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++
++  <refsect1>
++    <title>See Also</title>
++    <para>
++      <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
++      <citerefentry><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
++      <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
++      <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
++      <citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
++      <citerefentry><refentrytitle>systemd.automount</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
++      <citerefentry><refentrytitle>systemd-run</refentrytitle><manvolnum>1</manvolnum></citerefentry>
++    </para>
++  </refsect1>
++
++</refentry>
+diff --git a/man/systemd-run.xml b/man/systemd-run.xml
+index 1a30c07..56d585c 100644
+--- a/man/systemd-run.xml
++++ b/man/systemd-run.xml
+@@ -452,6 +452,7 @@ There is a screen on:
+       <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+       <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+       <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
++      <citerefentry><refentrytitle>systemd-mount</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+       <citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+     </para>
+   </refsect1>
+diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c
+index ba69895..6192743 100644
+--- a/src/basic/mount-util.c
++++ b/src/basic/mount-util.c
+@@ -75,7 +75,6 @@ static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id
+         return safe_atoi(p, mnt_id);
+ }
+-
+ int fd_is_mount_point(int fd, const char *filename, int flags) {
+         union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT;
+         int mount_id = -1, mount_id_parent = -1;
+diff --git a/src/mount/Makefile b/src/mount/Makefile
+new file mode 120000
+index 0000000..d0b0e8e
+--- /dev/null
++++ b/src/mount/Makefile
+@@ -0,0 +1 @@
++../Makefile
+\ No newline at end of file
+diff --git a/src/mount/mount-tool.c b/src/mount/mount-tool.c
+new file mode 100644
+index 0000000..9076ba3
+--- /dev/null
++++ b/src/mount/mount-tool.c
+@@ -0,0 +1,1112 @@
++/***
++  This file is part of systemd.
++
++  Copyright 2016 Lennart Poettering
++
++  systemd is free software; you can redistribute it and/or modify it
++  under the terms of the GNU Lesser General Public License as published by
++  the Free Software Foundation; either version 2.1 of the License, or
++  (at your option) any later version.
++
++  systemd is distributed in the hope that it will be useful, but
++  WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++  Lesser General Public License for more details.
++
++  You should have received a copy of the GNU Lesser General Public License
++  along with systemd; If not, see <http://www.gnu.org/licenses/>.
++***/
++
++#include <getopt.h>
++
++#include "libudev.h"
++#include "sd-bus.h"
++
++#include "bus-error.h"
++#include "bus-unit-util.h"
++#include "bus-util.h"
++#include "escape.h"
++#include "fstab-util.h"
++#include "pager.h"
++#include "parse-util.h"
++#include "path-util.h"
++#include "spawn-polkit-agent.h"
++#include "strv.h"
++#include "udev-util.h"
++#include "unit-name.h"
++#include "terminal-util.h"
++
++enum {
++        ACTION_DEFAULT,
++        ACTION_MOUNT,
++        ACTION_AUTOMOUNT,
++        ACTION_LIST,
++} arg_action = ACTION_DEFAULT;
++
++static bool arg_no_block = false;
++static bool arg_no_pager = false;
++static bool arg_ask_password = true;
++static bool arg_quiet = false;
++static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
++static bool arg_user = false;
++static const char *arg_host = NULL;
++static bool arg_discover = false;
++static char *arg_mount_what = NULL;
++static char *arg_mount_where = NULL;
++static char *arg_mount_type = NULL;
++static char *arg_mount_options = NULL;
++static char *arg_description = NULL;
++static char **arg_property = NULL;
++static usec_t arg_timeout_idle = USEC_INFINITY;
++static bool arg_timeout_idle_set = false;
++static char **arg_automount_property = NULL;
++static int arg_bind_device = -1;
++static bool arg_fsck = true;
++
++static void polkit_agent_open_if_enabled(void) {
++
++        /* Open the polkit agent as a child process if necessary */
++        if (!arg_ask_password)
++                return;
++
++        if (arg_transport != BUS_TRANSPORT_LOCAL)
++                return;
++
++        polkit_agent_open();
++}
++
++static void help(void) {
++        printf("%s [OPTIONS...] WHAT [WHERE]\n\n"
++               "Establish a mount or auto-mount point transiently.\n\n"
++               "  -h --help                       Show this help\n"
++               "     --version                    Show package version\n"
++               "     --no-block                   Do not wait until operation finished\n"
++               "     --no-pager                   Do not pipe output into a pager\n"
++               "     --no-ask-password            Do not prompt for password\n"
++               "  -q --quiet                      Suppress information messages during runtime\n"
++               "     --user                       Run as user unit\n"
++               "  -H --host=[USER@]HOST           Operate on remote host\n"
++               "  -M --machine=CONTAINER          Operate on local container\n"
++               "     --discover                   Discover mount device metadata\n"
++               "  -t --type=TYPE                  File system type\n"
++               "  -o --options=OPTIONS            Mount options\n"
++               "     --fsck=no                    Don't run file system check before mount\n"
++               "     --description=TEXT           Description for unit\n"
++               "  -p --property=NAME=VALUE        Set mount unit property\n"
++               "  -A --automount=BOOL             Create an auto-mount point\n"
++               "     --timeout-idle-sec=SEC       Specify automount idle timeout\n"
++               "     --automount-property=NAME=VALUE\n"
++               "                                  Set automount unit property\n"
++               "     --bind-device                Bind automount unit to device\n"
++               "     --list                       List mountable block devices\n"
++               , program_invocation_short_name);
++}
++
++static int parse_argv(int argc, char *argv[]) {
++
++        enum {
++                ARG_VERSION = 0x100,
++                ARG_NO_BLOCK,
++                ARG_NO_PAGER,
++                ARG_NO_ASK_PASSWORD,
++                ARG_USER,
++                ARG_SYSTEM,
++                ARG_DISCOVER,
++                ARG_MOUNT_TYPE,
++                ARG_MOUNT_OPTIONS,
++                ARG_FSCK,
++                ARG_DESCRIPTION,
++                ARG_TIMEOUT_IDLE,
++                ARG_AUTOMOUNT,
++                ARG_AUTOMOUNT_PROPERTY,
++                ARG_BIND_DEVICE,
++                ARG_LIST,
++        };
++
++        static const struct option options[] = {
++                { "help",               no_argument,       NULL, 'h'                    },
++                { "version",            no_argument,       NULL, ARG_VERSION            },
++                { "no-block",           no_argument,       NULL, ARG_NO_BLOCK           },
++                { "no-pager",           no_argument,       NULL, ARG_NO_PAGER           },
++                { "no-ask-password",    no_argument,       NULL, ARG_NO_ASK_PASSWORD    },
++                { "quiet",              no_argument,       NULL, 'q'                    },
++                { "user",               no_argument,       NULL, ARG_USER               },
++                { "system",             no_argument,       NULL, ARG_SYSTEM             },
++                { "host",               required_argument, NULL, 'H'                    },
++                { "machine",            required_argument, NULL, 'M'                    },
++                { "discover",           no_argument,       NULL, ARG_DISCOVER           },
++                { "type",               required_argument, NULL, 't'                    },
++                { "options",            required_argument, NULL, 'o'                    },
++                { "description",        required_argument, NULL, ARG_DESCRIPTION        },
++                { "property",           required_argument, NULL, 'p'                    },
++                { "automount",          required_argument, NULL, ARG_AUTOMOUNT          },
++                { "timeout-idle-sec",   required_argument, NULL, ARG_TIMEOUT_IDLE       },
++                { "automount-property", required_argument, NULL, ARG_AUTOMOUNT_PROPERTY },
++                { "bind-device",        no_argument,       NULL, ARG_BIND_DEVICE        },
++                { "list",               no_argument,       NULL, ARG_LIST               },
++                {},
++        };
++
++        int r, c;
++
++        assert(argc >= 0);
++        assert(argv);
++
++        while ((c = getopt_long(argc, argv, "hqH:M:t:o:p:A", options, NULL)) >= 0)
++
++                switch (c) {
++
++                case 'h':
++                        help();
++                        return 0;
++
++                case ARG_VERSION:
++                        return version();
++
++                case ARG_NO_BLOCK:
++                        arg_no_block = true;
++                        break;
++
++                case ARG_NO_PAGER:
++                        arg_no_pager = true;
++                        break;
++
++                case ARG_NO_ASK_PASSWORD:
++                        arg_ask_password = false;
++                        break;
++
++                case 'q':
++                        arg_quiet = true;
++                        break;
++
++                case ARG_USER:
++                        arg_user = true;
++                        break;
++
++                case ARG_SYSTEM:
++                        arg_user = false;
++                        break;
++
++                case 'H':
++                        arg_transport = BUS_TRANSPORT_REMOTE;
++                        arg_host = optarg;
++                        break;
++
++                case 'M':
++                        arg_transport = BUS_TRANSPORT_MACHINE;
++                        arg_host = optarg;
++                        break;
++
++                case ARG_DISCOVER:
++                        arg_discover = true;
++                        break;
++
++                case 't':
++                        if (free_and_strdup(&arg_mount_type, optarg) < 0)
++                                return log_oom();
++                        break;
++
++                case 'o':
++                        if (free_and_strdup(&arg_mount_options, optarg) < 0)
++                                return log_oom();
++                        break;
++
++                case ARG_FSCK:
++                        r = parse_boolean(optarg);
++                        if (r < 0)
++                                return log_error_errno(r, "Failed to parse --fsck= argument: %s", optarg);
++
++                        arg_fsck = r;
++                        break;
++
++                case ARG_DESCRIPTION:
++                        if (free_and_strdup(&arg_description, optarg) < 0)
++                                return log_oom();
++                        break;
++
++                case 'p':
++                        if (strv_extend(&arg_property, optarg) < 0)
++                                return log_oom();
++
++                        break;
++
++                case 'A':
++                        arg_action = ACTION_AUTOMOUNT;
++                        break;
++
++                case ARG_AUTOMOUNT:
++                        r = parse_boolean(optarg);
++                        if (r < 0)
++                                return log_error_errno(r, "--automount= expects a valid boolean parameter: %s", optarg);
++
++                        arg_action = r ? ACTION_AUTOMOUNT : ACTION_MOUNT;
++                        break;
++
++                case ARG_TIMEOUT_IDLE:
++                        r = parse_sec(optarg, &arg_timeout_idle);
++                        if (r < 0)
++                                return log_error_errno(r, "Failed to parse timeout: %s", optarg);
++
++                        break;
++
++                case ARG_AUTOMOUNT_PROPERTY:
++                        if (strv_extend(&arg_automount_property, optarg) < 0)
++                                return log_oom();
++
++                        break;
++
++                case ARG_BIND_DEVICE:
++                        arg_bind_device = true;
++                        break;
++
++                case ARG_LIST:
++                        arg_action = ACTION_LIST;
++                        break;
++
++                case '?':
++                        return -EINVAL;
++
++                default:
++                        assert_not_reached("Unhandled option");
++                }
++
++        if (arg_user && arg_transport != BUS_TRANSPORT_LOCAL) {
++                log_error("Execution in user context is not supported on non-local systems.");
++                return -EINVAL;
++        }
++
++        if (arg_action == ACTION_LIST) {
++                if (optind < argc) {
++                        log_error("Too many arguments.");
++                        return -EINVAL;
++                }
++
++                if (arg_transport != BUS_TRANSPORT_LOCAL) {
++                        log_error("Listing devices only supported locally.");
++                        return -EOPNOTSUPP;
++                }
++        } else {
++                if (optind >= argc) {
++                        log_error("At least one argument required.");
++                        return -EINVAL;
++                }
++
++                if (argc > optind+2) {
++                        log_error("At most two arguments required.");
++                        return -EINVAL;
++                }
++
++                arg_mount_what = fstab_node_to_udev_node(argv[optind]);
++                if (!arg_mount_what)
++                        return log_oom();
++
++                if (argc > optind+1) {
++                        r = path_make_absolute_cwd(argv[optind+1], &arg_mount_where);
++                        if (r < 0)
++                                return log_error_errno(r, "Failed to make path absolute: %m");
++                } else
++                        arg_discover = true;
++
++                if (arg_discover && arg_transport != BUS_TRANSPORT_LOCAL) {
++                        log_error("Automatic mount location discovery is only supported locally.");
++                        return -EOPNOTSUPP;
++                }
++        }
++
++        return 1;
++}
++
++static int transient_unit_set_properties(sd_bus_message *m, char **properties) {
++        int r;
++
++        r = sd_bus_message_append(m, "(sv)", "Description", "s", arg_description);
++        if (r < 0)
++                return r;
++
++        if (arg_bind_device && is_device_path(arg_mount_what)) {
++                _cleanup_free_ char *device_unit = NULL;
++
++                r = unit_name_from_path(arg_mount_what, ".device", &device_unit);
++                if (r < 0)
++                        return r;
++
++                r = sd_bus_message_append(m, "(sv)(sv)",
++                                          "After", "as", 1, device_unit,
++                                          "BindsTo", "as", 1, device_unit);
++                if (r < 0)
++                        return r;
++        }
++
++        r = bus_append_unit_property_assignment_many(m, properties);
++        if (r < 0)
++                return r;
++
++        return 0;
++}
++
++static int transient_mount_set_properties(sd_bus_message *m) {
++        int r;
++
++        assert(m);
++
++        r = transient_unit_set_properties(m, arg_property);
++        if (r < 0)
++                return r;
++
++        if (arg_mount_what) {
++                r = sd_bus_message_append(m, "(sv)", "What", "s", arg_mount_what);
++                if (r < 0)
++                        return r;
++        }
++
++        if (arg_mount_type) {
++                r = sd_bus_message_append(m, "(sv)", "Type", "s", arg_mount_type);
++                if (r < 0)
++                        return r;
++        }
++
++        if (arg_mount_options) {
++                r = sd_bus_message_append(m, "(sv)", "Options", "s", arg_mount_options);
++                if (r < 0)
++                        return r;
++        }
++
++        if (arg_fsck) {
++                _cleanup_free_ char *fsck = NULL;
++
++                r = unit_name_from_path_instance("systemd-fsck", arg_mount_what, ".service", &fsck);
++                if (r < 0)
++                        return r;
++
++                r = sd_bus_message_append(m,
++                                          "(sv)(sv)",
++                                          "Requires", "as", 1, fsck,
++                                          "After", "as", 1, fsck);
++                if (r < 0)
++                        return r;
++        }
++
++        return 0;
++}
++
++static int transient_automount_set_properties(sd_bus_message *m) {
++        int r;
++
++        assert(m);
++
++        r = transient_unit_set_properties(m, arg_automount_property);
++        if (r < 0)
++                return r;
++
++        if (arg_timeout_idle != USEC_INFINITY) {
++                r = sd_bus_message_append(m, "(sv)", "TimeoutIdleUSec", "t", arg_timeout_idle);
++                if (r < 0)
++                        return r;
++        }
++
++        return 0;
++}
++
++static int start_transient_mount(
++                sd_bus *bus,
++                char **argv) {
++
++        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
++        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
++        _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
++        _cleanup_free_ char *mount_unit = NULL;
++        int r;
++
++        if (!arg_no_block) {
++                r = bus_wait_for_jobs_new(bus, &w);
++                if (r < 0)
++                        return log_error_errno(r, "Could not watch jobs: %m");
++        }
++
++        r = unit_name_from_path(arg_mount_where, ".mount", &mount_unit);
++        if (r < 0)
++                return log_error_errno(r, "Failed to make mount unit name: %m");
++
++        r = sd_bus_message_new_method_call(
++                        bus,
++                        &m,
++                        "org.freedesktop.systemd1",
++                        "/org/freedesktop/systemd1",
++                        "org.freedesktop.systemd1.Manager",
++                        "StartTransientUnit");
++        if (r < 0)
++                return bus_log_create_error(r);
++
++        r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
++        if (r < 0)
++                return bus_log_create_error(r);
++
++        /* Name and mode */
++        r = sd_bus_message_append(m, "ss", mount_unit, "fail");
++        if (r < 0)
++                return bus_log_create_error(r);
++
++        /* Properties */
++        r = sd_bus_message_open_container(m, 'a', "(sv)");
++        if (r < 0)
++                return bus_log_create_error(r);
++
++        r = transient_mount_set_properties(m);
++        if (r < 0)
++                return bus_log_create_error(r);
++
++        r = sd_bus_message_close_container(m);
++        if (r < 0)
++                return bus_log_create_error(r);
++
++        /* Auxiliary units */
++        r = sd_bus_message_append(m, "a(sa(sv))", 0);
++        if (r < 0)
++                return bus_log_create_error(r);
++
++        polkit_agent_open_if_enabled();
++
++        r = sd_bus_call(bus, m, 0, &error, &reply);
++        if (r < 0)
++                return log_error_errno(r, "Failed to start transient mount unit: %s", bus_error_message(&error, r));
++
++        if (w) {
++                const char *object;
++
++                r = sd_bus_message_read(reply, "o", &object);
++                if (r < 0)
++                        return bus_log_parse_error(r);
++
++                r = bus_wait_for_jobs_one(w, object, arg_quiet);
++                if (r < 0)
++                        return r;
++        }
++
++        if (!arg_quiet)
++                log_info("Started unit %s%s%s for mount point: %s%s%s",
++                         ansi_highlight(), mount_unit, ansi_normal(),
++                         ansi_highlight(), arg_mount_where, ansi_normal());
++
++        return 0;
++}
++
++static int start_transient_automount(
++                sd_bus *bus,
++                char **argv) {
++
++        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
++        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
++        _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
++        _cleanup_free_ char *automount_unit = NULL, *mount_unit = NULL;
++        int r;
++
++        if (!arg_no_block) {
++                r = bus_wait_for_jobs_new(bus, &w);
++                if (r < 0)
++                        return log_error_errno(r, "Could not watch jobs: %m");
++        }
++
++        r = unit_name_from_path(arg_mount_where, ".automount", &automount_unit);
++        if (r < 0)
++                return log_error_errno(r, "Failed to make automount unit name: %m");
++
++        r = unit_name_from_path(arg_mount_where, ".mount", &mount_unit);
++        if (r < 0)
++                return log_error_errno(r, "Failed to make mount unit name: %m");
++
++        r = sd_bus_message_new_method_call(
++                        bus,
++                        &m,
++                        "org.freedesktop.systemd1",
++                        "/org/freedesktop/systemd1",
++                        "org.freedesktop.systemd1.Manager",
++                        "StartTransientUnit");
++        if (r < 0)
++                return bus_log_create_error(r);
++
++        r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
++        if (r < 0)
++                return bus_log_create_error(r);
++
++        /* Name and mode */
++        r = sd_bus_message_append(m, "ss", automount_unit, "fail");
++        if (r < 0)
++                return bus_log_create_error(r);
++
++        /* Properties */
++        r = sd_bus_message_open_container(m, 'a', "(sv)");
++        if (r < 0)
++                return bus_log_create_error(r);
++
++        r = transient_automount_set_properties(m);
++        if (r < 0)
++                return bus_log_create_error(r);
++
++        r = sd_bus_message_close_container(m);
++        if (r < 0)
++                return bus_log_create_error(r);
++
++        /* Auxiliary units */
++        r = sd_bus_message_open_container(m, 'a', "(sa(sv))");
++        if (r < 0)
++                return bus_log_create_error(r);
++
++        r = sd_bus_message_open_container(m, 'r', "sa(sv)");
++        if (r < 0)
++                return bus_log_create_error(r);
++
++        r = sd_bus_message_append(m, "s", mount_unit);
++        if (r < 0)
++                return bus_log_create_error(r);
++
++        r = sd_bus_message_open_container(m, 'a', "(sv)");
++        if (r < 0)
++                return bus_log_create_error(r);
++
++        r = transient_mount_set_properties(m);
++        if (r < 0)
++                return bus_log_create_error(r);
++
++        r = sd_bus_message_close_container(m);
++        if (r < 0)
++                return bus_log_create_error(r);
++
++        r = sd_bus_message_close_container(m);
++        if (r < 0)
++                return bus_log_create_error(r);
++
++        r = sd_bus_message_close_container(m);
++        if (r < 0)
++                return bus_log_create_error(r);
++
++        polkit_agent_open_if_enabled();
++
++        r = sd_bus_call(bus, m, 0, &error, &reply);
++        if (r < 0)
++                return log_error_errno(r, "Failed to start transient automount unit: %s", bus_error_message(&error, r));
++
++        if (w) {
++                const char *object;
++
++                r = sd_bus_message_read(reply, "o", &object);
++                if (r < 0)
++                        return bus_log_parse_error(r);
++
++                r = bus_wait_for_jobs_one(w, object, arg_quiet);
++                if (r < 0)
++                        return r;
++        }
++
++        if (!arg_quiet)
++                log_info("Started unit %s%s%s for mount point: %s%s%s",
++                         ansi_highlight(), automount_unit, ansi_normal(),
++                         ansi_highlight(), arg_mount_where, ansi_normal());
++
++        return 0;
++}
++
++static int acquire_mount_type(struct udev_device *d) {
++        const char *v;
++
++        assert(d);
++
++        if (arg_mount_type)
++                return 0;
++
++        v = udev_device_get_property_value(d, "ID_FS_TYPE");
++        if (isempty(v))
++                return 0;
++
++        arg_mount_type = strdup(v);
++        if (!arg_mount_type)
++                return log_oom();
++
++        log_debug("Discovered type=%s", arg_mount_type);
++        return 1;
++}
++
++static int acquire_mount_options(struct udev_device *d) {
++        const char *v;
++
++        if (arg_mount_options)
++                return 0;
++
++        v = udev_device_get_property_value(d, "SYSTEMD_MOUNT_OPTIONS");
++        if (isempty(v))
++                return 0;
++
++        arg_mount_options = strdup(v);
++        if (!arg_mount_options)
++                return log_oom();
++
++        log_debug("Discovered options=%s", arg_mount_options);
++        return 1;
++}
++
++static const char *get_model(struct udev_device *d) {
++        const char *model;
++
++        assert(d);
++
++        model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
++        if (model)
++                return model;
++
++        return udev_device_get_property_value(d, "ID_MODEL");
++}
++
++static const char* get_label(struct udev_device *d) {
++        const char *label;
++
++        assert(d);
++
++        label = udev_device_get_property_value(d, "ID_FS_LABEL");
++        if (label)
++                return label;
++
++        return udev_device_get_property_value(d, "ID_PART_ENTRY_NAME");
++}
++
++static int acquire_mount_where(struct udev_device *d) {
++        const char *v;
++
++        if (arg_mount_where)
++                return 0;
++
++        v = udev_device_get_property_value(d, "SYSTEMD_MOUNT_WHERE");
++        if (isempty(v)) {
++                _cleanup_free_ char *escaped = NULL;
++                const char *name;
++
++                name = get_label(d);
++                if (!name)
++                        name = get_model(d);
++                if (!name) {
++                        const char *dn;
++
++                        dn = udev_device_get_devnode(d);
++                        if (!dn)
++                                return 0;
++
++                        name = basename(dn);
++                }
++
++                escaped = xescape(name, "\\");
++                if (!filename_is_valid(escaped))
++                        return 0;
++
++                arg_mount_where = strjoin("/run/media/system/", escaped, NULL);
++        } else
++                arg_mount_where = strdup(v);
++
++        if (!arg_mount_where)
++                return log_oom();
++
++        log_debug("Discovered where=%s", arg_mount_where);
++        return 1;
++}
++
++static int acquire_description(struct udev_device *d) {
++        const char *model, *label;
++
++        if (arg_description)
++                return 0;
++
++        model = get_model(d);
++
++        label = get_label(d);
++        if (!label)
++                label = udev_device_get_property_value(d, "ID_PART_ENTRY_NUMBER");
++
++        if (model && label)
++                arg_description = strjoin(model, " ", label, NULL);
++        else if (label)
++                arg_description = strdup(label);
++        else if (model)
++                arg_description = strdup(model);
++        else
++                return NULL;
++
++        if (!arg_description)
++                return log_oom();
++
++        log_debug("Discovered description=%s", arg_description);
++        return 1;
++}
++
++static int acquire_removable(struct udev_device *d) {
++        const char *v;
++
++        /* Shortcut this if there's no reason to check it */
++        if (arg_action != ACTION_DEFAULT && arg_timeout_idle_set && arg_bind_device >= 0)
++                return 0;
++
++        for (;;) {
++                v = udev_device_get_sysattr_value(d, "removable");
++                if (v)
++                        break;
++
++                d = udev_device_get_parent(d);
++                if (!d)
++                        return 0;
++
++                if (!streq_ptr(udev_device_get_subsystem(d), "block"))
++                        return 0;
++        }
++
++        if (parse_boolean(v) <= 0)
++                return 0;
++
++        log_debug("Discovered removable device.");
++
++        if (arg_action == ACTION_DEFAULT) {
++                log_debug("Automatically turning on automount.");
++                arg_action = ACTION_AUTOMOUNT;
++        }
++
++        if (!arg_timeout_idle_set) {
++                log_debug("Setting idle timeout to 1s.");
++                arg_timeout_idle = USEC_PER_SEC;
++        }
++
++        if (arg_bind_device < 0) {
++                log_debug("Binding automount unit to device.");
++                arg_bind_device = true;
++        }
++
++        return 1;
++}
++
++static int discover_device(void) {
++        _cleanup_udev_device_unref_ struct udev_device *d = NULL;
++        _cleanup_udev_unref_ struct udev *udev = NULL;
++        struct stat st;
++        const char *v;
++        int r;
++
++        if (!arg_discover)
++                return 0;
++
++        if (!is_device_path(arg_mount_what)) {
++                log_error("Discovery only supported for block devices, don't know what to do.");
++                return -EINVAL;
++        }
++
++        if (stat(arg_mount_what, &st) < 0)
++                return log_error_errno(errno, "Can't stat %s: %m", arg_mount_what);
++
++        if (!S_ISBLK(st.st_mode)) {
++                log_error("Path %s is not a block device, don't know what to do.", arg_mount_what);
++                return -ENOTBLK;
++        }
++
++        udev = udev_new();
++        if (!udev)
++                return log_oom();
++
++        d = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
++        if (!d)
++                return log_oom();
++
++        v = udev_device_get_property_value(d, "ID_FS_USAGE");
++        if (!streq_ptr(v, "filesystem")) {
++                log_error("%s does not contain a file system.", arg_mount_what);
++                return -EINVAL;
++        }
++
++        r = acquire_mount_type(d);
++        if (r < 0)
++                return r;
++
++        r = acquire_mount_options(d);
++        if (r < 0)
++                return r;
++
++        r = acquire_mount_where(d);
++        if (r < 0)
++                return r;
++
++        r = acquire_description(d);
++        if (r < 0)
++                return r;
++
++        r = acquire_removable(d);
++        if (r < 0)
++                return r;
++
++        return 0;
++}
++
++enum {
++        COLUMN_NODE,
++        COLUMN_PATH,
++        COLUMN_MODEL,
++        COLUMN_WWN,
++        COLUMN_FSTYPE,
++        COLUMN_LABEL,
++        COLUMN_UUID,
++        _COLUMN_MAX,
++};
++
++struct item {
++        char* columns[_COLUMN_MAX];
++};
++
++static int compare_item(const void *a, const void *b) {
++        const struct item *x = a, *y = b;
++
++        if (x->columns[COLUMN_NODE] == y->columns[COLUMN_NODE])
++                return 0;
++        if (!x->columns[COLUMN_NODE])
++                return 1;
++        if (!y->columns[COLUMN_NODE])
++                return -1;
++
++        return path_compare(x->columns[COLUMN_NODE], y->columns[COLUMN_NODE]);
++}
++
++static int list_devices(void) {
++
++        static const char * const titles[_COLUMN_MAX] = {
++                [COLUMN_NODE] = "NODE",
++                [COLUMN_PATH] = "PATH",
++                [COLUMN_MODEL] = "MODEL",
++                [COLUMN_WWN] = "WWN",
++                [COLUMN_FSTYPE] = "TYPE",
++                [COLUMN_LABEL] = "LABEL",
++                [COLUMN_UUID] = "UUID"
++        };
++
++        _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
++        _cleanup_udev_unref_ struct udev *udev = NULL;
++        struct udev_list_entry *item = NULL, *first = NULL;
++        size_t n_allocated = 0, n = 0, i;
++        size_t column_width[_COLUMN_MAX];
++        struct item *items = NULL;
++        unsigned c;
++        int r;
++
++        for (c = 0; c < _COLUMN_MAX; c++)
++                column_width[c] = strlen(titles[c]);
++
++        udev = udev_new();
++        if (!udev)
++                return log_oom();
++
++        e = udev_enumerate_new(udev);
++        if (!e)
++                return log_oom();
++
++        r = udev_enumerate_add_match_subsystem(e, "block");
++        if (r < 0)
++                return log_error_errno(r, "Failed to add block match: %m");
++
++        r = udev_enumerate_add_match_property(e, "ID_FS_USAGE", "filesystem");
++        if (r < 0)
++                return log_error_errno(r, "Failed to add property match: %m");
++
++        r = udev_enumerate_scan_devices(e);
++        if (r < 0)
++                return log_error_errno(r, "Failed to scan devices: %m");
++
++        first = udev_enumerate_get_list_entry(e);
++        udev_list_entry_foreach(item, first) {
++                _cleanup_udev_device_unref_ struct udev_device *d;
++                struct item *j;
++
++                d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
++                if (!d) {
++                        r = log_oom();
++                        goto finish;
++                }
++
++                if (!GREEDY_REALLOC0(items, n_allocated, n+1)) {
++                        r = log_oom();
++                        goto finish;
++                }
++
++                j = items + n++;
++
++                for (c = 0; c < _COLUMN_MAX; c++) {
++                        const char *x;
++                        size_t k;
++
++                        switch (c) {
++
++                        case COLUMN_NODE:
++                                x = udev_device_get_devnode(d);
++                                break;
++
++                        case COLUMN_PATH:
++                                x = udev_device_get_property_value(d, "ID_PATH");
++                                break;
++
++                        case COLUMN_MODEL:
++                                x = get_model(d);
++                                break;
++
++                        case COLUMN_WWN:
++                                x = udev_device_get_property_value(d, "ID_WWN");
++                                break;
++
++                        case COLUMN_FSTYPE:
++                                x = udev_device_get_property_value(d, "ID_FS_TYPE");
++                                break;
++
++                        case COLUMN_LABEL:
++                                x = get_label(d);
++                                break;
++
++                        case COLUMN_UUID:
++                                x = udev_device_get_property_value(d, "ID_FS_UUID");
++                                break;
++                        }
++
++                        if (isempty(x))
++                                continue;
++
++                        j->columns[c] = strdup(x);
++                        if (!j->columns[c]) {
++                                r = log_oom();
++                                goto finish;
++                        }
++
++                        k = strlen(x);
++                        if (k > column_width[c])
++                                column_width[c] = k;
++                }
++        }
++
++        if (n == 0) {
++                log_info("No devices found.");
++                goto finish;
++        }
++
++        qsort_safe(items, n, sizeof(struct item), compare_item);
++
++        pager_open(arg_no_pager, false);
++
++        fputs(ansi_underline(), stdout);
++        for (c = 0; c < _COLUMN_MAX; c++) {
++                if (c > 0)
++                        fputc(' ', stdout);
++
++                printf("%-*s", (int) column_width[c], titles[c]);
++        }
++        fputs(ansi_normal(), stdout);
++        fputc('\n', stdout);
++
++        for (i = 0; i < n; i++) {
++                for (c = 0; c < _COLUMN_MAX; c++) {
++                        if (c > 0)
++                                fputc(' ', stdout);
++
++                        printf("%-*s", (int) column_width[c], strna(items[i].columns[c]));
++                }
++                fputc('\n', stdout);
++        }
++
++        r = 0;
++
++finish:
++        for (i = 0; i < n; i++)
++                for (c = 0; c < _COLUMN_MAX; c++)
++                        free(items[i].columns[c]);
++
++        free(items);
++        return r;
++}
++
++int main(int argc, char* argv[]) {
++        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
++        int r;
++
++        log_parse_environment();
++        log_open();
++
++        r = parse_argv(argc, argv);
++        if (r <= 0)
++                goto finish;
++
++        if (arg_action == ACTION_LIST) {
++                r = list_devices();
++                goto finish;
++        }
++
++        r = discover_device();
++        if (r < 0)
++                goto finish;
++        if (!arg_mount_where) {
++                log_error("Can't figure out where to mount %s.", arg_mount_what);
++                r = -EINVAL;
++                goto finish;
++        }
++
++        path_kill_slashes(arg_mount_where);
++
++        if (path_equal(arg_mount_where, "/")) {
++                log_error("Refusing to operate on root directory.");
++                r = -EINVAL;
++                goto finish;
++        }
++
++        if (!path_is_safe(arg_mount_where)) {
++                log_error("Path is contains unsafe components.");
++                r = -EINVAL;
++                goto finish;
++        }
++
++        if (streq_ptr(arg_mount_type, "auto"))
++                arg_mount_type = mfree(arg_mount_type);
++        if (streq_ptr(arg_mount_options, "defaults"))
++                arg_mount_options = mfree(arg_mount_options);
++
++        if (!is_device_path(arg_mount_what))
++                arg_fsck = false;
++
++        if (arg_fsck && arg_mount_type && arg_transport == BUS_TRANSPORT_LOCAL) {
++                r = fsck_exists(arg_mount_type);
++                if (r < 0)
++                        log_warning_errno(r, "Couldn't determine whether fsck for %s exists, proceeding anyway.", arg_mount_type);
++                else if (r == 0) {
++                        log_debug("Disabling file system check as fsck for %s doesn't exist.", arg_mount_type);
++                        arg_fsck = false; /* fsck doesn't exist, let's not attempt it */
++                }
++        }
++
++        r = bus_connect_transport_systemd(arg_transport, arg_host, arg_user, &bus);
++        if (r < 0) {
++                log_error_errno(r, "Failed to create bus connection: %m");
++                goto finish;
++        }
++
++        switch (arg_action) {
++
++        case ACTION_MOUNT:
++        case ACTION_DEFAULT:
++                r = start_transient_mount(bus, argv + optind);
++                break;
++
++        case ACTION_AUTOMOUNT:
++                r = start_transient_automount(bus, argv + optind);
++                break;
++
++        default:
++                assert_not_reached("Unexpected action.");
++        }
++
++finish:
++        bus = sd_bus_flush_close_unref(bus);
++
++        pager_close();
++
++        free(arg_mount_what);
++        free(arg_mount_where);
++        free(arg_mount_type);
++        free(arg_mount_options);
++        free(arg_description);
++        strv_free(arg_property);
++        strv_free(arg_automount_property);
++
++        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
++}
index b4140fca1e7653511b0e909694993318c3ced644..7ad59d33df5cdd2085042642a58e27cccc783352 100644 (file)
@@ -38,6 +38,12 @@ SRC_URI += " \
            file://0023-automount-handle-expire_tokens-when-the-mount-unit-c.patch \
            file://0024-automount-don-t-cancel-mount-umount-request-on-reloa.patch \
            file://0025-automount-make-sure-the-expire-event-is-restarted-af.patch \
+           file://0026-automount-implement-transient-automounts.patch \
+           file://0027-mount-use-get_mount_parameters_fragment-consistently.patch \
+           file://0028-mount-write-drop-in-file-when-setting-transient-prop.patch \
+           file://0029-bus-util-unify-loop-around-bus_append_unit_property_.patch \
+           file://0030-run-various-minor-improvements.patch \
+           file://0031-add-a-new-tool-for-creating-transient-mount-and-auto.patch \
            file://udev-re-enable-mount-propagation-for-udevd.patch \
            file://CVE-2016-7795.patch \
 "