[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