[systemd-commits] 6 commits - man/systemd-run.xml src/core src/libsystemd src/run src/shared src/systemctl

Lennart Poettering lennart at kemper.freedesktop.org
Tue Mar 4 19:10:51 PST 2014


 man/systemd-run.xml              |   96 ++++++++++++++++---
 src/core/dbus-execute.c          |   38 +++++++
 src/libsystemd/sd-bus/bus-util.c |  195 +++++++++++++++++++++++++++++++++++++++
 src/libsystemd/sd-bus/bus-util.h |    2 
 src/run/run.c                    |   82 +++++++++++-----
 src/shared/strv.h                |    2 
 src/systemctl/systemctl.c        |  159 -------------------------------
 7 files changed, 379 insertions(+), 195 deletions(-)

New commits:
commit e567439ec6a63f07258d52fe383a538f5dbeb79b
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Mar 5 04:07:37 2014 +0100

    systemd-run: support all currently exported properties with -p

diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c
index d0ae43d..3b07993 100644
--- a/src/libsystemd/sd-bus/bus-util.c
+++ b/src/libsystemd/sd-bus/bus-util.c
@@ -1252,7 +1252,9 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
         if (r < 0)
                 return bus_log_create_error(r);
 
-        if (STR_IN_SET(field, "CPUAccounting", "MemoryAccounting", "BlockIOAccounting")) {
+        if (STR_IN_SET(field,
+                       "CPUAccounting", "MemoryAccounting", "BlockIOAccounting",
+                       "SendSIGHUP", "SendSIGKILL")) {
 
                 r = parse_boolean(eq);
                 if (r < 0) {
@@ -1284,7 +1286,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
 
                 r = sd_bus_message_append(m, "v", "t", u);
 
-        } else if (streq(field, "DevicePolicy"))
+        } else if (STR_IN_SET(field, "User", "Group", "DevicePolicy", "KillMode"))
                 r = sd_bus_message_append(m, "v", "s", eq);
 
         else if (streq(field, "DeviceAllow")) {
@@ -1387,6 +1389,32 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
 
                 r = sd_bus_message_append(m, "v", "t", rl);
 
+        } else if (streq(field, "Nice")) {
+                int32_t i;
+
+                r = safe_atoi32(eq, &i);
+                if (r < 0) {
+                        log_error("Failed to parse %s value %s.", field, eq);
+                        return -EINVAL;
+                }
+
+                r = sd_bus_message_append(m, "v", "i", i);
+
+        } else if (streq(field, "Environment")) {
+
+                r = sd_bus_message_append(m, "v", "as", 1, eq);
+
+        } else if (streq(field, "KillSignal")) {
+                int sig;
+
+                sig = signal_from_string_try_harder(eq);
+                if (sig < 0) {
+                        log_error("Failed to parse %s value %s.", field, eq);
+                        return -EINVAL;
+                }
+
+                r = sd_bus_message_append(m, "v", "i", sig);
+
         } else {
                 log_error("Unknown assignment %s.", assignment);
                 return -EINVAL;

commit d584f638940366c46a48e34a25cf43e2b77475be
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Mar 5 03:49:00 2014 +0100

    core: make the LimitXYZ= properties settable for transient service units

diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 4c3ad65..bf4a682 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -851,6 +851,44 @@ int bus_exec_context_set_transient_property(
                 }
 
                 return 1;
+
+        } else if (rlimit_from_string(name) >= 0) {
+                uint64_t rl;
+                rlim_t x;
+
+                r = sd_bus_message_read(message, "t", &rl);
+                if (r < 0)
+                        return r;
+
+                if (rl == (uint64_t) -1)
+                        x = RLIM_INFINITY;
+                else {
+                        x = (rlim_t) rl;
+
+                        if ((uint64_t) x != rl)
+                                return -ERANGE;
+                }
+
+                if (mode != UNIT_CHECK) {
+                        int z;
+
+                        z = rlimit_from_string(name);
+
+                        if (!c->rlimit[z]) {
+                                c->rlimit[z] = new(struct rlimit, 1);
+                                if (!c->rlimit[z])
+                                        return -ENOMEM;
+                        }
+
+                        c->rlimit[z]->rlim_cur = c->rlimit[z]->rlim_max = x;
+
+                        if (x == RLIM_INFINITY)
+                                unit_write_drop_in_private_format(u, mode, name, "%s=infinity\n", name);
+                        else
+                                unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64 "\n", name, rl);
+                }
+
+                return 1;
         }
 
         return 0;
diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c
index 40aab2a..d0ae43d 100644
--- a/src/libsystemd/sd-bus/bus-util.c
+++ b/src/libsystemd/sd-bus/bus-util.c
@@ -1372,6 +1372,21 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
                         r = sd_bus_message_append(m, "v", "a(st)", path, u);
                 }
 
+        } else if (rlimit_from_string(field) >= 0) {
+                uint64_t rl;
+
+                if (streq(eq, "infinity"))
+                        rl = (uint64_t) -1;
+                else {
+                        r = safe_atou64(eq, &rl);
+                        if (r < 0) {
+                                log_error("Invalid resource limit: %s", eq);
+                                return -EINVAL;
+                        }
+                }
+
+                r = sd_bus_message_append(m, "v", "t", rl);
+
         } else {
                 log_error("Unknown assignment %s.", assignment);
                 return -EINVAL;

commit 1ac67edb7c4d31a287fa98c0b554ae98bd34e71b
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Mar 5 03:38:36 2014 +0100

    systemd-run: add some extra safety checks

diff --git a/src/run/run.c b/src/run/run.c
index 81763c9..e71ca7d 100644
--- a/src/run/run.c
+++ b/src/run/run.c
@@ -37,7 +37,7 @@ static const char *arg_description = NULL;
 static const char *arg_slice = NULL;
 static bool arg_send_sighup = false;
 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
-static char *arg_host = NULL;
+static const char *arg_host = NULL;
 static bool arg_user = false;
 static const char *arg_service_type = NULL;
 static const char *arg_exec_user = NULL;
@@ -186,7 +186,7 @@ static int parse_argv(int argc, char *argv[]) {
 
                 case ARG_NICE:
                         r = safe_atoi(optarg, &arg_nice);
-                        if (r < 0) {
+                        if (r < 0 || arg_nice < PRIO_MIN || arg_nice >= PRIO_MAX) {
                                 log_error("Failed to parse nice value");
                                 return -EINVAL;
                         }

commit 981ee551945f4e00de52fcbb7780fd7476bcd47e
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Mar 5 03:37:48 2014 +0100

    man: document missing options of systemd-run

diff --git a/man/systemd-run.xml b/man/systemd-run.xml
index 95c1cb7..81d41dc 100644
--- a/man/systemd-run.xml
+++ b/man/systemd-run.xml
@@ -121,9 +121,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
       <varlistentry>
         <term><option>--description=</option></term>
 
-        <listitem><para>Provide description for the unit. If not
-        specified, the command itself will be used as a description.
-        See <varname>Description=</varname> in
+        <listitem><para>Provide description for the service or scope
+        unit. If not specified, the command itself will be used as a
+        description.  See <varname>Description=</varname> in
         <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
         </para></listitem>
       </varlistentry>
@@ -140,10 +140,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
       <varlistentry>
         <term><option>--remain-after-exit</option></term>
 
-        <listitem><para>After the service's process has terminated, keep
-        the service around until it is explicitly stopped. This is
-        useful to collect runtime information about the service after
-        it finished running. Also see
+        <listitem><para>After the service or scope process has
+        terminated, keep the service around until it is explicitly
+        stopped. This is useful to collect runtime information about
+        the service after it finished running. Also see
         <varname>RemainAfterExit=</varname> in
         <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
         </para>
@@ -153,15 +153,64 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
       <varlistentry>
         <term><option>--send-sighup</option></term>
 
-        <listitem><para>When terminating the scope unit, send a SIGHUP
-        immediately after SIGTERM. This is useful to indicate to
-        shells and shell-like processes that the connection has been
-        severed. Also see <varname>SendSIGHUP=</varname> in
+        <listitem><para>When terminating the scope or service unit,
+        send a SIGHUP immediately after SIGTERM. This is useful to
+        indicate to shells and shell-like processes that the
+        connection has been severed. Also see
+        <varname>SendSIGHUP=</varname> in
         <citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
         </para>
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--service-type=</option></term>
+
+        <listitem><para>Sets the service type. Also see
+        <varname>Type=</varname> in
+        <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>. This
+        option has no effect in conjunction with
+        <option>--scope</option>. Defaults to
+        <constant>simple</constant>.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--uid=</option></term>
+        <term><option>--gid=</option></term>
+
+        <listitem><para>Runs the service process under the UNIX user
+        and group. Also see <varname>User=</varname> and
+        <varname>Group=</varname> in
+        <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>. This
+        option has no effect in conjunction with
+        <option>--scope</option>.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--nice=</option></term>
+
+        <listitem><para>Runs the service process with the specified
+        nice level. Also see <varname>Nice=</varname> in
+        <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>. This
+        option has no effect in conjunction with
+        <option>--scope</option>.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--setenv=</option></term>
+
+        <listitem><para>Runs the service process with the specified
+        environment variables set. Also see
+        <varname>Environment=</varname> in
+        <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>. This
+        option has no effect in conjunction with
+        <option>--scope</option>.</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" />

commit df31a6c0fe07805cb50045fbe91c2a6e7e430562
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Mar 5 03:36:22 2014 +0100

    systemd-run: add new --property= switch that can set arbitrary properties for the unit that is created
    
    The code for parsing these properties is shared with "systemctl
    set-property", which means all the resource control settings are
    immediately available.

diff --git a/man/systemd-run.xml b/man/systemd-run.xml
index 064195a..95c1cb7 100644
--- a/man/systemd-run.xml
+++ b/man/systemd-run.xml
@@ -107,6 +107,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
       </varlistentry>
 
       <varlistentry>
+        <term><option>--property=</option></term>
+        <term><option>-p</option></term>
+
+        <listitem><para>Sets a unit property for the scope or service
+        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>--description=</option></term>
 
         <listitem><para>Provide description for the unit. If not
@@ -173,7 +185,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
   </refsect1>
 
   <refsect1>
-    <title>Example</title>
+    <title>Examples</title>
 
     <para>The following command will log the environment variables
     provided by systemd to services:</para>
@@ -186,6 +198,15 @@ Sep 08 07:37:21 bupkis systemd[1]: Started /usr/bin/env.
 Sep 08 07:37:21 bupkis env[19948]: PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
 Sep 08 07:37:21 bupkis env[19948]: LANG=en_US.UTF-8
 Sep 08 07:37:21 bupkis env[19948]: BOOT_IMAGE=/vmlinuz-3.11.0-0.rc5.git6.2.fc20.x86_64</programlisting>
+
+    <para>The following command invokes the
+    <citerefentry><refentrytitle>updatedb</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+    tool but lowers the block IO weight for it to 10. See
+    <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+    for more information on the <varname>BlockIOWeight=</varname>
+    property.</para>
+
+    <programlisting># systemd-run -p BlockIOWeight=10 updatedb</programlisting>
   </refsect1>
 
   <refsect1>
@@ -197,6 +218,8 @@ Sep 08 07:37:21 bupkis env[19948]: BOOT_IMAGE=/vmlinuz-3.11.0-0.rc5.git6.2.fc20.
       <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>systemd.scope</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
     </para>
   </refsect1>
diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c
index 2935f69..40aab2a 100644
--- a/src/libsystemd/sd-bus/bus-util.c
+++ b/src/libsystemd/sd-bus/bus-util.c
@@ -26,6 +26,7 @@
 #include "strv.h"
 #include "macro.h"
 #include "def.h"
+#include "path-util.h"
 #include "missing.h"
 
 #include "sd-event.h"
@@ -1230,3 +1231,154 @@ int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) {
 
         return 1;
 }
+
+int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) {
+        const char *eq, *field;
+        int r;
+
+        assert(m);
+        assert(assignment);
+
+        eq = strchr(assignment, '=');
+        if (!eq) {
+                log_error("Not an assignment: %s", assignment);
+                return -EINVAL;
+        }
+
+        field = strndupa(assignment, eq - assignment);
+        eq ++;
+
+        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        if (STR_IN_SET(field, "CPUAccounting", "MemoryAccounting", "BlockIOAccounting")) {
+
+                r = parse_boolean(eq);
+                if (r < 0) {
+                        log_error("Failed to parse boolean assignment %s.", assignment);
+                        return -EINVAL;
+                }
+
+                r = sd_bus_message_append(m, "v", "b", r);
+
+        } else if (streq(field, "MemoryLimit")) {
+                off_t bytes;
+
+                r = parse_size(eq, 1024, &bytes);
+                if (r < 0) {
+                        log_error("Failed to parse bytes specification %s", assignment);
+                        return -EINVAL;
+                }
+
+                r = sd_bus_message_append(m, "v", "t", (uint64_t) bytes);
+
+        } else if (STR_IN_SET(field, "CPUShares", "BlockIOWeight")) {
+                uint64_t u;
+
+                r = safe_atou64(eq, &u);
+                if (r < 0) {
+                        log_error("Failed to parse %s value %s.", field, eq);
+                        return -EINVAL;
+                }
+
+                r = sd_bus_message_append(m, "v", "t", u);
+
+        } else if (streq(field, "DevicePolicy"))
+                r = sd_bus_message_append(m, "v", "s", eq);
+
+        else if (streq(field, "DeviceAllow")) {
+
+                if (isempty(eq))
+                        r = sd_bus_message_append(m, "v", "a(ss)", 0);
+                else {
+                        const char *path, *rwm, *e;
+
+                        e = strchr(eq, ' ');
+                        if (e) {
+                                path = strndupa(eq, e - eq);
+                                rwm = e+1;
+                        } else {
+                                path = eq;
+                                rwm = "";
+                        }
+
+                        if (!path_startswith(path, "/dev")) {
+                                log_error("%s is not a device file in /dev.", path);
+                                return -EINVAL;
+                        }
+
+                        r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
+                }
+
+        } else if (STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
+
+                if (isempty(eq))
+                        r = sd_bus_message_append(m, "v", "a(st)", 0);
+                else {
+                        const char *path, *bandwidth, *e;
+                        off_t bytes;
+
+                        e = strchr(eq, ' ');
+                        if (e) {
+                                path = strndupa(eq, e - eq);
+                                bandwidth = e+1;
+                        } else {
+                                log_error("Failed to parse %s value %s.", field, eq);
+                                return -EINVAL;
+                        }
+
+                        if (!path_startswith(path, "/dev")) {
+                                log_error("%s is not a device file in /dev.", path);
+                                return -EINVAL;
+                        }
+
+                        r = parse_size(bandwidth, 1000, &bytes);
+                        if (r < 0) {
+                                log_error("Failed to parse byte value %s.", bandwidth);
+                                return -EINVAL;
+                        }
+
+                        r = sd_bus_message_append(m, "v", "a(st)", 1, path, (uint64_t) bytes);
+                }
+
+        } else if (streq(field, "BlockIODeviceWeight")) {
+
+                if (isempty(eq))
+                        r = sd_bus_message_append(m, "v", "a(st)", 0);
+                else {
+                        const char *path, *weight, *e;
+                        uint64_t u;
+
+                        e = strchr(eq, ' ');
+                        if (e) {
+                                path = strndupa(eq, e - eq);
+                                weight = e+1;
+                        } else {
+                                log_error("Failed to parse %s value %s.", field, eq);
+                                return -EINVAL;
+                        }
+
+                        if (!path_startswith(path, "/dev")) {
+                                log_error("%s is not a device file in /dev.", path);
+                                return -EINVAL;
+                        }
+
+                        r = safe_atou64(weight, &u);
+                        if (r < 0) {
+                                log_error("Failed to parse %s value %s.", field, weight);
+                                return -EINVAL;
+                        }
+                        r = sd_bus_message_append(m, "v", "a(st)", path, u);
+                }
+
+        } else {
+                log_error("Unknown assignment %s.", assignment);
+                return -EINVAL;
+        }
+
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        return 0;
+}
diff --git a/src/libsystemd/sd-bus/bus-util.h b/src/libsystemd/sd-bus/bus-util.h
index 51e1613..b093620 100644
--- a/src/libsystemd/sd-bus/bus-util.h
+++ b/src/libsystemd/sd-bus/bus-util.h
@@ -178,3 +178,5 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_creds*, sd_bus_creds_unref);
         SD_BUS_PROPERTY(name "Monotonic", "t", bus_property_get_usec, (offset) + offsetof(struct dual_timestamp, monotonic), (flags))
 
 int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error);
