diff --git a/man/systemd-run.xml b/man/systemd-run.xml
index eeefe901dc..a0924e30a2 100644
--- a/man/systemd-run.xml
+++ b/man/systemd-run.xml
@@ -484,6 +484,23 @@
+
+
+
+
+ When queuing a new job, this option controls how to deal with
+ already queued jobs.
+
+ The option takes the same mode values as
+ systemctl1's
+ option. The default job mode is fail.
+
+ Running shows a list of available job modes.
+
+
+
+
+
diff --git a/shell-completion/bash/systemd-run b/shell-completion/bash/systemd-run
index 4537211ae5..4524744bb5 100644
--- a/shell-completion/bash/systemd-run
+++ b/shell-completion/bash/systemd-run
@@ -38,7 +38,7 @@ _systemd_run() {
--unit -p --property --slice --description --service-type --uid --gid --nice --working-directory
-E --setenv --on-active --on-boot --on-startup --on-unit-active --on-unit-inactive --on-calendar
--path-property --socket-property --timer-property -H --host -M --machine --expand-environment
- --background --json
+ --background --json --job-mode
)
local OPTS="${opts_with_values[*]} --no-ask-password --scope -u --slice-inherit -r --remain-after-exit
--send-sighup -d --same-dir -t --pty -P --pipe -S --shell -q --quiet --ignore-failure
@@ -131,6 +131,11 @@ _systemd_run() {
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
return 0
;;
+ --job-mode)
+ local comps=$( systemd-run --job-mode=help 2>/dev/null )
+ COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
+ return 0
+ ;;
esac
COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") )
diff --git a/shell-completion/zsh/_systemd-run b/shell-completion/zsh/_systemd-run
index 4bb864da21..9ee5897178 100644
--- a/shell-completion/zsh/_systemd-run
+++ b/shell-completion/zsh/_systemd-run
@@ -22,6 +22,13 @@ __systemctl() {
_describe 'slices' _slices
}
+(( $+functions[_systemd-run_job_modes] )) ||
+ _systemd-run_job_modes() {
+ local -a _modes
+ _modes=($( systemd-run --job-mode=help 2>/dev/null ))
+ _values "${_modes[@]}"
+ }
+
_arguments \
'(-G --collect)'{-G,--collect}'[Unload the transient unit after it completed]' \
'--description=[Description for unit]:description' \
@@ -60,6 +67,7 @@ _arguments \
'(-t --pty)'{-t,--pty}'[The service connects to the terminal]' \
'(-q --quiet)'{-q,--quiet}'[Suppresses additional informational output]' \
'--json=[Output as JSON]:JSON:(pretty short off)' \
+ '--job-mode=[Specify how to deal with other jobs]:mode:_systemd-run_job_modes' \
'(-r --remain-after-exit)'{-r,--remain-after-exit}'[Leave service around until explicitly stopped]' \
'(-d --same-dir)'{-d,--same-dir}'[Run on the current working directory]' \
'--scope[Run this as scope rather than service]' \
diff --git a/src/run/run.c b/src/run/run.c
index af28d60858..68966ccbda 100644
--- a/src/run/run.c
+++ b/src/run/run.c
@@ -40,6 +40,7 @@
#include "ptyfwd.h"
#include "signal-util.h"
#include "special.h"
+#include "string-table.h"
#include "strv.h"
#include "terminal-util.h"
#include "uid-classification.h"
@@ -82,6 +83,7 @@ static bool arg_quiet = false;
static bool arg_aggressive_gc = false;
static char *arg_working_directory = NULL;
static bool arg_shell = false;
+static JobMode arg_job_mode = JOB_FAIL;
static char **arg_cmdline = NULL;
static char *arg_exec_path = NULL;
static bool arg_ignore_failure = false;
@@ -143,6 +145,8 @@ static int help(void) {
" --json=pretty|short|off Print unit name and invocation id as JSON\n"
" -G --collect Unload unit after it ran, even when failed\n"
" -S --shell Invoke a $SHELL interactively\n"
+ " --job-mode=MODE Specify how to deal with already queued jobs,\n"
+ " when queueing a new job\n"
" --ignore-failure Ignore the exit status of the invoked process\n"
" --background=COLOR Set ANSI color for background\n"
"\n%3$sPath options:%4$s\n"
@@ -278,6 +282,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_WAIT,
ARG_WORKING_DIRECTORY,
ARG_SHELL,
+ ARG_JOB_MODE,
ARG_IGNORE_FAILURE,
ARG_BACKGROUND,
ARG_JSON,
@@ -327,6 +332,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "working-directory", required_argument, NULL, ARG_WORKING_DIRECTORY },
{ "same-dir", no_argument, NULL, 'd' },
{ "shell", no_argument, NULL, 'S' },
+ { "job-mode", required_argument, NULL, ARG_JOB_MODE },
{ "ignore-failure", no_argument, NULL, ARG_IGNORE_FAILURE },
{ "background", required_argument, NULL, ARG_BACKGROUND },
{ "json", required_argument, NULL, ARG_JSON },
@@ -621,6 +627,17 @@ static int parse_argv(int argc, char *argv[]) {
arg_shell = true;
break;
+ case ARG_JOB_MODE:
+ if (streq(optarg, "help"))
+ return DUMP_STRING_TABLE(job_mode, JobMode, _JOB_MODE_MAX);
+
+ r = job_mode_from_string(optarg);
+ if (r < 0)
+ return log_error_errno(r, "Invalid job mode: %s", optarg);
+
+ arg_job_mode = r;
+ break;
+
case ARG_IGNORE_FAILURE:
arg_ignore_failure = true;
break;
@@ -1768,7 +1785,7 @@ static int make_transient_service_unit(
return bus_log_create_error(r);
/* Name and mode */
- r = sd_bus_message_append(m, "ss", service, "fail");
+ r = sd_bus_message_append(m, "ss", service, job_mode_to_string(arg_job_mode));
if (r < 0)
return bus_log_create_error(r);
@@ -2283,7 +2300,7 @@ static int start_transient_scope(sd_bus *bus) {
return bus_log_create_error(r);
/* Name and Mode */
- r = sd_bus_message_append(m, "ss", scope, "fail");
+ r = sd_bus_message_append(m, "ss", scope, job_mode_to_string(arg_job_mode));
if (r < 0)
return bus_log_create_error(r);
@@ -2452,7 +2469,7 @@ static int make_transient_trigger_unit(
return bus_log_create_error(r);
/* Name and Mode */
- r = sd_bus_message_append(m, "ss", trigger, "fail");
+ r = sd_bus_message_append(m, "ss", trigger, job_mode_to_string(arg_job_mode));
if (r < 0)
return bus_log_create_error(r);
diff --git a/test/units/TEST-74-AUX-UTILS.run.sh b/test/units/TEST-74-AUX-UTILS.run.sh
index d47550c801..f624b00c89 100755
--- a/test/units/TEST-74-AUX-UTILS.run.sh
+++ b/test/units/TEST-74-AUX-UTILS.run.sh
@@ -200,6 +200,16 @@ grep -q "^SocketMode=0644$" "/run/systemd/transient/$UNIT.socket"
grep -qE "^ExecStart=.*/bin/true.*$" "/run/systemd/transient/$UNIT.service"
systemctl stop "$UNIT.socket" "$UNIT.service" || :
+: "Job mode"
+systemd-run --job-mode=help
+(! systemd-run --job-mode=foo --scope true)
+systemd-run --no-block --unit=slowly-activating.service --collect \
+ --service-type=oneshot --remain-after-exit \
+ sleep 30
+(! systemd-run --scope --property=Conflicts=slowly-activating.service true)
+(! systemd-run --scope --property=Conflicts=slowly-activating.service --job-mode=fail true)
+systemd-run --scope --property=Conflicts=slowly-activating.service --job-mode=replace true
+
: "Interactive options"
SHELL=/bin/true systemd-run --shell
SHELL=/bin/true systemd-run --scope --shell