chiark / gitweb /
systemd-run: add new --property= switch that can set arbitrary properties for the...
authorLennart Poettering <lennart@poettering.net>
Wed, 5 Mar 2014 02:36:22 +0000 (03:36 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 5 Mar 2014 02:36:22 +0000 (03:36 +0100)
The code for parsing these properties is shared with "systemctl
set-property", which means all the resource control settings are
immediately available.

man/systemd-run.xml
src/libsystemd/sd-bus/bus-util.c
src/libsystemd/sd-bus/bus-util.h
src/run/run.c
src/systemctl/systemctl.c

index 064195a989ff9486c43eca64fba0c96d8400a99a..95c1cb739611513260bc60ee46bf2a426b15b335 100644 (file)
@@ -106,6 +106,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
         generated one.</para></listitem>
       </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>
 
@@ -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>
index 2935f69684d839aefe1277189f0b4070b1919385..40aab2a88c7c42874ce26b0c52c8b249ae6d9d7e 100644 (file)
@@ -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;
+}
index 51e1613c17a0b344019bb9987314332635da6e1b..b0936208fbd9cdd1fface287a322b4452abd4656 100644 (file)
@@ -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);
index 885d881ec6763ebf652bc295f5d5972b46627687..81763c94ffef0b7bc6cde552e683791292139164 100644 (file)
@@ -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;
 }
index 952d2f8358caeb7ca9da0e4ee426d5dc5a6122a5..f3952653e153698352bae410bc6cb9f6a565eef4 100644 (file)
@@ -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;