Skip to content
Open
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 @@ -10,11 +10,21 @@ import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.gram
* in src/shared/parse-helpers.c:90. Accepts:
* - "none" (clears the set, sets allowlist)
* - optional leading "~" (invert / denylist mode), followed by a whitespace-separated list
* of address family names from af_from_name (AF_UNIX, AF_INET, AF_INET6, AF_NETLINK,
* AF_PACKET, …)
* of address family names resolved by af_from_name
*
* The grammar matches the "AF_" prefix loosely (any uppercase/digit/underscore tail); unknown
* names slip past the grammar but fail at runtime. This is the same tradeoff as syscall_errno.
* The name set is the list of AF_* macros systemd's af_from_name knows about, which is
* generated (src/basic/generate-af-list.sh) from the AF_* #defines in <sys/socket.h>, minus
* AF_UNSPEC and AF_MAX. It can be reproduced by preprocessing <sys/socket.h> with
* `cpp -dM`, keeping the `#define AF_*` lines (dropping AF_UNSPEC/AF_MAX), and taking the macro
* names.
*
* Enumerating the names exactly (rather than the old loose RegexTerminal("AF_[A-Z0-9_]+"))
* makes validation correct (AF_BOGUS is now rejected) and sets up grammar-based completion.
*
* Note: some of these names still resolve via af_from_name (the macro exists in libc headers)
* even though the kernel removed the protocol — AF_DECnet (Linux 6.1), AF_IRDA (4.17),
* AF_ECONET (3.5), AF_WANPIPE (2.6.21). These are valid-but-removed and are intended targets
* of a future deprecation annotator (see GitHub #467 / address_families(7)).
*/
class ConfigParseAddressFamiliesOptionValue : SimpleGrammarOptionValues(
"config_parse_address_families",
Expand All @@ -23,13 +33,71 @@ class ConfigParseAddressFamiliesOptionValue : SimpleGrammarOptionValues(
LiteralChoiceTerminal("none"),
SequenceCombinator(
ZeroOrOne(LiteralChoiceTerminal("~")),
RegexTerminal("AF_[A-Z0-9_]+", "AF_[A-Z0-9_]+"),
ADDRESS_FAMILY,
ZeroOrMore(SequenceCombinator(
WhitespaceTerminal(),
RegexTerminal("AF_[A-Z0-9_]+", "AF_[A-Z0-9_]+")
ADDRESS_FAMILY
))
)
),
EOF()
)
)
) {
companion object {
/**
* The AF_* names systemd's af_from_name accepts. FlexibleLiteralChoiceTerminal matches
* loosely for syntax (so coloring / error localization still work) but requires an exact
* choice to be semantically valid.
*/
private val ADDRESS_FAMILY = FlexibleLiteralChoiceTerminal(
"AF_ALG",
"AF_APPLETALK",
"AF_ASH",
"AF_ATMPVC",
"AF_ATMSVC",
"AF_AX25",
"AF_BLUETOOTH",
"AF_BRIDGE",
"AF_CAIF",
"AF_CAN",
"AF_DECnet",
"AF_ECONET",
"AF_FILE",
"AF_IB",
"AF_IEEE802154",
"AF_INET",
"AF_INET6",
"AF_IPX",
"AF_IRDA",
"AF_ISDN",
"AF_IUCV",
"AF_KCM",
"AF_KEY",
"AF_LLC",
"AF_LOCAL",
"AF_MCTP",
"AF_MPLS",
"AF_NETBEUI",
"AF_NETLINK",
"AF_NETROM",
"AF_NFC",
"AF_PACKET",
"AF_PHONET",
"AF_PPPOX",
"AF_QIPCRTR",
"AF_RDS",
"AF_ROSE",
"AF_ROUTE",
"AF_RXRPC",
"AF_SECURITY",
"AF_SMC",
"AF_SNA",
"AF_TIPC",
"AF_UNIX",
"AF_VSOCK",
"AF_WANPIPE",
"AF_X25",
"AF_XDP"
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,27 @@ class ConfigParseAddressFamiliesOptionValueTest : AbstractUnitFileTest() {
assertSize(0, highlights)
}

@Test
fun testValidEnumeratedFamilies() {
// Names that the previous loose RegexTerminal happened to accept but that we now want to
// keep accepting: an alias (AF_LOCAL), a mixed-case real name (AF_DECnet), the newest
// families, and a long whitespace-separated list including the inversion prefix.
// language="unit file (systemd)"
val file = """
[Service]
RestrictAddressFamilies=AF_LOCAL
RestrictAddressFamilies=AF_DECnet
RestrictAddressFamilies=AF_VSOCK AF_XDP AF_MCTP
RestrictAddressFamilies=~AF_UNIX AF_INET AF_INET6 AF_NETLINK AF_PACKET
""".trimIndent()

setupFileInEditor("file.service", file)
enableInspection(InvalidValueInspection::class.java)
val highlights = myFixture.doHighlighting()

assertSize(0, highlights)
}

@Test
fun testInvalidValues() {
// language="unit file (systemd)"
Expand All @@ -45,4 +66,27 @@ class ConfigParseAddressFamiliesOptionValueTest : AbstractUnitFileTest() {

assertSize(5, highlights)
}

@Test
fun testUnknownFamiliesAreNowRejected() {
// Regression guard for the grammar fix: the old RegexTerminal("AF_[A-Z0-9_]+") accepted
// any AF_-prefixed token, so these passed validation incorrectly. With the enumerated
// family set they must be flagged (syntactically well-formed, semantically invalid).
// Raw values (no <error> markup) so the guard does not depend on markup stripping; each
// invalid property contributes exactly one highlight.
// language="unit file (systemd)"
val file = """
[Service]
RestrictAddressFamilies=AF_BOGUS
RestrictAddressFamilies=AF_INETZ
RestrictAddressFamilies=AF_INET AF_MADEUP
RestrictAddressFamilies=AF_DECNET
""".trimIndent()

setupFileInEditor("file.service", file)
enableInspection(InvalidValueInspection::class.java)
val highlights = myFixture.doHighlighting()

assertSize(4, highlights)
}
}
Loading