]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
run: add --job-mode= argument 34708/head
authorGavin Li <gavin.li@samsara.com>
Thu, 10 Oct 2024 20:07:16 +0000 (16:07 -0400)
committerGavin Li <gavinli@thegavinli.com>
Thu, 23 Jan 2025 07:08:32 +0000 (02:08 -0500)
systemctl has a --job-mode= argument, and adding the same argument to
systemd-run is useful for starting transient scopes with dependencies.
For example, if a transient scope BindsTo a service that is stopping,
specifying --job-mode=replace will wait for the service to stop before
starting it again, while the default job mode of "fail" will cause the
systemd-run invocation to fail.

man/systemd-run.xml
shell-completion/bash/systemd-run
shell-completion/zsh/_systemd-run
src/run/run.c
test/units/TEST-74-AUX-UTILS.run.sh

index eeefe901dcfc55a412535014dcd00c30939cb052..a0924e30a26d95caad4e263212e574ed6125f96f 100644 (file)
         <xi:include href="version-info.xml" xpointer="v236"/></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--job-mode=<replaceable>MODE</replaceable></option></term>
+
+        <listitem>
+          <para>When queuing a new job, this option controls how to deal with
+          already queued jobs.</para>
+
+          <para>The option takes the same mode values as
+          <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
+          <option>--job-mode=</option> option. The default job mode is <literal>fail</literal>.</para>
+
+          <para>Running <option>--job-mode=help</option> shows a list of available job modes.</para>
+
+          <xi:include href="version-info.xml" xpointer="v258"/>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>--ignore-failure</option></term>
 
index 4537211ae55a0e0ae11c4fddb126e2dfe72faf96..4524744bb5fff683207b3b10d96875ee6cb7cc5d 100644 (file)
@@ -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") )
index 4bb864da219dc67d96985235db3b3028969805b5..9ee589717806b67bbb3adde07ba9fe31e198bed2 100644 (file)
@@ -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]' \
index af28d60858adccabe9b3bc6288ecf5f3371e33a2..68966ccbda29d0b06104b4127bce78d783c799d0 100644 (file)
@@ -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);
 
index d47550c8016f83cf0dc6fe529795c54aa74503c7..f624b00c89cd0bd53186fc13ff6e25a399a26ce1 100755 (executable)
@@ -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