File 0001-test.patch of Package systemd

From 2f8fd71fa2546296f2210d75899c3c891ea85243 Mon Sep 17 00:00:00 2001
From: Antonio Alvarez Feijoo <antonio.feijoo@suse.com>
Date: Wed, 3 Dec 2025 15:06:32 +0100
Subject: [PATCH] test

---
 man/systemctl.xml                         | 37 ++++++-------
 shell-completion/bash/systemctl.in        |  2 +-
 src/shared/install.c                      | 67 +++++++++++++++++++++--
 src/shared/install.h                      |  2 +
 src/systemctl/systemctl-list-unit-files.c |  1 +
 src/systemctl/systemctl-show.c            | 19 ++++++-
 src/systemctl/systemctl.c                 | 11 ++--
 7 files changed, 105 insertions(+), 34 deletions(-)

diff --git a/man/systemctl.xml b/man/systemctl.xml
index eae6442f58..7914a520cc 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -997,18 +997,17 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
           <term><command>preset <replaceable>UNIT</replaceable>…</command></term>
 
           <listitem>
-            <para>Reset the enable/disable status of one or more unit files, as specified on
-            the command line, to the defaults configured in the preset policy files. This
-            has the same effect as <command>disable</command> or
-            <command>enable</command>, depending how the unit is listed in the preset
+            <para>Reset the enable/disable/mask status of one or more unit files, as specified on the command line, to
+            the defaults configured in the preset policy files. This has the same effect as <command>disable</command>,
+            <command>enable</command>, or <command>mask</command>, depending how the unit is listed in the preset
             files.</para>
 
-            <para>Use <option>--preset-mode=</option> to control whether units shall be
-            enabled and disabled, or only enabled, or only disabled.</para>
+            <para>Use <option>--preset-mode=</option> to control whether units shall be enabled, disabled, and masked,
+            or only enabled, or only disabled, or only masked.</para>
 
-            <para>If the unit carries no install information, it will be silently ignored
-            by this command. <replaceable>UNIT</replaceable> must be the real unit name,
-            any alias names are ignored silently.</para>
+            <para>If the unit carries no install information, it will be silently ignored by this command for the
+            enable/disable directives. <replaceable>UNIT</replaceable> must be the real unit name, any alias names are
+            ignored silently.</para>
 
             <para>For more information on the preset policy format, see
             <citerefentry><refentrytitle>systemd.preset</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
@@ -1022,12 +1021,11 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
           <term><command>preset-all</command></term>
 
           <listitem>
-            <para>Resets all installed unit files to the defaults
-            configured in the preset policy file (see above).</para>
+            <para>Resets all installed unit files to the defaults configured in the preset policy file (see above).
+            </para>
 
-            <para>Use <option>--preset-mode=</option> to control
-            whether units shall be enabled and disabled, or only
-            enabled, or only disabled.</para>
+            <para>Use <option>--preset-mode=</option> to control whether units shall be enabled, disabled, and masked,
+            or only enabled, or only disabled, or only masked.</para>
 
             <xi:include href="version-info.xml" xpointer="v215"/>
           </listitem>
@@ -2680,13 +2678,10 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
         <term><option>--preset-mode=</option></term>
 
         <listitem>
-          <para>Takes one of <literal>full</literal> (the default),
-          <literal>enable-only</literal>,
-          <literal>disable-only</literal>. When used with the
-          <command>preset</command> or <command>preset-all</command>
-          commands, controls whether units shall be disabled and
-          enabled according to the preset rules, or only enabled, or
-          only disabled.</para>
+          <para>Takes one of <literal>full</literal> (the default), <literal>enable-only</literal>,
+          <literal>disable-only</literal>, <literal>mask-only</literal>. When used with the <command>preset</command>
+          or <command>preset-all</command> commands, controls whether units shall be disabled, enabled, and masked
+          according to the preset rules, or only enabled, or only disabled, or only masked.</para>
 
           <xi:include href="version-info.xml" xpointer="v215"/>
         </listitem>
diff --git a/shell-completion/bash/systemctl.in b/shell-completion/bash/systemctl.in
index cbca727cee..60ba21cb41 100644
--- a/shell-completion/bash/systemctl.in
+++ b/shell-completion/bash/systemctl.in
@@ -178,7 +178,7 @@ _systemctl () {
                 comps=$(__systemd_properties)
                 ;;
             --preset-mode)
