Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,22 @@ fun getAllAIGeneratedValidators(): Map<Validator, OptionValueInformation> {
Validator("config_parse_socket_service", "0") to ConfigParseSocketServiceOptionValue() as OptionValueInformation,
Validator("config_parse_service_sockets", "0") to ConfigParseServiceSocketsOptionValue() as OptionValueInformation,

// Batch 2026-10: exec
Validator("config_parse_bind_paths", "0") to ConfigParseBindPathsOptionValue() as OptionValueInformation,
Validator("config_parse_temporary_filesystems", "0") to ConfigParseTemporaryFilesystemsOptionValue() as OptionValueInformation,
Validator("config_parse_root_image_options", "0") to ConfigParseRootImageOptionsOptionValue() as OptionValueInformation,
Validator("config_parse_numa_mask", "0") to ConfigParseNumaMaskOptionValue() as OptionValueInformation,
Validator("config_parse_mount_images", "0") to ConfigParseMountImagesOptionValue() as OptionValueInformation,
Validator("config_parse_import_credential", "0") to ConfigParseImportCredentialOptionValue() as OptionValueInformation,
Validator("config_parse_extension_images", "0") to ConfigParseExtensionImagesOptionValue() as OptionValueInformation,
Validator("config_parse_exec_root_hash_sig", "0") to ConfigParseExecRootHashSigOptionValue() as OptionValueInformation,
Validator("config_parse_exec_root_hash", "0") to ConfigParseExecRootHashOptionValue() as OptionValueInformation,
Validator("config_parse_exec_input_data", "0") to ConfigParseExecInputDataOptionValue() as OptionValueInformation,
Validator("config_parse_exec_coredump_filter", "0") to ConfigParseExecCoredumpFilterOptionValue() as OptionValueInformation,
Validator("config_parse_environ", "0") to ConfigParseEnvironOptionValue() as OptionValueInformation,
Validator("config_parse_concurrency_max", "0") to ConfigParseConcurrencyMaxOptionValue() as OptionValueInformation,
Validator("config_parse_luo_sessions", "0") to ConfigParseLuoSessionsOptionValue() as OptionValueInformation,

)

return allValidators
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai

import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.COLON
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.FlexibleLiteralChoiceTerminal
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.RETAINED_ABSOLUTE_PATH_FIELD
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.RETAINED_OPTIONAL_ABSOLUTE_PATH_FIELD
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.SequenceCombinator
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.ZeroOrOne
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.whitespaceList

/*
* [Service]/[Socket]/[Mount]/[Swap] BindPaths= / BindReadOnlyPaths=.
*
* man https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#BindPaths=
* parser https://github.com/systemd/systemd/blob/0f0682b773/src/core/load-fragment.c#L5187-L5305 config_parse_bind_paths (0)
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/basic/extract-word.c#L10 extract_first_word (UNQUOTE|RETAIN_ESCAPE, then ':' with CUNESCAPE|UNESCAPE_SEPARATORS|DONT_COALESCE_SEPARATORS)
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/basic/extract-word.c#L240 extract_many_words_internal (4 slots: a 4th field is "Too many parameters")
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/basic/escape.c#L104 cunescape_one
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/core/unit-printf.c#L253 unit_path_printf (specifiers)
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/shared/parse-helpers.c#L34 path_simplify_and_warn (PATH_CHECK_ABSOLUTE)
* tests https://github.com/systemd/systemd/blob/0f0682b773/src/test/test-load-fragment.c#L459 TEST(config_parse_bind_paths)
* tests https://github.com/systemd/systemd/blob/0f0682b773/test/test-execute/exec-bindpaths.service#L27-L30
*/