+
+int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment);
diff --git a/src/run/run.c b/src/run/run.c
index 885d881..81763c9 100644
--- a/src/run/run.c
+++ b/src/run/run.c
@@ -45,27 +45,29 @@ static const char *arg_exec_group = NULL;
 static int arg_nice = 0;
 static bool arg_nice_set = false;
 static char **arg_environment = NULL;
+static char **arg_property = NULL;
 
 static int help(void) {
 
         printf("%s [OPTIONS...] COMMAND [ARGS...]\n\n"
                "Run the specified command in a transient scope or service unit.\n\n"
-               "  -h --help               Show this help\n"
-               "     --version            Show package version\n"
-               "     --user               Run as user unit\n"
-               "  -H --host=[USER@]HOST   Operate on remote host\n"
-               "  -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"
-               "     --description=TEXT   Description for unit\n"
-               "     --slice=SLICE        Run in the specified slice\n"
-               "  -r --remain-after-exit  Leave service around until explicitly stopped\n"
-               "     --send-sighup        Send SIGHUP when terminating\n"
-               "     --service-type=TYPE  Service type\n"
-               "     --uid=USER           Run as system user\n"
-               "     --gid=GROUP          Run as system group\n"
-               "     --nice=NICE          Nice level\n"
-               "     --setenv=NAME=VALUE  Set environment\n",
+               "  -h --help                 Show this help\n"
+               "     --version              Show package version\n"
+               "     --user                 Run as user unit\n"
+               "  -H --host=[USER@]HOST     Operate on remote host\n"
+               "  -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"
+               "     --description=TEXT     Description for unit\n"
+               "     --slice=SLICE          Run in the specified slice\n"
+               "  -r --remain-after-exit    Leave service around until explicitly stopped\n"
+               "     --send-sighup          Send SIGHUP when terminating\n"
+               "     --service-type=TYPE    Service type\n"
+               "     --uid=USER             Run as system user\n"
+               "     --gid=GROUP            Run as system group\n"
+               "     --nice=NICE            Nice level\n"
+               "     --setenv=NAME=VALUE    Set environment\n",
                program_invocation_short_name);
 
         return 0;
@@ -107,6 +109,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "gid",               required_argument, NULL, ARG_EXEC_GROUP   },
                 { "nice",              required_argument, NULL, ARG_NICE         },
                 { "setenv",            required_argument, NULL, ARG_SETENV       },
