<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>
<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,
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
<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>
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>
<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>
#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;
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 {
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);
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;
assert_not_reached("Unhandled option");
}
- if (optind >= argc) {
+ if ((optind >= argc) && (!arg_unit || !with_timer())) {
log_error("Command line to execute required.");
return -EINVAL;
}
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)
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);
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;
}
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);
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");
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, " ");
goto finish;
}
+ if (arg_unit && isempty(description)) {
+ free(description);
+ description = strdup(arg_unit);
+
+ if (!description) {
+ r = log_oom();
+ goto finish;
+ }
+ }
+
arg_description = description;
}
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;
}