/**
* Validator for `BindPaths=` and `BindReadOnlyPaths=` (config_parse_bind_paths, ltype 0; the only
* difference between the two keys is `strstr(lvalue, "ReadOnly")`).
*
* A whitespace-separated list of `[-]SOURCE[:DESTINATION[:OPTIONS]]` tuples:
* - SOURCE and DESTINATION are absolute paths after specifier expansion (so `%t/foo` is fine) with no
* `..` component; only SOURCE may carry the `-` "ignore if missing" prefix.
* - OPTIONS is `rbind`, `norbind`, or empty (`/a:/b:` is accepted — `isempty(options)` means rbind).
* - fields are split with EXTRACT_DONT_COALESCE_SEPARATORS, so an empty field is a field: `/a:` and
* `/a::rbind` have an empty, non-absolute destination and are rejected; a fourth field is too many.
* - a ':' inside a path is written `\:`; other backslashes must be valid C escapes.
*
* Every rejected tuple is logged by systemd and skipped ("…, ignoring"). Lenient corners: quoted runs
* are opaque (see BatchExecCombinators.kt), and `%` specifiers are not checked.
*/
class ConfigParseBindPathsOptionValue : SimpleGrammarOptionValues(
"config_parse_bind_paths",
whitespaceList(
SequenceCombinator(
RETAINED_OPTIONAL_ABSOLUTE_PATH_FIELD,
ZeroOrOne(
SequenceCombinator(
COLON,
RETAINED_ABSOLUTE_PATH_FIELD,
ZeroOrOne(SequenceCombinator(COLON, ZeroOrOne(FlexibleLiteralChoiceTerminal("rbind", "norbind")))),
)
),
)
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai

import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.AlternativeCombinator
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.EOF
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.FlexibleLiteralChoiceTerminal
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.SafeAtoTerminal
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.SequenceCombinator

/*
* [Slice] ConcurrencyHardMax= / ConcurrencySoftMax= / ActivatingConcurrencyMax=.
*
* man https://www.freedesktop.org/software/systemd/man/latest/systemd.slice.html#ConcurrencyHardMax=
* man https://www.freedesktop.org/software/systemd/man/latest/systemd.slice.html#ActivatingConcurrencyMax=
* parser https://github.com/systemd/systemd/blob/0f0682b773/src/core/load-fragment.c#L6091-L6111 config_parse_concurrency_max (0)
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/shared/conf-parser.c#L966 config_parse_unsigned → safe_atou
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/basic/parse-util.c#L429 safe_atou_full (base 0, plus mangle_base 0b/0o at L403)
*/

/**
* Validator for the [Slice] concurrency limits (config_parse_concurrency_max, ltype 0):
* `ConcurrencyHardMax=`, `ConcurrencySoftMax=` and `ActivatingConcurrencyMax=`.
*
* `infinity` (exact, streq), or an unsigned int as safe_atou() reads it (see [SafeAtoTerminal]), up to
* UINT_MAX (4294967295). The value is the whole (stripped) setting, so whitespace can still reach the parser:
* `0b 1` and a leading `\v` are accepted, as are `0b+1`, `0b-0`, a negative zero such as `-0`, and `+`-signed
* numbers (but not `+0b1`/`-0b0`, which mangle_base misses). `0` is legal (it blocks all activation).
*/
class ConfigParseConcurrencyMaxOptionValue : SimpleGrammarOptionValues(
"config_parse_concurrency_max",
SequenceCombinator(
AlternativeCombinator(
FlexibleLiteralChoiceTerminal("infinity"),
SafeAtoTerminal(
signed = false,
base = 0,
flags = emptySet(),
minInclusive = 0L,
maxInclusive = 4_294_967_295L,
acceptsWhitespace = true,
acceptsMinus = true,
),
),
EOF(),
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai

import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.AlternativeCombinator
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.C_ESCAPE_BODY
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.LiteralChoiceTerminal
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.RegexTerminal
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.SequenceCombinator
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.ZeroOrOne
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.whitespaceList

/*
* [Service]/[Socket]/[Mount]/[Swap] Environment=.
*
* man https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#Environment=
* parser https://github.com/systemd/systemd/blob/0f0682b773/src/core/load-fragment.c#L2763-L2834 config_parse_environ (0)
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/basic/extract-word.c#L10 extract_first_word (EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE)
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/basic/escape.c#L104 cunescape_one (an unknown escape is -EINVAL: the rest of the line is ignored)
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/core/unit-printf.c#L265 unit_env_printf (specifiers)
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/basic/env-util.c#L81 env_assignment_is_valid
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/basic/env-util.c#L31 env_name_is_valid_n (ASCII letters, digits, '_'; not starting with a digit)
* tests https://github.com/systemd/systemd/blob/0f0682b773/test/test-execute/exec-environment.service#L8
* tests https://github.com/systemd/systemd/blob/0f0682b773/test/test-execute/exec-unsetenvironment.service#L10
* linux https://man7.org/linux/man-pages/man7/environ.7.html
*/

// One raw chunk of a word: a double- or single-quoted run, a C escape, or an ordinary character.
// Inside quotes a backslash is an escape too (EXTRACT_CUNESCAPE applies there as well).
private const val QUOTED_SYNTAX = """"(?:[^"\\]|\\[\s\S])*"|'(?:[^'\\]|\\[\s\S])*'"""
private const val QUOTED_SEMANTIC = """"(?:[^"\\]|\\$C_ESCAPE_BODY)*"|'(?:[^'\\]|\\$C_ESCAPE_BODY)*'"""
private const val WORD_SYNTAX = """(?:$QUOTED_SYNTAX|\\\S|[^\s"'\\])+"""
private const val WORD_SEMANTIC = """(?:$QUOTED_SEMANTIC|\\$C_ESCAPE_BODY|[^\s"'\\])+"""

// A specifier stands in for name characters; which specifier, and what it expands to, is not checked.
private const val NAME_SPECIFIER = """%[^\s="'\\]"""

// The plain form NAME=VALUE, where NAME has no quotes or backslashes in it. The name may contain
// specifiers (systemd's own test-execute uses `X%b=%U`).
private val ENV_NAME = RegexTerminal(
"""[^\s="'\\]+""",
"""(?:[A-Za-z_]|$NAME_SPECIFIER)(?:[A-Za-z0-9_]|$NAME_SPECIFIER)*(?![^\s="'\\])""",
)
private val ENV_VALUE = RegexTerminal(WORD_SYNTAX, "$WORD_SEMANTIC(?!\\S)")

// Any word with a quote or backslash before its first '=' — the documented `"NAME=value with spaces"`
// form above all. The assignment only exists after unquoting, so this is one token: the lookahead
// requires that, skipping quotes, the word starts with a valid name followed by '='. Disjoint from the
// plain form (whose name may not contain a quote), so the two never both claim a word.
private val QUOTED_ENV_ASSIGNMENT = RegexTerminal(
"""(?=[^\s="'\\]*["'\\])$WORD_SYNTAX""",
"""(?=["']*(?:[A-Za-z_]|$NAME_SPECIFIER|\\\S)(?:["']|[A-Za-z0-9_]|$NAME_SPECIFIER|\\\S)*=)$WORD_SEMANTIC(?!\S)""",
)

/**
* Validator for `Environment=` (config_parse_environ, ltype 0).
*
* A whitespace-separated list of `NAME=VALUE` assignments, each unquoted (`"VAR1=word1 word2"`,
* `VAR="a b"`) and C-unescaped before it is checked. NAME is ASCII letters, digits and `_`, not
* starting with a digit; VALUE may be empty (`FOO=`) and may contain anything, including further `=`.
* A word without `=` (e.g. the stray `production` in `UNICORN_OPTS=-E production`) is logged and
* skipped. An unbalanced quote or an unknown escape such as `\q` makes systemd drop the rest of the line.
*
* The man page says non-printable characters in values are rejected; env_value_is_valid() at
* 0f0682b773 only requires valid UTF-8, so control characters (e.g. `\t`) are accepted, following the C.
*
* Lenient corners: `%` specifiers are not checked, and in a word that is quoted before its `=` the name
* is only checked roughly (quotes inside it are skipped over).
*/
class ConfigParseEnvironOptionValue : SimpleGrammarOptionValues(
"config_parse_environ",
whitespaceList(
AlternativeCombinator(
SequenceCombinator(ENV_NAME, LiteralChoiceTerminal("="), ZeroOrOne(ENV_VALUE)),
QUOTED_ENV_ASSIGNMENT,
)
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai

import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.AlternativeCombinator
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.FlexibleLiteralChoiceTerminal
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.RegexTerminal
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.whitespaceList

/*
* [Service]/[Socket]/[Mount]/[Swap] CoredumpFilter=.
*
* man https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#CoredumpFilter=
* parser https://github.com/systemd/systemd/blob/0f0682b773/src/core/load-fragment.c#L802-L838 config_parse_exec_coredump_filter (0)
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/shared/coredump-util.c#L38-L81 coredump_filter_mask_from_string (words split on WHITESPACE, flags 0)
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/shared/coredump-util.c#L24-L34 coredump_filter_table
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/basic/parse-util.h#L95 safe_atoux64 (base 16)
* tests https://github.com/systemd/systemd/blob/0f0682b773/src/test/test-coredump-util.c#L26-L70 TEST(coredump_filter_mask_from_string)
* linux https://man7.org/linux/man-pages/man5/core.5.html
*/

// A raw mask: strtoull(…, 16) — an optional 0x prefix, at most 16 significant hex digits (uint64_t).
// strtoull also takes a sign: '+' is fine, and '-' is only refused when the value is non-zero, so "-0"
// and "-0x00" are accepted (safe_atollu_full: `l != 0 && s[0] == '-'`).
// The trailing lookahead keeps this from matching a hex-looking prefix of a longer word (the "de" of
// "default"), so it and the names never claim the same word.
private val COREDUMP_FILTER_MASK = RegexTerminal(
"""[+-]?[0-9a-fA-FxX]+(?![a-zA-Z0-9-])""",
"""(?:\+?(?:0[xX])?0*[0-9a-fA-F]{1,16}|-(?:0[xX])?0+)(?![a-zA-Z0-9-])""",
)

/**
* Validator for `CoredumpFilter=` (config_parse_exec_coredump_filter, ltype 0).
*
* A whitespace-separated list of mapping-type names (`private-anonymous`, `shared-anonymous`,
* `private-file-backed`, `shared-file-backed`, `elf-headers`, `private-huge`, `shared-huge`,
* `private-dax`, `shared-dax`), the specials `default` and `all`, or raw masks, which are always
* hexadecimal (`11` is 0x11; `0x1101` is fine) and must fit 64 bits. Names are matched exactly
* (streq / string table, case-sensitive). One bad word makes systemd ignore the whole assignment.
*/
class ConfigParseExecCoredumpFilterOptionValue : SimpleGrammarOptionValues(
"config_parse_exec_coredump_filter",
whitespaceList(
AlternativeCombinator(
COREDUMP_FILTER_MASK,
FlexibleLiteralChoiceTerminal(
"default", "all",
"private-anonymous", "shared-anonymous", "private-file-backed", "shared-file-backed",
"elf-headers", "private-huge", "shared-huge", "private-dax", "shared-dax",
),
)
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai

import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.EOF
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.NON_EMPTY_BASE64_DATA
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.SequenceCombinator

/*
* [Service]/[Socket]/[Mount]/[Swap] StandardInputData=.
*
* man https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#StandardInputData=
* parser https://github.com/systemd/systemd/blob/0f0682b773/src/core/load-fragment.c#L1271-L1327 config_parse_exec_input_data (0)
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/basic/hexdecoct.c#L755 unbase64mem_full
* leaf https://github.com/systemd/systemd/blob/0f0682b773/src/basic/hexdecoct.c#L528 unbase64char (standard and URL-safe alphabets)
*/

/**
* Validator for `StandardInputData=` (config_parse_exec_input_data, ltype 0).
*
* Base64 as unbase64mem() decodes it: whitespace anywhere is ignored (so a value continued over several
* lines with a trailing `\` works), standard (`+/`) or URL-safe (`-_`) alphabet, complete 4-character
* groups, `=` padding only in the last group and only where the discarded bits are zero. No escapes or
* specifiers are resolved. The 64 MiB cumulative cap (EXEC_STDIN_DATA_MAX) is not checked.
*/
class ConfigParseExecInputDataOptionValue : SimpleGrammarOptionValues(
"config_parse_exec_input_data",
SequenceCombinator(NON_EMPTY_BASE64_DATA, EOF())
)
Loading
Loading