+                { "property",          required_argument, NULL, 'p'              },
                 {},
         };
 
@@ -115,7 +118,7 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "+hrH:M:", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "+hrH:M:p:", options, NULL)) >= 0) {
 
                 switch (c) {
 
@@ -198,6 +201,13 @@ static int parse_argv(int argc, char *argv[]) {
 
                         break;
 
+                case 'p':
+
+                        if (strv_extend(&arg_property, optarg) < 0)
+                                return log_oom();
+
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -231,6 +241,7 @@ static int parse_argv(int argc, char *argv[]) {
 
 static int message_start_transient_unit_new(sd_bus *bus, const char *name, sd_bus_message **ret) {
         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        char **i;
         int r;
 
         assert(bus);
@@ -257,6 +268,20 @@ static int message_start_transient_unit_new(sd_bus *bus, const char *name, sd_bu
         if (r < 0)
                 return r;
 
+        STRV_FOREACH(i, arg_property) {
+                r = sd_bus_message_open_container(m, 'r', "sv");
+                if (r < 0)
+                        return r;
+
+                r = bus_append_unit_property_assignment(m, *i);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_close_container(m);
+                if (r < 0)
+                        return r;
+        }
+
         r = sd_bus_message_append(m, "(sv)", "Description", "s", arg_description);
         if (r < 0)
                 return r;
@@ -273,9 +298,11 @@ static int message_start_transient_unit_new(sd_bus *bus, const char *name, sd_bu
                         return r;
         }
 
-        r = sd_bus_message_append(m, "(sv)", "SendSIGHUP", "b", arg_send_sighup);
-        if (r < 0)
-                return r;
+        if (arg_send_sighup) {
+                r = sd_bus_message_append(m, "(sv)", "SendSIGHUP", "b", arg_send_sighup);
+                if (r < 0)
+                        return r;
+        }
 
         *ret = m;
         m = NULL;
@@ -320,9 +347,11 @@ static int start_transient_service(
         if (r < 0)
                 return r;
 
-        r = sd_bus_message_append(m, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit);
-        if (r < 0)
-                return r;
+        if (arg_remain_after_exit) {
+                r = sd_bus_message_append(m, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit);
+                if (r < 0)
+                        return r;
+        }
 
         if (arg_service_type) {
                 r = sd_bus_message_append(m, "(sv)", "Type", "s", arg_service_type);
@@ -504,5 +533,8 @@ int main(int argc, char* argv[]) {
                 log_error("Failed start transient unit: %s", bus_error_message(&error, r));
 
 finish:
+        strv_free(arg_environment);
+        strv_free(arg_property);
+
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 952d2f8..f395265 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -4019,163 +4019,6 @@ static int show(sd_bus *bus, char **args) {
         return ret;
 }
 
-static int append_assignment(sd_bus_message *m, const char *assignment) {
-        const char *eq;
-        char *field;
-        int r;
-
-        assert(m);
-        assert(assignment);
-
-        eq = strchr(assignment, '=');
-        if (!eq) {
-                log_error("Not an assignment: %s", assignment);
-                return -EINVAL;
-        }
-
-        field = strndupa(assignment, eq - assignment);
-        eq ++;
-
-        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
-        if (r < 0)
-                return bus_log_create_error(r);
-
-        if (streq(field, "CPUAccounting") ||
-            streq(field, "MemoryAccounting") ||
-            streq(field, "BlockIOAccounting")) {
-
-                r = parse_boolean(eq);
-                if (r < 0) {
-                        log_error("Failed to parse boolean assignment %s.", assignment);
-                        return -EINVAL;
-                }
-
-                r = sd_bus_message_append(m, "v", "b", r);
-
-        } else if (streq(field, "MemoryLimit")) {
-                off_t bytes;
-
-                r = parse_size(eq, 1024, &bytes);
-                if (r < 0) {
-                        log_error("Failed to parse bytes specification %s", assignment);
-                        return -EINVAL;
-                }
-
-                r = sd_bus_message_append(m, "v", "t", (uint64_t) bytes);
-
-        } else if (streq(field, "CPUShares") || streq(field, "BlockIOWeight")) {
-                uint64_t u;
-
-                r = safe_atou64(eq, &u);
-                if (r < 0) {
-                        log_error("Failed to parse %s value %s.", field, eq);
-                        return -EINVAL;
-                }
-
-                r = sd_bus_message_append(m, "v", "t", u);
-
-        } else if (streq(field, "DevicePolicy"))
-                r = sd_bus_message_append(m, "v", "s", eq);
-
-        else if (streq(field, "DeviceAllow")) {
-
-                if (isempty(eq))
-                        r = sd_bus_message_append(m, "v", "a(ss)", 0);
-                else {
-                        const char *path, *rwm;
-                        char *e;
-
-                        e = strchr(eq, ' ');
-                        if (e) {
-                                path = strndupa(eq, e - eq);
-                                rwm = e+1;
-                        } else {
-                                path = eq;
-                                rwm = "";
-                        }
-
-                        if (!path_startswith(path, "/dev")) {
-                                log_error("%s is not a device file in /dev.", path);
-                                return -EINVAL;
-                        }
-
-                        r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
-                }
-
-        } else if (streq(field, "BlockIOReadBandwidth") || streq(field, "BlockIOWriteBandwidth")) {
-
-                if (isempty(eq))
-                        r = sd_bus_message_append(m, "v", "a(st)", 0);
-                else {
-                        const char *path, *bandwidth;
-                        off_t bytes;
-                        char *e;
-
-                        e = strchr(eq, ' ');
-                        if (e) {
-                                path = strndupa(eq, e - eq);
-                                bandwidth = e+1;
-                        } else {
-                                log_error("Failed to parse %s value %s.", field, eq);
-                                return -EINVAL;
-                        }
-
-                        if (!path_startswith(path, "/dev")) {
-                                log_error("%s is not a device file in /dev.", path);
-                                return -EINVAL;
-                        }
-
-                        r = parse_size(bandwidth, 1000, &bytes);
-                        if (r < 0) {
-                                log_error("Failed to parse byte value %s.", bandwidth);
-                                return -EINVAL;
-                        }
-
-                        r = sd_bus_message_append(m, "v", "a(st)", 1, path, (uint64_t) bytes);
-                }
-
-        } else if (streq(field, "BlockIODeviceWeight")) {
-
-                if (isempty(eq))
-                        r = sd_bus_message_append(m, "v", "a(st)", 0);
-                else {
-                        const char *path, *weight;
-                        uint64_t u;
-                        char *e;
-
-                        e = strchr(eq, ' ');
-                        if (e) {
-                                path = strndupa(eq, e - eq);
-                                weight = e+1;
-                        } else {
-                                log_error("Failed to parse %s value %s.", field, eq);
-                                return -EINVAL;
-                        }
-
-                        if (!path_startswith(path, "/dev")) {
-                                log_error("%s is not a device file in /dev.", path);
-                                return -EINVAL;
-                        }
-
-                        r = safe_atou64(weight, &u);
-                        if (r < 0) {
-                                log_error("Failed to parse %s value %s.", field, weight);
-                                return -EINVAL;
-                        }
-                        r = sd_bus_message_append(m, "v", "a(st)", path, u);
-                }
-
-        } else {
-                log_error("Unknown assignment %s.", assignment);
-                return -EINVAL;
-        }
-
-        if (r < 0)
-                return bus_log_create_error(r);
-
-        return 0;
-}
-
 static int set_property(sd_bus *bus, char **args) {
         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -4210,7 +4053,7 @@ static int set_property(sd_bus *bus, char **args) {
                 if (r < 0)
                         return bus_log_create_error(r);
 
-                r = append_assignment(m, *i);
+                r = bus_append_unit_property_assignment(m, *i);
                 if (r < 0)
                         return r;
 

commit 53ede806cb58c661efbee6bbaabee6b2f0d3ce79
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Mar 5 03:34:48 2014 +0100

    strv: add new STR_IN_SET() macro that operates similar to IN_SET() but for strings

diff --git a/src/shared/strv.h b/src/shared/strv.h
index 13a4bb6..618951c 100644
--- a/src/shared/strv.h
+++ b/src/shared/strv.h
@@ -116,3 +116,5 @@ void strv_print(char **l);
                 }                                               \
                 _l;                                             \
         })
+
+#define STR_IN_SET(x, ...) strv_contains(STRV_MAKE(__VA_ARGS__), x)



More information about the systemd-commits mailing list