mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +03:00
preset: Add ignore directive
The ignore directive specifies to not do anything with the given unit and leave existing configuration intact. This allows distributions to gradually adopt preset files by shipping a ignore * preset file.
This commit is contained in:
parent
6e4ec79a3c
commit
e77e07f601
@ -62,23 +62,23 @@
|
||||
<refsect1>
|
||||
<title>Preset File Format</title>
|
||||
|
||||
<para>The preset files contain a list of directives consisting of
|
||||
either the word <literal>enable</literal> or
|
||||
<literal>disable</literal> followed by a space and a unit name
|
||||
(possibly with shell style wildcards), separated by newlines.
|
||||
Empty lines and lines whose first non-whitespace character is <literal>#</literal> or
|
||||
<literal>;</literal> are ignored. Multiple instance names for unit
|
||||
templates may be specified as a space separated list at the end of
|
||||
the line instead of the customary position between <literal>@</literal>
|
||||
and the unit suffix.</para>
|
||||
<para>The preset files contain a list of directives, one per line. Empty lines and lines whose first
|
||||
non-whitespace character is <literal>#</literal> or <literal>;</literal> are ignored. Each directive
|
||||
consists of one of the words <literal>enable</literal>, <literal>disable</literal>, or
|
||||
<literal>ignore</literal>, followed by whitespace and a unit name. The unit name may contain shell-style
|
||||
wildcards.</para>
|
||||
|
||||
<para>For the enable directive for template units, one or more instance names may be specified as a
|
||||
space-separated list after the unit name. In this case, those instances will be enabled instead of the
|
||||
instance specified via DefaultInstance= in the unit.</para>
|
||||
|
||||
<para>Presets must refer to the "real" unit file, and not to any aliases. See
|
||||
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
for a description of unit aliasing.</para>
|
||||
|
||||
<para>Two different directives are understood:
|
||||
<literal>enable</literal> may be used to enable units by default,
|
||||
<literal>disable</literal> to disable units by default.</para>
|
||||
<para>Three different directives are understood: <literal>enable</literal> may be used to enable units by
|
||||
default, <literal>disable</literal> to disable units by default, and <literal>ignore</literal> to ignore
|
||||
units and leave existing configuration intact.</para>
|
||||
|
||||
<para>If multiple lines apply to a unit name, the first matching
|
||||
one takes precedence over all others.</para>
|
||||
|
@ -235,9 +235,7 @@ static int property_get_unit_file_preset(
|
||||
|
||||
r = unit_get_unit_file_preset(u);
|
||||
|
||||
return sd_bus_message_append(reply, "s",
|
||||
r < 0 ? NULL:
|
||||
r > 0 ? "enabled" : "disabled");
|
||||
return sd_bus_message_append(reply, "s", preset_action_past_tense_to_string(r));
|
||||
}
|
||||
|
||||
static int property_get_job(
|
||||
|
@ -4094,7 +4094,7 @@ UnitFileState unit_get_unit_file_state(Unit *u) {
|
||||
return u->unit_file_state;
|
||||
}
|
||||
|
||||
int unit_get_unit_file_preset(Unit *u) {
|
||||
PresetAction unit_get_unit_file_preset(Unit *u) {
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "bpf-program.h"
|
||||
#include "condition.h"
|
||||
#include "emergency-action.h"
|
||||
#include "install.h"
|
||||
#include "list.h"
|
||||
#include "show-status.h"
|
||||
#include "set.h"
|
||||
@ -358,7 +359,7 @@ typedef struct Unit {
|
||||
|
||||
/* Cached unit file state and preset */
|
||||
UnitFileState unit_file_state;
|
||||
int unit_file_preset;
|
||||
PresetAction unit_file_preset;
|
||||
|
||||
/* Where the cpu.stat or cpuacct.usage was at the time the unit was started */
|
||||
nsec_t cpu_usage_base;
|
||||
@ -954,7 +955,7 @@ void unit_start_on_failure(Unit *u, const char *dependency_name, UnitDependencyA
|
||||
void unit_trigger_notify(Unit *u);
|
||||
|
||||
UnitFileState unit_get_unit_file_state(Unit *u);
|
||||
int unit_get_unit_file_preset(Unit *u);
|
||||
PresetAction unit_get_unit_file_preset(Unit *u);
|
||||
|
||||
Unit* unit_ref_set(UnitRef *ref, Unit *source, Unit *target);
|
||||
void unit_ref_unset(UnitRef *ref);
|
||||
|
@ -52,18 +52,22 @@ typedef struct {
|
||||
OrderedHashmap *have_processed;
|
||||
} InstallContext;
|
||||
|
||||
typedef enum {
|
||||
PRESET_UNKNOWN,
|
||||
PRESET_ENABLE,
|
||||
PRESET_DISABLE,
|
||||
} PresetAction;
|
||||
|
||||
struct UnitFilePresetRule {
|
||||
char *pattern;
|
||||
PresetAction action;
|
||||
char **instances;
|
||||
};
|
||||
|
||||
/* NB! strings use past tense. */
|
||||
static const char *const preset_action_past_tense_table[_PRESET_ACTION_MAX] = {
|
||||
[PRESET_UNKNOWN] = "unknown",
|
||||
[PRESET_ENABLE] = "enabled",
|
||||
[PRESET_DISABLE] = "disabled",
|
||||
[PRESET_IGNORE] = "ignored",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(preset_action_past_tense, PresetAction);
|
||||
|
||||
static bool install_info_has_rules(const InstallInfo *i) {
|
||||
assert(i);
|
||||
|
||||
@ -3297,6 +3301,20 @@ static int read_presets(RuntimeScope scope, const char *root_dir, UnitFilePreset
|
||||
};
|
||||
}
|
||||
|
||||
parameter = first_word(l, "ignore");
|
||||
if (parameter) {
|
||||
char *pattern;
|
||||
|
||||
pattern = strdup(parameter);
|
||||
if (!pattern)
|
||||
return -ENOMEM;
|
||||
|
||||
rule = (UnitFilePresetRule) {
|
||||
.pattern = pattern,
|
||||
.action = PRESET_IGNORE,
|
||||
};
|
||||
}
|
||||
|
||||
if (rule.action) {
|
||||
if (!GREEDY_REALLOC(ps.rules, ps.n_rules + 1))
|
||||
return -ENOMEM;
|
||||
@ -3382,23 +3400,26 @@ static int query_presets(const char *name, const UnitFilePresets *presets, char
|
||||
switch (action) {
|
||||
case PRESET_UNKNOWN:
|
||||
log_debug("Preset files don't specify rule for %s. Enabling.", name);
|
||||
return 1;
|
||||
return PRESET_ENABLE;
|
||||
case PRESET_ENABLE:
|
||||
if (instance_name_list && *instance_name_list)
|
||||
STRV_FOREACH(s, *instance_name_list)
|
||||
log_debug("Preset files say enable %s.", *s);
|
||||
else
|
||||
log_debug("Preset files say enable %s.", name);
|
||||
return 1;
|
||||
return PRESET_ENABLE;
|
||||
case PRESET_DISABLE:
|
||||
log_debug("Preset files say disable %s.", name);
|
||||
return 0;
|
||||
return PRESET_DISABLE;
|
||||
case PRESET_IGNORE:
|
||||
log_debug("Preset files say ignore %s.", name);
|
||||
return PRESET_IGNORE;
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
int unit_file_query_preset(RuntimeScope scope, const char *root_dir, const char *name, UnitFilePresets *cached) {
|
||||
PresetAction unit_file_query_preset(RuntimeScope scope, const char *root_dir, const char *name, UnitFilePresets *cached) {
|
||||
_cleanup_(unit_file_presets_done) UnitFilePresets tmp = {};
|
||||
int r;
|
||||
|
||||
@ -3492,7 +3513,7 @@ static int preset_prepare_one(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (r > 0) {
|
||||
if (r == PRESET_ENABLE) {
|
||||
if (instance_name_list)
|
||||
STRV_FOREACH(s, instance_name_list) {
|
||||
r = install_info_discover_and_check(plus, lp, *s, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
|
||||
@ -3507,7 +3528,7 @@ static int preset_prepare_one(
|
||||
return r;
|
||||
}
|
||||
|
||||
} else
|
||||
} else if (r == PRESET_DISABLE)
|
||||
r = install_info_discover(minus, lp, name, SEARCH_FOLLOW_CONFIG_SYMLINKS,
|
||||
&info, changes, n_changes);
|
||||
|
||||
|
@ -217,8 +217,20 @@ typedef struct {
|
||||
bool initialized;
|
||||
} UnitFilePresets;
|
||||
|
||||
typedef enum PresetAction {
|
||||
PRESET_UNKNOWN,
|
||||
PRESET_ENABLE,
|
||||
PRESET_DISABLE,
|
||||
PRESET_IGNORE,
|
||||
_PRESET_ACTION_MAX,
|
||||
_PRESET_ACTION_INVALID = -EINVAL,
|
||||
_PRESET_ACTION_ERRNO_MAX = -ERRNO_MAX, /* Ensure this type covers the whole negative errno range */
|
||||
} PresetAction;
|
||||
|
||||
const char *preset_action_past_tense_to_string(PresetAction action);
|
||||
|
||||
void unit_file_presets_done(UnitFilePresets *p);
|
||||
int unit_file_query_preset(RuntimeScope scope, const char *root_dir, const char *name, UnitFilePresets *cached);
|
||||
PresetAction unit_file_query_preset(RuntimeScope scope, const char *root_dir, const char *name, UnitFilePresets *cached);
|
||||
|
||||
const char *unit_file_state_to_string(UnitFileState s) _const_;
|
||||
UnitFileState unit_file_state_from_string(const char *s) _pure_;
|
||||
|
@ -49,6 +49,21 @@ static bool output_show_unit_file(const UnitFileList *u, char **states, char **p
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char* preset_action_to_color(PresetAction action, bool underline) {
|
||||
assert(action >= 0);
|
||||
|
||||
switch (action) {
|
||||
case PRESET_ENABLE:
|
||||
return underline ? ansi_highlight_green_underline() : ansi_highlight_green();
|
||||
case PRESET_DISABLE:
|
||||
return underline ? ansi_highlight_red_underline() : ansi_highlight_red();
|
||||
case PRESET_IGNORE:
|
||||
return underline ? ansi_highlight_yellow_underline() : ansi_highlight_yellow();
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int output_unit_file_list(const UnitFileList *units, unsigned c) {
|
||||
_cleanup_(table_unrefp) Table *table = NULL;
|
||||
_cleanup_(unit_file_presets_done) UnitFilePresets presets = {};
|
||||
@ -98,22 +113,14 @@ static int output_unit_file_list(const UnitFileList *units, unsigned c) {
|
||||
return table_log_add_error(r);
|
||||
|
||||
if (show_preset_for_state(u->state)) {
|
||||
const char *unit_preset_str, *on_preset_color;
|
||||
const char *on_preset_color = underline ? on_underline : ansi_normal();
|
||||
|
||||
r = unit_file_query_preset(arg_runtime_scope, arg_root, id, &presets);
|
||||
if (r < 0) {
|
||||
unit_preset_str = "n/a";
|
||||
on_preset_color = underline ? on_underline : ansi_normal();
|
||||
} else if (r == 0) {
|
||||
unit_preset_str = "disabled";
|
||||
on_preset_color = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
|
||||
} else {
|
||||
unit_preset_str = "enabled";
|
||||
on_preset_color = underline ? ansi_highlight_green_underline() : ansi_highlight_green();
|
||||
}
|
||||
if (r >= 0)
|
||||
on_preset_color = preset_action_to_color(r, underline);
|
||||
|
||||
r = table_add_many(table,
|
||||
TABLE_STRING, unit_preset_str,
|
||||
TABLE_STRING, strna(preset_action_past_tense_to_string(r)),
|
||||
TABLE_SET_BOTH_COLORS, strempty(on_preset_color));
|
||||
} else
|
||||
r = table_add_many(table,
|
||||
|
@ -580,8 +580,11 @@ TEST(preset_and_list) {
|
||||
UnitFileList *fl;
|
||||
_cleanup_(hashmap_freep) Hashmap *h = NULL;
|
||||
|
||||
CLEANUP_ARRAY(changes, n_changes, install_changes_free);
|
||||
|
||||
assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "preset-yes.service", &state) == -ENOENT);
|
||||
assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "preset-no.service", &state) == -ENOENT);
|
||||
assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "preset-ignore.service", &state) == -ENOENT);
|
||||
|
||||
p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service");
|
||||
assert_se(write_string_file(p,
|
||||
@ -593,13 +596,20 @@ TEST(preset_and_list) {
|
||||
"[Install]\n"
|
||||
"WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
|
||||
|
||||
p = strjoina(root, "/usr/lib/systemd/system/preset-ignore.service");
|
||||
assert_se(write_string_file(p,
|
||||
"[Install]\n"
|
||||
"WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
|
||||
|
||||
p = strjoina(root, "/usr/lib/systemd/system-preset/test.preset");
|
||||
assert_se(write_string_file(p,
|
||||
"enable *-yes.*\n"
|
||||
"ignore *-ignore.*\n"
|
||||
"disable *\n", WRITE_STRING_FILE_CREATE) >= 0);
|
||||
|
||||
assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
|
||||
assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
|
||||
assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "preset-ignore.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
|
||||
|
||||
assert_se(unit_file_preset(RUNTIME_SCOPE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0);
|
||||
assert_se(n_changes == 1);
|
||||
@ -612,6 +622,7 @@ TEST(preset_and_list) {
|
||||
|
||||
assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
|
||||
assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
|
||||
assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "preset-ignore.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
|
||||
|
||||
assert_se(unit_file_disable(RUNTIME_SCOPE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), &changes, &n_changes) >= 0);
|
||||
assert_se(n_changes == 1);
|
||||
@ -623,6 +634,7 @@ TEST(preset_and_list) {
|
||||
|
||||
assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
|
||||
assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
|
||||
assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "preset-ignore.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
|
||||
|
||||
assert_se(unit_file_preset(RUNTIME_SCOPE_SYSTEM, 0, root, STRV_MAKE("preset-no.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0);
|
||||
assert_se(n_changes == 0);
|
||||
@ -631,6 +643,7 @@ TEST(preset_and_list) {
|
||||
|
||||
assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
|
||||
assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
|
||||
assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "preset-ignore.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
|
||||
|
||||
assert_se(unit_file_preset_all(RUNTIME_SCOPE_SYSTEM, 0, root, UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0);
|
||||
|
||||
@ -652,6 +665,7 @@ TEST(preset_and_list) {
|
||||
|
||||
assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
|
||||
assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
|
||||
assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "preset-ignore.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
|
||||
|
||||
assert_se(h = hashmap_new(&unit_file_list_hash_ops_free));
|
||||
assert_se(unit_file_get_list(RUNTIME_SCOPE_SYSTEM, root, h, NULL, NULL) >= 0);
|
||||
@ -674,6 +688,10 @@ TEST(preset_and_list) {
|
||||
}
|
||||
|
||||
assert_se(got_yes && got_no);
|
||||
|
||||
assert_se(unit_file_enable(RUNTIME_SCOPE_SYSTEM, 0, root, STRV_MAKE("preset-ignore.service"), &changes, &n_changes) >= 0);
|
||||
assert_se(unit_file_preset(RUNTIME_SCOPE_SYSTEM, 0, root, STRV_MAKE("preset-ignore.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0);
|
||||
assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "preset-ignore.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
|
||||
}
|
||||
|
||||
TEST(revert) {
|
||||
|
Loading…
Reference in New Issue
Block a user