[systemd-devel] [PATCH v7] run: introduce timer support option
Lennart Poettering
lennart at poettering.net
Tue Dec 9 09:25:35 PST 2014
On Tue, 09.12.14 16:07, WaLyong Cho (walyong.cho at samsung.com) wrote:
> Support timer options --on-active=, --on-boot=, --on-startup=,
> --on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
> corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
> OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
> respectively. And OnCalendar= and WakeSystem= supported by
> --timer-property= option like --property= of systemd-run.
Looks good! Applied!
Thanks!
>
> And if --unit= option and timer options are specified the command can
> be omitted. In this case, systemd-run assumes the target service is
> already loaded. And just try to generate transient timer unit only.
> ---
> man/systemd-run.xml | 94 +++++-
> src/core/dbus-manager.c | 8 +-
> src/libsystemd/sd-bus/bus-util.c | 14 +-
> src/run/run.c | 628 ++++++++++++++++++++++++++++++---------
> 4 files changed, 596 insertions(+), 148 deletions(-)
>
> diff --git a/man/systemd-run.xml b/man/systemd-run.xml
> index 28a9878..b9cec91 100644
> --- a/man/systemd-run.xml
> +++ b/man/systemd-run.xml
> @@ -45,7 +45,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
>
> <refnamediv>
> <refname>systemd-run</refname>
> - <refpurpose>Run programs in transient scope or service units</refpurpose>
> + <refpurpose>Run programs in transient scope or service or timer units</refpurpose>
> </refnamediv>
>
> <refsynopsisdiv>
> @@ -56,15 +56,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
> <arg choice="opt" rep="repeat">ARGS</arg>
> </arg>
> </cmdsynopsis>
> + <cmdsynopsis>
> + <command>systemd-run</command>
> + <arg choice="opt" rep="repeat">OPTIONS</arg>
> + <arg choice="opt" rep="repeat">TIMER OPTIONS</arg>
> + <arg choice="req"><replaceable>COMMAND</replaceable></arg>
> + <arg choice="opt" rep="repeat">ARGS</arg>
> + </cmdsynopsis>
> </refsynopsisdiv>
>
> <refsect1>
> <title>Description</title>
>
> - <para><command>systemd-run</command> may be used to create and start
> - a transient <filename>.service</filename> or a
> - <filename>.scope</filename> unit and run the specified
> - <replaceable>COMMAND</replaceable> in it.</para>
> + <para><command>systemd-run</command> may be used to create and
> + start a transient <filename>.service</filename> or a transient
> + <filename>.timer</filename> or a <filename>.scope</filename> unit
> + and run the specified <replaceable>COMMAND</replaceable> in
> + it.</para>
>
> <para>If a command is run as transient service unit, it will be
> started and managed by the service manager like any other service,
> @@ -74,6 +82,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
> will start the service asynchronously in the background and
> immediately return.</para>
>
> + <para>If a command is run with timer options, transient timer unit
> + also be created with transient service unit. But the transient
> + timer unit is only started immediately. The transient service unit
> + will be started when the transient timer is elapsed. If
> + <option>--unit=</option> is specified with timer options, the
> + <replaceable>COMMAND</replaceable> can be omitted. In this case,
> + <command>systemd-run</command> assumes service unit is already
> + loaded and creates transient timer unit only. To successfully
> + create timer unit, already loaded service unit should be specified
> + with <option>--unit=</option>. This transient timer unit can
> + activate the existing service unit like any other timer.</para>
> +
> <para>If a command is run as transient scope unit, it will be
> started directly by <command>systemd-run</command> and thus
> inherit the execution environment of the caller. It is however
> @@ -210,6 +230,54 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
> <xi:include href="user-system-options.xml" xpointer="host" />
> <xi:include href="user-system-options.xml" xpointer="machine" />
>
> + <varlistentry>
> + <term><option>--on-active=</option></term>
> + <term><option>--on-boot=</option></term>
> + <term><option>--on-startup=</option></term>
> + <term><option>--on-unit-active=</option></term>
> + <term><option>--on-unit-inactive=</option></term>
> +
> + <listitem><para>Defines monotonic timers relative to different
> + starting points. Also see <varname>OnActiveSec=</varname>,
> + <varname>OnBootSec=</varname>,
> + <varname>OnStartupSec=</varname>,
> + <varname>OnUnitActiveSec=</varname> and
> + <varname>OnUnitInactiveSec=</varname> in
> + <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>. This
> + options have no effect in conjunction with
> + <option>--scope</option>.</para>
> + </listitem>
> + </varlistentry>
> +
> + <varlistentry>
> + <term><option>--on-calendar=</option></term>
> +
> + <listitem><para>Defines realtime (i.e. wallclock) timers with
> + calendar event expressions. Also see
> + <varname>OnCalendar=</varname> in
> + <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>. This
> + option has no effect in conjunction with
> + <option>--scope</option>.</para>
> + </listitem>
> + </varlistentry>
> +
> + <varlistentry>
> + <term><option>--timer-property=</option></term>
> +
> + <listitem><para>Sets a timer unit property for the timer unit
> + that is created. It is similar with
> + <option>--property</option> but only for created timer
> + unit. This option only has effect in conjunction with
> + <option>--on-active=</option>, <option>--on-boot=</option>,
> + <option>--on-startup=</option>,
> + <option>--on-unit-active=</option>,
> + <option>--on-unit-inactive=</option>,
> + <option>--on-calendar=</option>. 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>
> +
> <xi:include href="standard-options.xml" xpointer="help" />
> <xi:include href="standard-options.xml" xpointer="version" />
> </variablelist>
> @@ -250,6 +318,21 @@ Sep 08 07:37:21 bupkis env[19948]: BOOT_IMAGE=/vmlinuz-3.11.0-0.rc5.git6.2.fc20.
> property.</para>
>
> <programlisting># systemd-run -p BlockIOWeight=10 updatedb</programlisting>
> +
> + <para>The following command will touch a file after 30 seconds.</para>
> +
> + <programlisting># date; systemd-run --on-active=30 --timer-property=AccuracySec=100ms /bin/touch /tmp/foo
> +Mon Dec 8 20:44:24 KST 2014
> +Running as unit run-71.timer.
> +Will run as unit run-71.service.
> +# journalctl -b -u run-73.timer
> +-- Logs begin at Fri 2014-12-05 19:09:21 KST, end at Mon 2014-12-08 20:44:54 KST. --
> +Dec 08 20:44:38 container systemd[1]: Starting /bin/touch /tmp/foo.
> +Dec 08 20:44:38 container systemd[1]: Started /bin/touch /tmp/foo.
> +# journalctl -b -u run-73.service
> +-- Logs begin at Fri 2014-12-05 19:09:21 KST, end at Mon 2014-12-08 20:44:54 KST. --
> +Dec 08 20:44:48 container systemd[1]: Starting /bin/touch /tmp/foo...
> +Dec 08 20:44:48 container systemd[1]: Started /bin/touch /tmp/foo.</programlisting>
> </refsect1>
>
> <refsect1>
> @@ -263,6 +346,7 @@ Sep 08 07:37:21 bupkis env[19948]: BOOT_IMAGE=/vmlinuz-3.11.0-0.rc5.git6.2.fc20.
> <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>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
> <citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
> </para>
> </refsect1>
> diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
> index 5fe06f9..140a413 100644
> --- a/src/core/dbus-manager.c
> +++ b/src/core/dbus-manager.c
> @@ -681,9 +681,11 @@ static int transient_aux_units_from_message(
> if (r < 0 && r != -EEXIST)
> return r;
>
> - r = unit_load(u);
> - if (r < 0)
> - return r;
> + if (r != -EEXIST) {
> + r = unit_load(u);
> + if (r < 0)
> + return r;
> + }
>
> r = sd_bus_message_exit_container(message);
> if (r < 0)
> diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c
> index bdaa449..0f1a89c 100644
> --- a/src/libsystemd/sd-bus/bus-util.c
> +++ b/src/libsystemd/sd-bus/bus-util.c
> @@ -1372,7 +1372,8 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
>
> if (STR_IN_SET(field,
> "CPUAccounting", "MemoryAccounting", "BlockIOAccounting",
> - "SendSIGHUP", "SendSIGKILL")) {
> + "SendSIGHUP", "SendSIGKILL",
> + "WakeSystem")) {
>
> r = parse_boolean(eq);
> if (r < 0) {
> @@ -1533,6 +1534,17 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
>
> r = sd_bus_message_append(m, "v", "i", sig);
>
> + } else if (streq(field, "AccuracySec")) {
> + usec_t u;
> +
> + r = parse_sec(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 {
> log_error("Unknown assignment %s.", assignment);
> return -EINVAL;
> diff --git a/src/run/run.c b/src/run/run.c
> index 85eb052..7a80223 100644
> --- a/src/run/run.c
> +++ b/src/run/run.c
> @@ -30,6 +30,7 @@
> #include "env-util.h"
> #include "path-util.h"
> #include "bus-error.h"
> +#include "calendarspec.h"
>
> static bool arg_scope = false;
> static bool arg_remain_after_exit = false;
> @@ -47,30 +48,51 @@ static int arg_nice = 0;
> static bool arg_nice_set = false;
> static char **arg_environment = NULL;
> static char **arg_property = NULL;
> +static usec_t arg_on_active = 0;
> +static usec_t arg_on_boot = 0;
> +static usec_t arg_on_startup = 0;
> +static usec_t arg_on_unit_active = 0;
> +static usec_t arg_on_unit_inactive = 0;
> +static char *arg_on_calendar = NULL;
> +static char **arg_timer_property = NULL;
>
> static void 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"
> - " -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",
> + printf("%s [OPTIONS...] {COMMAND} [ARGS...]\n\n"
> + "Run the specified command in a transient scope or service or timer\n"
> + "unit. If timer option is specified and unit is exist which is\n"
> + "specified with --unit option then command can be ommited.\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"
> + " -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\n"
> + "Timer options:\n\n"
> + " --on-active=SEC Run after seconds\n"
> + " --on-boot=SEC Run after seconds from machine was booted up\n"
> + " --on-startup=SEC Run after seconds from systemd was first started\n"
> + " --on-unit-active=SEC Run after seconds from the last activation\n"
> + " --on-unit-inactive=SEC Run after seconds from the last deactivation\n"
> + " --on-calendar=SPEC Realtime timer\n"
> + " --timer-property=NAME=VALUE Set timer unit property\n",
> program_invocation_short_name);
> }
>
> +static bool with_timer(void) {
> + return arg_on_active || arg_on_boot || arg_on_startup || arg_on_unit_active || arg_on_unit_inactive || arg_on_calendar;
> +}
> +
> static int parse_argv(int argc, char *argv[]) {
>
> enum {
> @@ -86,32 +108,47 @@ static int parse_argv(int argc, char *argv[]) {
> ARG_EXEC_GROUP,
> ARG_SERVICE_TYPE,
> ARG_NICE,
> - ARG_SETENV
> + ARG_SETENV,
> + ARG_ON_ACTIVE,
> + ARG_ON_BOOT,
> + ARG_ON_STARTUP,
> + ARG_ON_UNIT_ACTIVE,
> + ARG_ON_UNIT_INACTIVE,
> + ARG_ON_CALENDAR,
> + ARG_TIMER_PROPERTY
> };
>
> static const struct option options[] = {
> - { "help", no_argument, NULL, 'h' },
> - { "version", no_argument, NULL, ARG_VERSION },
> - { "user", no_argument, NULL, ARG_USER },
> - { "system", no_argument, NULL, ARG_SYSTEM },
> - { "scope", no_argument, NULL, ARG_SCOPE },
> - { "unit", required_argument, NULL, ARG_UNIT },
> - { "description", required_argument, NULL, ARG_DESCRIPTION },
> - { "slice", required_argument, NULL, ARG_SLICE },
> - { "remain-after-exit", no_argument, NULL, 'r' },
> - { "send-sighup", no_argument, NULL, ARG_SEND_SIGHUP },
> - { "host", required_argument, NULL, 'H' },
> - { "machine", required_argument, NULL, 'M' },
> - { "service-type", required_argument, NULL, ARG_SERVICE_TYPE },
> - { "uid", required_argument, NULL, ARG_EXEC_USER },
> - { "gid", required_argument, NULL, ARG_EXEC_GROUP },
> - { "nice", required_argument, NULL, ARG_NICE },
> - { "setenv", required_argument, NULL, ARG_SETENV },
> - { "property", required_argument, NULL, 'p' },
> + { "help", no_argument, NULL, 'h' },
> + { "version", no_argument, NULL, ARG_VERSION },
> + { "user", no_argument, NULL, ARG_USER },
> + { "system", no_argument, NULL, ARG_SYSTEM },
> + { "scope", no_argument, NULL, ARG_SCOPE },
> + { "unit", required_argument, NULL, ARG_UNIT },
> + { "description", required_argument, NULL, ARG_DESCRIPTION },
> + { "slice", required_argument, NULL, ARG_SLICE },
> + { "remain-after-exit", no_argument, NULL, 'r' },
> + { "send-sighup", no_argument, NULL, ARG_SEND_SIGHUP },
> + { "host", required_argument, NULL, 'H' },
> + { "machine", required_argument, NULL, 'M' },
> + { "service-type", required_argument, NULL, ARG_SERVICE_TYPE },
> + { "uid", required_argument, NULL, ARG_EXEC_USER },
> + { "gid", required_argument, NULL, ARG_EXEC_GROUP },
> + { "nice", required_argument, NULL, ARG_NICE },
> + { "setenv", required_argument, NULL, ARG_SETENV },
> + { "property", required_argument, NULL, 'p' },
> + { "on-active", required_argument, NULL, ARG_ON_ACTIVE },
> + { "on-boot", required_argument, NULL, ARG_ON_BOOT },
> + { "on-startup", required_argument, NULL, ARG_ON_STARTUP },
> + { "on-unit-active", required_argument, NULL, ARG_ON_UNIT_ACTIVE },
> + { "on-unit-inactive", required_argument, NULL, ARG_ON_UNIT_INACTIVE },
> + { "on-calendar", required_argument, NULL, ARG_ON_CALENDAR },
> + { "timer-property", required_argument, NULL, ARG_TIMER_PROPERTY },
> {},
> };
>
> int r, c;
> + CalendarSpec *spec = NULL;
>
> assert(argc >= 0);
> assert(argv);
> @@ -207,6 +244,74 @@ static int parse_argv(int argc, char *argv[]) {
>
> break;
>
> + case ARG_ON_ACTIVE:
> +
> + r = parse_sec(optarg, &arg_on_active);
> + if (r < 0) {
> + log_error("Failed to parse timer value: %s", optarg);
> + return r;
> + }
> +
> + break;
> +
> + case ARG_ON_BOOT:
> +
> + r = parse_sec(optarg, &arg_on_boot);
> + if (r < 0) {
> + log_error("Failed to parse timer value: %s", optarg);
> + return r;
> + }
> +
> + break;
> +
> + case ARG_ON_STARTUP:
> +
> + r = parse_sec(optarg, &arg_on_startup);
> + if (r < 0) {
> + log_error("Failed to parse timer value: %s", optarg);
> + return r;
> + }
> +
> + break;
> +
> + case ARG_ON_UNIT_ACTIVE:
> +
> + r = parse_sec(optarg, &arg_on_unit_active);
> + if (r < 0) {
> + log_error("Failed to parse timer value: %s", optarg);
> + return r;
> + }
> +
> + break;
> +
> + case ARG_ON_UNIT_INACTIVE:
> +
> + r = parse_sec(optarg, &arg_on_unit_inactive);
> + if (r < 0) {
> + log_error("Failed to parse timer value: %s", optarg);
> + return r;
> + }
> +
> + break;
> +
> + case ARG_ON_CALENDAR:
> +
> + r = calendar_spec_from_string(optarg, &spec);
> + if (r < 0) {
> + log_error("Invalid calendar spec: %s", optarg);
> + return r;
> + }
> + free(spec);
> + arg_on_calendar = optarg;
> + break;
> +
> + case ARG_TIMER_PROPERTY:
> +
> + if (strv_extend(&arg_timer_property, optarg) < 0)
> + return log_oom();
> +
> + break;
> +
> case '?':
> return -EINVAL;
>
> @@ -214,7 +319,7 @@ static int parse_argv(int argc, char *argv[]) {
> assert_not_reached("Unhandled option");
> }
>
> - if (optind >= argc) {
> + if ((optind >= argc) && (!arg_unit || !with_timer())) {
> log_error("Command line to execute required.");
> return -EINVAL;
> }
> @@ -234,44 +339,34 @@ static int parse_argv(int argc, char *argv[]) {
> return -EINVAL;
> }
>
> + if (arg_scope && with_timer()) {
> + log_error("Timer options are not supported in --scope mode.");
> + return -EINVAL;
> + }
> +
> + if (arg_timer_property && !with_timer()) {
> + log_error("--timer-property= has no effect without any other timer options.");
> + return -EINVAL;
> + }
> +
> return 1;
> }
>
> -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;
> +static int transient_unit_set_properties(sd_bus_message *m, UnitType t) {
> char **i;
> int r;
>
> - assert(bus);
> - assert(name);
> - assert(ret);
> -
> - r = sd_bus_message_new_method_call(
> - bus,
> - &m,
> - "org.freedesktop.systemd1",
> - "/org/freedesktop/systemd1",
> - "org.freedesktop.systemd1.Manager",
> - "StartTransientUnit");
> - if (r < 0)
> - return r;
> -
> - r = sd_bus_message_append(m, "ss", name, "fail");
> - if (r < 0)
> - return r;
> -
> - r = sd_bus_message_open_container(m, 'a', "(sv)");
> - if (r < 0)
> - return r;
> -
> - STRV_FOREACH(i, arg_property) {
> + STRV_FOREACH(i, t == UNIT_TIMER ? arg_timer_property : 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;
> + if (r < 0) {
> + r = sd_bus_message_append(m, "sv", 0);
> + if (r < 0)
> + return r;
> + }
>
> r = sd_bus_message_close_container(m);
> if (r < 0)
> @@ -294,152 +389,324 @@ static int message_start_transient_unit_new(sd_bus *bus, const char *name, sd_bu
> return r;
> }
>
> - if (arg_send_sighup) {
> + if (arg_send_sighup && t != UNIT_TIMER) {
> r = sd_bus_message_append(m, "(sv)", "SendSIGHUP", "b", arg_send_sighup);
> if (r < 0)
> return r;
> }
>
> - *ret = m;
> - m = NULL;
> -
> return 0;
> }
>
> -static int message_start_transient_unit_send(sd_bus *bus, sd_bus_message *m, sd_bus_error *error, sd_bus_message **reply) {
> +static int transient_service_set_properties(sd_bus_message *m, char **argv) {
> int r;
>
> - assert(bus);
> assert(m);
>
> - r = sd_bus_message_close_container(m);
> - if (r < 0)
> - return r;
> -
> - r = sd_bus_message_append(m, "a(sa(sv))", 0);
> + r = transient_unit_set_properties(m, UNIT_SERVICE);
> if (r < 0)
> return r;
>
> - return sd_bus_call(bus, m, 0, error, reply);
> -}
> -
> -static int start_transient_service(
> - sd_bus *bus,
> - char **argv,
> - sd_bus_error *error) {
> -
> - _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
> - _cleanup_free_ char *name = NULL;
> - int r;
> -
> - if (arg_unit) {
> - name = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".service");
> - if (!name)
> - return log_oom();
> - } else if (asprintf(&name, "run-"PID_FMT".service", getpid()) < 0)
> - return log_oom();
> -
> - r = message_start_transient_unit_new(bus, name, &m);
> - if (r < 0)
> - return bus_log_create_error(r);
> -
> if (arg_remain_after_exit) {
> r = sd_bus_message_append(m, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit);
> if (r < 0)
> - return bus_log_create_error(r);
> + return r;
> }
>
> if (arg_service_type) {
> r = sd_bus_message_append(m, "(sv)", "Type", "s", arg_service_type);
> if (r < 0)
> - return bus_log_create_error(r);
> + return r;
> }
>
> if (arg_exec_user) {
> r = sd_bus_message_append(m, "(sv)", "User", "s", arg_exec_user);
> if (r < 0)
> - return bus_log_create_error(r);
> + return r;
> }
>
> if (arg_exec_group) {
> r = sd_bus_message_append(m, "(sv)", "Group", "s", arg_exec_group);
> if (r < 0)
> - return bus_log_create_error(r);
> + return r;
> }
>
> if (arg_nice_set) {
> r = sd_bus_message_append(m, "(sv)", "Nice", "i", arg_nice);
> if (r < 0)
> - return bus_log_create_error(r);
> + return r;
> }
>
> if (!strv_isempty(arg_environment)) {
> r = sd_bus_message_open_container(m, 'r', "sv");
> if (r < 0)
> - return bus_log_create_error(r);
> + return r;
>
> r = sd_bus_message_append(m, "s", "Environment");
> if (r < 0)
> - return bus_log_create_error(r);
> + return r;
>
> r = sd_bus_message_open_container(m, 'v', "as");
> if (r < 0)
> - return bus_log_create_error(r);
> + return r;
>
> r = sd_bus_message_append_strv(m, arg_environment);
> if (r < 0)
> - return bus_log_create_error(r);
> + return r;
>
> r = sd_bus_message_close_container(m);
> if (r < 0)
> - return bus_log_create_error(r);
> + return r;
>
> r = sd_bus_message_close_container(m);
> if (r < 0)
> - return bus_log_create_error(r);
> + return r;
> + }
> +
> + /* Exec container */
> + {
> + r = sd_bus_message_open_container(m, 'r', "sv");
> + if (r < 0)
> + return r;
> +
> + r = sd_bus_message_append(m, "s", "ExecStart");
> + if (r < 0)
> + return r;
> +
> + r = sd_bus_message_open_container(m, 'v', "a(sasb)");
> + if (r < 0)
> + return r;
> +
> + r = sd_bus_message_open_container(m, 'a', "(sasb)");
> + if (r < 0)
> + return r;
> +
> + r = sd_bus_message_open_container(m, 'r', "sasb");
> + if (r < 0)
> + return r;
> +
> + r = sd_bus_message_append(m, "s", argv[0]);
> + if (r < 0)
> + return r;
> +
> + r = sd_bus_message_append_strv(m, argv);
> + if (r < 0)
> + return r;
> +
> + r = sd_bus_message_append(m, "b", false);
> + if (r < 0)
> + return r;
> +
> + r = sd_bus_message_close_container(m);
> + if (r < 0)
> + return r;
> +
> + r = sd_bus_message_close_container(m);
> + if (r < 0)
> + return r;
> +
> + r = sd_bus_message_close_container(m);
> + if (r < 0)
> + return r;
> +
> + r = sd_bus_message_close_container(m);
> + if (r < 0)
> + return r;
> + }
> +
> + return 0;
> +}
> +
> +static int transient_timer_set_properties(sd_bus_message *m) {
> + int r;
> +
> + assert(m);
> +
> + r = transient_unit_set_properties(m, UNIT_TIMER);
> + if (r < 0)
> + return r;
> +
> + if (arg_on_active) {
> + r = sd_bus_message_append(m, "(sv)", "OnActiveSec", "t", arg_on_active);
> + if (r < 0)
> + return r;
> }
>
> - r = sd_bus_message_open_container(m, 'r', "sv");
> + if (arg_on_boot) {
> + r = sd_bus_message_append(m, "(sv)", "OnBootSec", "t", arg_on_boot);
> + if (r < 0)
> + return r;
> + }
> +
> + if (arg_on_startup) {
> + r = sd_bus_message_append(m, "(sv)", "OnStartupSec", "t", arg_on_startup);
> + if (r < 0)
> + return r;
> + }
> +
> + if (arg_on_unit_active) {
> + r = sd_bus_message_append(m, "(sv)", "OnUnitActiveSec", "t", arg_on_unit_active);
> + if (r < 0)
> + return r;
> + }
> +
> + if (arg_on_unit_inactive) {
> + r = sd_bus_message_append(m, "(sv)", "OnUnitInactiveSec", "t", arg_on_unit_inactive);
> + if (r < 0)
> + return r;
> + }
> +
> + if (arg_on_calendar) {
> + r = sd_bus_message_append(m, "(sv)", "OnCalendar", "s", arg_on_calendar);
> + if (r < 0)
> + return r;
> + }
> +
> + return 0;
> +}
> +
> +static int transient_scope_set_properties(sd_bus_message *m) {
> + int r;
> +
> + assert(m);
> +
> + r = transient_unit_set_properties(m, UNIT_SCOPE);
> + if (r < 0)
> + return r;
> +
> + r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
> + if (r < 0)
> + return r;
> +
> + return 0;
> +}
> +
> +static int start_transient_service(
> + sd_bus *bus,
> + char **argv,
> + sd_bus_error *error) {
> +
> + _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
> + _cleanup_free_ char *service = NULL;
> + int r;
> +
> + assert(bus);
> + assert(argv);
> +
> + if (arg_unit) {
> + service = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".service");
> + if (!service)
> + return log_oom();
> + } else if (asprintf(&service, "run-"PID_FMT".service", getpid()) < 0)
> + return log_oom();
> +
> + 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_append(m, "s", "ExecStart");
> + /* name and mode */
> + r = sd_bus_message_append(m, "ss", service, "fail");
> if (r < 0)
> return bus_log_create_error(r);
>
> - r = sd_bus_message_open_container(m, 'v', "a(sasb)");
> + /* properties */
> + r = sd_bus_message_open_container(m, 'a', "(sv)");
> if (r < 0)
> return bus_log_create_error(r);
>
> - r = sd_bus_message_open_container(m, 'a', "(sasb)");
> + r = transient_service_set_properties(m, argv);
> if (r < 0)
> return bus_log_create_error(r);
>
> - r = sd_bus_message_open_container(m, 'r', "sasb");
> + r = sd_bus_message_close_container(m);
> if (r < 0)
> return bus_log_create_error(r);
>
> - r = sd_bus_message_append(m, "s", argv[0]);
> + /* aux */
> + r = sd_bus_message_append(m, "a(sa(sv))", 0);
> if (r < 0)
> return bus_log_create_error(r);
>
> - r = sd_bus_message_append_strv(m, argv);
> + /* send dbus */
> + r = sd_bus_call(bus, m, 0, error, NULL);
> if (r < 0)
> return bus_log_create_error(r);
>
> - r = sd_bus_message_append(m, "b", false);
> + log_info("Running as unit %s.", service);
> +
> + return 0;
> +}
> +
> +static int start_transient_timer(
> + sd_bus *bus,
> + char **argv,
> + sd_bus_error *error) {
> +
> + _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
> + _cleanup_free_ char *timer = NULL, *service = NULL;
> + int r;
> +
> + assert(bus);
> + assert(argv);
> +
> + if (arg_unit) {
> + switch(unit_name_to_type(arg_unit)) {
> + case UNIT_SERVICE:
> + service = strdup(arg_unit);
> + timer = unit_name_change_suffix(service, ".timer");
> + if (!timer)
> + return log_oom();
> + break;
> +
> + case UNIT_TIMER:
> + timer = strdup(arg_unit);
> + service = unit_name_change_suffix(timer, ".service");
> + if (!service)
> + return log_oom();
> + break;
> +
> + default:
> + service = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".service");
> + if (!service)
> + return log_oom();
> +
> + timer = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".timer");
> + if (!timer)
> + return log_oom();
> +
> + break;
> + }
> + } else if ((asprintf(&service, "run-"PID_FMT".service", getpid()) < 0) ||
> + (asprintf(&timer, "run-"PID_FMT".timer", getpid()) < 0))
> + return log_oom();
> +
> + 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_close_container(m);
> + /* name and mode */
> + r = sd_bus_message_append(m, "ss", timer, "fail");
> if (r < 0)
> return bus_log_create_error(r);
>
> - r = sd_bus_message_close_container(m);
> + /* properties */
> + r = sd_bus_message_open_container(m, 'a', "(sv)");
> if (r < 0)
> return bus_log_create_error(r);
>
> - r = sd_bus_message_close_container(m);
> + r = transient_timer_set_properties(m);
> if (r < 0)
> return bus_log_create_error(r);
>
> @@ -447,11 +714,52 @@ static int start_transient_service(
> if (r < 0)
> return bus_log_create_error(r);
>
> - r = message_start_transient_unit_send(bus, m, error, NULL);
> + if (argv[0]) {
> + 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", service);
> + 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_service_set_properties(m, argv);
> + 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);
> + } else {
> + r = sd_bus_message_append(m, "a(sa(sv))", 0);
> + if (r < 0)
> + return bus_log_create_error(r);
> + }
> +
> + /* send dbus */
> + r = sd_bus_call(bus, m, 0, error, NULL);
> if (r < 0)
> return bus_log_create_error(r);
>
> - log_info("Running as unit %s.", name);
> + log_info("Running as unit %s.", timer);
> + if (argv[0])
> + log_info("Will run as unit %s.", service);
>
> return 0;
> }
> @@ -462,28 +770,55 @@ static int start_transient_scope(
> sd_bus_error *error) {
>
> _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
> - _cleanup_free_ char *name = NULL;
> + _cleanup_free_ char *scope = NULL;
> _cleanup_strv_free_ char **env = NULL, **user_env = NULL;
> int r;
>
> assert(bus);
> + assert(argv);
>
> if (arg_unit) {
> - name = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".scope");
> - if (!name)
> + scope = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".scope");
> + if (!scope)
> return log_oom();
> - } else if (asprintf(&name, "run-"PID_FMT".scope", getpid()) < 0)
> + } else if (asprintf(&scope, "run-"PID_FMT".scope", getpid()) < 0)
> return log_oom();
>
> - r = message_start_transient_unit_new(bus, 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_append(m, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
> + /* name and mode */
> + r = sd_bus_message_append(m, "ss", scope, "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_scope_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);
> +
> + /* aux */
> + r = sd_bus_message_append(m, "a(sa(sv))", 0);
> if (r < 0)
> return bus_log_create_error(r);
>
> - r = message_start_transient_unit_send(bus, m, error, NULL);
> + /* send dbus */
> + r = sd_bus_call(bus, m, 0, error, NULL);
> if (r < 0)
> return bus_log_create_error(r);
>
> @@ -541,7 +876,7 @@ static int start_transient_scope(
> if (!env)
> return log_oom();
>
> - log_info("Running as unit %s.", name);
> + log_info("Running as unit %s.", scope);
>
> execvpe(argv[0], argv, env);
> log_error_errno(errno, "Failed to execute: %m");
> @@ -561,14 +896,16 @@ int main(int argc, char* argv[]) {
> if (r <= 0)
> goto finish;
>
> - r = find_binary(argv[optind], arg_transport == BUS_TRANSPORT_LOCAL, &command);
> - if (r < 0) {
> - log_error_errno(r, "Failed to find executable %s%s: %m",
> - argv[optind],
> - arg_transport == BUS_TRANSPORT_LOCAL ? "" : " on local system");
> - goto finish;
> + if (argc > optind) {
> + r = find_binary(argv[optind], arg_transport == BUS_TRANSPORT_LOCAL, &command);
> + if (r < 0) {
> + log_error_errno(r, "Failed to find executable %s%s: %m",
> + argv[optind],
> + arg_transport == BUS_TRANSPORT_LOCAL ? "" : " on local system");
> + goto finish;
> + }
> + argv[optind] = command;
> }
> - argv[optind] = command;
>
> if (!arg_description) {
> description = strv_join(argv + optind, " ");
> @@ -577,6 +914,16 @@ int main(int argc, char* argv[]) {
> goto finish;
> }
>
> + if (arg_unit && isempty(description)) {
> + free(description);
> + description = strdup(arg_unit);
> +
> + if (!description) {
> + r = log_oom();
> + goto finish;
> + }
> + }
> +
> arg_description = description;
> }
>
> @@ -588,12 +935,15 @@ int main(int argc, char* argv[]) {
>
> if (arg_scope)
> r = start_transient_scope(bus, argv + optind, &error);
> + else if (with_timer())
> + r = start_transient_timer(bus, argv + optind, &error);
> else
> r = start_transient_service(bus, argv + optind, &error);
>
> finish:
> strv_free(arg_environment);
> strv_free(arg_property);
> + strv_free(arg_timer_property);
>
> return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
> }
> --
> 1.9.3
>
> _______________________________________________
> systemd-devel mailing list
> systemd-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Lennart
--
Lennart Poettering, Red Hat
More information about the systemd-devel
mailing list