-                comps='full enable-only disable-only'
+                comps='full enable-only disable-only mask-only'
                 ;;
             --output|-o)
                 comps=$( systemctl --output=help 2>/dev/null )
diff --git a/src/shared/install.c b/src/shared/install.c
index 8195436564..20f7fb6ad7 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -60,6 +60,7 @@ static const char *const preset_action_past_tense_table[_PRESET_ACTION_MAX] = {
         [PRESET_UNKNOWN] = "unknown",
         [PRESET_ENABLE]  = "enabled",
         [PRESET_DISABLE] = "disabled",
+        [PRESET_MASK]    = "masked",
         [PRESET_IGNORE]  = "ignored",
 };
 
@@ -3392,6 +3393,18 @@ static int read_presets(RuntimeScope scope, const char *root_dir, UnitFilePreset
                                         .action = PRESET_DISABLE,
                                 };
 
+                        } else if ((parameter = first_word(line, "mask"))) {
+                                char *pattern;
+
+                                pattern = strdup(parameter);
+                                if (!pattern)
+                                        return -ENOMEM;
+
+                                rule = (UnitFilePresetRule) {
+                                        .pattern = pattern,
+                                        .action = PRESET_MASK,
+                                };
+
                         } else if ((parameter = first_word(line, "ignore"))) {
                                 char *pattern;
 
@@ -3510,6 +3523,10 @@ static int query_presets(const char *name, const UnitFilePresets *presets, char
                 log_debug("Preset files say disable %s.", name);
                 return PRESET_DISABLE;
 
+        case PRESET_MASK:
+                log_debug("Preset files say mask %s.", name);
+                return PRESET_MASK;
+
         case PRESET_IGNORE:
                 log_debug("Preset files say ignore %s.", name);
                 return PRESET_IGNORE;
@@ -3538,6 +3555,7 @@ static int execute_preset(
                 UnitFileFlags file_flags,
                 InstallContext *plus,
                 InstallContext *minus,
+                char * const *masks,
                 const LookupPaths *lp,
                 const char *config_path,
                 char * const *files,
@@ -3552,7 +3570,24 @@ static int execute_preset(
         assert(lp);
         assert(config_path);
 
-        if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) {
+        if (!IN_SET(mode, UNIT_FILE_PRESET_ENABLE_ONLY, UNIT_FILE_PRESET_DISABLE_ONLY))
+                STRV_FOREACH(name, masks) {
+                        _cleanup_free_ char *path = NULL;
+
+                        path = path_make_absolute(*name, config_path);
+                        if (!path)
+                                return -ENOMEM;
+
+                        RET_GATHER(r, create_symlink(
+                                        lp,
+                                        "/dev/null",
+                                        path,
+                                        file_flags & UNIT_FILE_FORCE,
+                                        changes,
+                                        n_changes));
+                }
+
+        if (!IN_SET(mode, UNIT_FILE_PRESET_ENABLE_ONLY, UNIT_FILE_PRESET_MASK_ONLY)) {
                 _cleanup_set_free_ Set *remove_symlinks_to = NULL;
 
                 r = install_context_mark_for_removal(minus, lp, &remove_symlinks_to, config_path, changes, n_changes);
@@ -3563,7 +3598,7 @@ static int execute_preset(
         } else
                 r = 0;
 
-        if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) {
+        if (!IN_SET(mode, UNIT_FILE_PRESET_DISABLE_ONLY, UNIT_FILE_PRESET_MASK_ONLY)) {
                 int q;
 
                 /* Returns number of symlinks that where supposed to be installed. */
@@ -3586,6 +3621,7 @@ static int preset_prepare_one(
                 RuntimeScope scope,
                 InstallContext *plus,
                 InstallContext *minus,
+                char ***masks,
                 LookupPaths *lp,
                 const char *name,
                 const UnitFilePresets *presets,
@@ -3632,6 +3668,13 @@ static int preset_prepare_one(
                 r = install_info_discover(minus, lp, name, SEARCH_FOLLOW_CONFIG_SYMLINKS,
                                           &info, changes, n_changes);
 
+        else if (r == PRESET_MASK) {
+                if (!unit_name_is_valid(name, UNIT_NAME_ANY))
+                        return -EINVAL;
+
+                r = strv_extend(masks, name);
+        }
+
         return r;
 }
 
@@ -3645,6 +3688,7 @@ int unit_file_preset(
                 size_t *n_changes) {
 
         _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
+        _cleanup_strv_free_ char **masks = NULL;
         _cleanup_(lookup_paths_done) LookupPaths lp = {};
         _cleanup_(unit_file_presets_done) UnitFilePresets presets = {};
         const char *config_path;
@@ -3667,12 +3711,12 @@ int unit_file_preset(
                 return r;
 
         STRV_FOREACH(name, names) {
-                r = preset_prepare_one(scope, &plus, &minus, &lp, *name, &presets, changes, n_changes);
+                r = preset_prepare_one(scope, &plus, &minus, &masks, &lp, *name, &presets, changes, n_changes);
                 if (r < 0)
                         return r;
         }
 
-        return execute_preset(file_flags, &plus, &minus, &lp, config_path, names, mode, changes, n_changes);
+        return execute_preset(file_flags, &plus, &minus, masks, &lp, config_path, names, mode, changes, n_changes);
 }
 
 int unit_file_preset_all(
@@ -3684,6 +3728,7 @@ int unit_file_preset_all(
                 size_t *n_changes) {
 
         _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
+        _cleanup_strv_free_ char **masks = NULL;
         _cleanup_(lookup_paths_done) LookupPaths lp = {};
         _cleanup_(unit_file_presets_done) UnitFilePresets presets = {};
         const char *config_path = NULL;
@@ -3725,7 +3770,16 @@ int unit_file_preset_all(
                         if (!IN_SET(de->d_type, DT_LNK, DT_REG))
                                 continue;
 
-                        k = preset_prepare_one(scope, &plus, &minus, &lp, de->d_name, &presets, changes, n_changes);
+                        k = preset_prepare_one(
+                                        scope,
+                                        &plus,
+                                        &minus,
+                                        &masks,
+                                        &lp,
+                                        de->d_name,
+                                        &presets,
+                                        changes,
+                                        n_changes);
                         if (k < 0 &&
                             !IN_SET(k, -EEXIST,
                                        -ERFKILL,
@@ -3745,7 +3799,7 @@ int unit_file_preset_all(
                 }
         }
 
-        return execute_preset(file_flags, &plus, &minus, &lp, config_path, NULL, mode, changes, n_changes);
+        return execute_preset(file_flags, &plus, &minus, masks, &lp, config_path, NULL, mode, changes, n_changes);
 }
 
 static UnitFileList* unit_file_list_free(UnitFileList *f) {
@@ -3882,6 +3936,7 @@ static const char* const unit_file_preset_mode_table[_UNIT_FILE_PRESET_MODE_MAX]
         [UNIT_FILE_PRESET_FULL]         = "full",
         [UNIT_FILE_PRESET_ENABLE_ONLY]  = "enable-only",
         [UNIT_FILE_PRESET_DISABLE_ONLY] = "disable-only",
+        [UNIT_FILE_PRESET_MASK_ONLY]    = "mask-only",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode, UnitFilePresetMode);
diff --git a/src/shared/install.h b/src/shared/install.h
index 53753a0366..99ad286f6e 100644
--- a/src/shared/install.h
+++ b/src/shared/install.h
@@ -9,6 +9,7 @@ typedef enum UnitFilePresetMode {
         UNIT_FILE_PRESET_FULL,
         UNIT_FILE_PRESET_ENABLE_ONLY,
         UNIT_FILE_PRESET_DISABLE_ONLY,
+        UNIT_FILE_PRESET_MASK_ONLY,
         _UNIT_FILE_PRESET_MODE_MAX,
         _UNIT_FILE_PRESET_MODE_INVALID = -EINVAL,
 } UnitFilePresetMode;
@@ -218,6 +219,7 @@ typedef enum PresetAction {
         PRESET_UNKNOWN,
         PRESET_ENABLE,
         PRESET_DISABLE,
+        PRESET_MASK,
         PRESET_IGNORE,
         _PRESET_ACTION_MAX,
         _PRESET_ACTION_INVALID = -EINVAL,
diff --git a/src/systemctl/systemctl-list-unit-files.c b/src/systemctl/systemctl-list-unit-files.c
index 548b2573fc..a8443a3b9b 100644
--- a/src/systemctl/systemctl-list-unit-files.c
+++ b/src/systemctl/systemctl-list-unit-files.c
@@ -86,6 +86,7 @@ static const char* preset_action_to_color(PresetAction action, bool underline) {
         case PRESET_ENABLE:
                 return underline ? ansi_highlight_green_underline() : ansi_highlight_green();
         case PRESET_DISABLE:
+        case PRESET_MASK:
                 return underline ? ansi_highlight_red_underline() : ansi_highlight_red();
         case PRESET_IGNORE:
                 return underline ? ansi_highlight_yellow_underline() : ansi_highlight_yellow();
diff --git a/src/systemctl/systemctl-show.c b/src/systemctl/systemctl-show.c
index 245ffdde09..124b03c29c 100644
--- a/src/systemctl/systemctl-show.c
+++ b/src/systemctl/systemctl-show.c
@@ -348,6 +348,23 @@ static void format_enable_state(const char *enable_state, const char **enable_on
                 *enable_on = *enable_off = "";
 }
 
+static void format_preset_state(const char *preset_state, const char **preset_on, const char **preset_off) {
+        assert(preset_on);
+        assert(preset_off);
+
+        if (streq_ptr(preset_state, "masked")) {
+                *preset_on = ansi_highlight_red();
+                *preset_off = ansi_normal();
+        } else if (streq_ptr(preset_state, "disabled")) {
+                *preset_on = ansi_highlight_yellow();
+                *preset_off = ansi_normal();
+        } else if (streq_ptr(preset_state, "enabled")) {
+                *preset_on = ansi_highlight_green();
+                *preset_off = ansi_normal();
+        } else
+                *preset_on = *preset_off = "";
+}
+
 static void print_exec_directory_quota(UnitStatusInfo *i, ExecDirectoryType dt) {
         assert(i);
 
@@ -383,7 +400,7 @@ static void print_status_info(
 
         format_active_state(i->active_state, &active_on, &active_off);
         format_enable_state(i->unit_file_state, &enable_on, &enable_off);
-        format_enable_state(i->unit_file_preset, &preset_on, &preset_off);
+        format_preset_state(i->unit_file_preset, &preset_on, &preset_off);
 
         const Glyph icon = unit_active_state_to_glyph(unit_active_state_from_string(i->active_state));
 
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 01b5517d14..355f9317cb 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -169,10 +169,10 @@ static int systemctl_help(void) {
                "  enable [UNIT...|PATH...]            Enable one or more unit files\n"
                "  disable UNIT...                     Disable one or more unit files\n"
                "  reenable UNIT...                    Reenable one or more unit files\n"
-               "  preset UNIT...                      Enable/disable one or more unit files\n"
-               "                                      based on preset configuration\n"
-               "  preset-all                          Enable/disable all unit files based on\n"
-               "                                      preset configuration\n"
+               "  preset UNIT...                      Enable/disable/mask one or more unit\n"
+               "                                      files based on preset configuration\n"
+               "  preset-all                          Enable/disable/mask all unit files based\n"
+               "                                      on preset configuration\n"
                "  is-enabled UNIT...                  Check whether unit files are enabled\n"
                "  mask UNIT...                        Mask one or more units\n"
                "  unmask UNIT...                      Unmask one or more units\n"
@@ -285,7 +285,8 @@ static int systemctl_help(void) {
                "                         next reboot\n"
                "  -f --force             When enabling unit files, override existing symlinks\n"
                "                         When shutting down, execute action immediately\n"
-               "     --preset-mode=      Apply only enable, only disable, or all presets\n"
+               "     --preset-mode=      Apply only enable, only disable, only mask, or all\n"
+               "                         presets\n"
                "     --root=PATH         Edit/enable/disable/mask unit files in the specified\n"
                "                         root directory\n"
                "     --image=PATH        Edit/enable/disable/mask unit files in the specified\n"
-- 
2.51.0

openSUSE Build Service is sponsored by