summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/net/sunrpc/xdrgen/README2
-rw-r--r--tools/net/sunrpc/xdrgen/generators/__init__.py5
-rw-r--r--tools/net/sunrpc/xdrgen/generators/enum.py9
-rw-r--r--tools/net/sunrpc/xdrgen/generators/passthru.py26
-rw-r--r--tools/net/sunrpc/xdrgen/generators/program.py38
-rw-r--r--tools/net/sunrpc/xdrgen/generators/typedef.py8
-rw-r--r--tools/net/sunrpc/xdrgen/generators/union.py115
-rw-r--r--tools/net/sunrpc/xdrgen/grammars/xdr.lark10
-rw-r--r--tools/net/sunrpc/xdrgen/subcmds/declarations.py28
-rw-r--r--tools/net/sunrpc/xdrgen/subcmds/definitions.py31
-rw-r--r--tools/net/sunrpc/xdrgen/subcmds/lint.py25
-rw-r--r--tools/net/sunrpc/xdrgen/subcmds/source.py51
-rw-r--r--tools/net/sunrpc/xdrgen/templates/C/enum/declaration/enum.j21
-rw-r--r--tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum.j211
-rw-r--r--tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum_be.j220
-rw-r--r--tools/net/sunrpc/xdrgen/templates/C/enum/definition/close.j21
-rw-r--r--tools/net/sunrpc/xdrgen/templates/C/enum/definition/close_be.j21
-rw-r--r--tools/net/sunrpc/xdrgen/templates/C/passthru/definition.j23
-rw-r--r--tools/net/sunrpc/xdrgen/templates/C/passthru/source.j23
-rw-r--r--tools/net/sunrpc/xdrgen/templates/C/program/decoder/argument.j24
-rw-r--r--tools/net/sunrpc/xdrgen/templates/C/program/definition/program.j25
-rw-r--r--tools/net/sunrpc/xdrgen/templates/C/program/encoder/result.j26
-rw-r--r--tools/net/sunrpc/xdrgen/templates/C/program/maxsize/max_args.j23
-rw-r--r--tools/net/sunrpc/xdrgen/templates/C/source_top/client.j21
-rw-r--r--tools/net/sunrpc/xdrgen/templates/C/union/decoder/bool_spec.j27
-rw-r--r--tools/net/sunrpc/xdrgen/templates/C/union/definition/close.j21
-rw-r--r--tools/net/sunrpc/xdrgen/templates/C/union/encoder/bool_spec.j27
-rw-r--r--tools/net/sunrpc/xdrgen/xdr_ast.py49
-rw-r--r--tools/net/sunrpc/xdrgen/xdr_parse.py138
-rwxr-xr-xtools/net/sunrpc/xdrgen/xdrgen8
30 files changed, 526 insertions, 91 deletions
diff --git a/tools/net/sunrpc/xdrgen/README b/tools/net/sunrpc/xdrgen/README
index 27218a78ab40..2cf05d1e4cd9 100644
--- a/tools/net/sunrpc/xdrgen/README
+++ b/tools/net/sunrpc/xdrgen/README
@@ -250,8 +250,6 @@ Add more pragma directives:
Enable something like a #include to dynamically insert the content
of other specification files
-Properly support line-by-line pass-through via the "%" decorator
-
Build a unit test suite for verifying translation of XDR language
into compilable code
diff --git a/tools/net/sunrpc/xdrgen/generators/__init__.py b/tools/net/sunrpc/xdrgen/generators/__init__.py
index e22632cf38fb..5c3a4a47ded8 100644
--- a/tools/net/sunrpc/xdrgen/generators/__init__.py
+++ b/tools/net/sunrpc/xdrgen/generators/__init__.py
@@ -6,7 +6,7 @@ from pathlib import Path
from jinja2 import Environment, FileSystemLoader, Template
from xdr_ast import _XdrAst, Specification, _RpcProgram, _XdrTypeSpecifier
-from xdr_ast import public_apis, pass_by_reference, get_header_name
+from xdr_ast import public_apis, pass_by_reference, structs, get_header_name
from xdr_parse import get_xdr_annotate
@@ -25,6 +25,7 @@ def create_jinja2_environment(language: str, xdr_type: str) -> Environment:
environment.globals["annotate"] = get_xdr_annotate()
environment.globals["public_apis"] = public_apis
environment.globals["pass_by_reference"] = pass_by_reference
+ environment.globals["structs"] = structs
return environment
case _:
raise NotImplementedError("Language not supported")
@@ -58,6 +59,8 @@ def kernel_c_type(spec: _XdrTypeSpecifier) -> str:
"""Return name of C type"""
builtin_native_c_type = {
"bool": "bool",
+ "short": "s16",
+ "unsigned_short": "u16",
"int": "s32",
"unsigned_int": "u32",
"long": "s32",
diff --git a/tools/net/sunrpc/xdrgen/generators/enum.py b/tools/net/sunrpc/xdrgen/generators/enum.py
index e62f715d3996..b4ed3ed6431e 100644
--- a/tools/net/sunrpc/xdrgen/generators/enum.py
+++ b/tools/net/sunrpc/xdrgen/generators/enum.py
@@ -5,6 +5,7 @@
from generators import SourceGenerator, create_jinja2_environment
from xdr_ast import _XdrEnum, public_apis, big_endian, get_header_name
+from xdr_parse import get_xdr_enum_validation
class XdrEnumGenerator(SourceGenerator):
@@ -42,7 +43,13 @@ class XdrEnumGenerator(SourceGenerator):
template = self.environment.get_template("decoder/enum_be.j2")
else:
template = self.environment.get_template("decoder/enum.j2")
- print(template.render(name=node.name))
+ print(
+ template.render(
+ name=node.name,
+ enumerators=node.enumerators,
+ validate=get_xdr_enum_validation(),
+ )
+ )
def emit_encoder(self, node: _XdrEnum) -> None:
"""Emit one encoder function for an XDR enum type"""
diff --git a/tools/net/sunrpc/xdrgen/generators/passthru.py b/tools/net/sunrpc/xdrgen/generators/passthru.py
new file mode 100644
index 000000000000..cb17bd977f1e
--- /dev/null
+++ b/tools/net/sunrpc/xdrgen/generators/passthru.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python3
+# ex: set filetype=python:
+
+"""Generate code for XDR pass-through lines"""
+
+from generators import SourceGenerator, create_jinja2_environment
+from xdr_ast import _XdrPassthru
+
+
+class XdrPassthruGenerator(SourceGenerator):
+ """Generate source code for XDR pass-through content"""
+
+ def __init__(self, language: str, peer: str):
+ """Initialize an instance of this class"""
+ self.environment = create_jinja2_environment(language, "passthru")
+ self.peer = peer
+
+ def emit_definition(self, node: _XdrPassthru) -> None:
+ """Emit one pass-through line"""
+ template = self.environment.get_template("definition.j2")
+ print(template.render(content=node.content))
+
+ def emit_decoder(self, node: _XdrPassthru) -> None:
+ """Emit one pass-through line"""
+ template = self.environment.get_template("source.j2")
+ print(template.render(content=node.content))
diff --git a/tools/net/sunrpc/xdrgen/generators/program.py b/tools/net/sunrpc/xdrgen/generators/program.py
index ac3cf1694b68..c0cb3f6d3319 100644
--- a/tools/net/sunrpc/xdrgen/generators/program.py
+++ b/tools/net/sunrpc/xdrgen/generators/program.py
@@ -5,8 +5,9 @@
from jinja2 import Environment
-from generators import SourceGenerator, create_jinja2_environment
+from generators import SourceGenerator, create_jinja2_environment, get_jinja2_template
from xdr_ast import _RpcProgram, _RpcVersion, excluded_apis
+from xdr_ast import max_widths, get_header_name
def emit_version_definitions(
@@ -127,6 +128,9 @@ class XdrProgramGenerator(SourceGenerator):
for version in node.versions:
emit_version_definitions(self.environment, program, version)
+ template = self.environment.get_template("definition/program.j2")
+ print(template.render(name=raw_name, value=node.number))
+
def emit_declaration(self, node: _RpcProgram) -> None:
"""Emit a declaration pair for each of an RPC programs's procedures"""
raw_name = node.name
@@ -166,3 +170,35 @@ class XdrProgramGenerator(SourceGenerator):
emit_version_argument_encoders(
self.environment, program, version,
)
+
+ def emit_maxsize(self, node: _RpcProgram) -> None:
+ """Emit maxsize macro for maximum RPC argument size"""
+ header = get_header_name().upper()
+
+ # Find the largest argument across all versions
+ max_arg_width = 0
+ max_arg_name = None
+ for version in node.versions:
+ for procedure in version.procedures:
+ if procedure.name in excluded_apis:
+ continue
+ arg_name = procedure.argument.type_name
+ if arg_name == "void":
+ continue
+ if arg_name not in max_widths:
+ continue
+ if max_widths[arg_name] > max_arg_width:
+ max_arg_width = max_widths[arg_name]
+ max_arg_name = arg_name
+
+ if max_arg_name is None:
+ return
+
+ macro_name = header + "_MAX_ARGS_SZ"
+ template = get_jinja2_template(self.environment, "maxsize", "max_args")
+ print(
+ template.render(
+ macro=macro_name,
+ width=header + "_" + max_arg_name + "_sz",
+ )
+ )
diff --git a/tools/net/sunrpc/xdrgen/generators/typedef.py b/tools/net/sunrpc/xdrgen/generators/typedef.py
index fab72e9d6915..75e3a40e14e1 100644
--- a/tools/net/sunrpc/xdrgen/generators/typedef.py
+++ b/tools/net/sunrpc/xdrgen/generators/typedef.py
@@ -58,7 +58,7 @@ def emit_typedef_declaration(environment: Environment, node: _XdrDeclaration) ->
elif isinstance(node, _XdrOptionalData):
raise NotImplementedError("<optional_data> typedef not yet implemented")
elif isinstance(node, _XdrVoid):
- raise NotImplementedError("<void> typedef not yet implemented")
+ raise ValueError("invalid void usage in RPC Specification")
else:
raise NotImplementedError("typedef: type not recognized")
@@ -104,7 +104,7 @@ def emit_type_definition(environment: Environment, node: _XdrDeclaration) -> Non
elif isinstance(node, _XdrOptionalData):
raise NotImplementedError("<optional_data> typedef not yet implemented")
elif isinstance(node, _XdrVoid):
- raise NotImplementedError("<void> typedef not yet implemented")
+ raise ValueError("invalid void usage in RPC Specification")
else:
raise NotImplementedError("typedef: type not recognized")
@@ -165,7 +165,7 @@ def emit_typedef_decoder(environment: Environment, node: _XdrDeclaration) -> Non
elif isinstance(node, _XdrOptionalData):
raise NotImplementedError("<optional_data> typedef not yet implemented")
elif isinstance(node, _XdrVoid):
- raise NotImplementedError("<void> typedef not yet implemented")
+ raise ValueError("invalid void usage in RPC Specification")
else:
raise NotImplementedError("typedef: type not recognized")
@@ -225,7 +225,7 @@ def emit_typedef_encoder(environment: Environment, node: _XdrDeclaration) -> Non
elif isinstance(node, _XdrOptionalData):
raise NotImplementedError("<optional_data> typedef not yet implemented")
elif isinstance(node, _XdrVoid):
- raise NotImplementedError("<void> typedef not yet implemented")
+ raise ValueError("invalid void usage in RPC Specification")
else:
raise NotImplementedError("typedef: type not recognized")
diff --git a/tools/net/sunrpc/xdrgen/generators/union.py b/tools/net/sunrpc/xdrgen/generators/union.py
index ad1f214ef22a..d15837dae651 100644
--- a/tools/net/sunrpc/xdrgen/generators/union.py
+++ b/tools/net/sunrpc/xdrgen/generators/union.py
@@ -84,6 +84,31 @@ def emit_union_switch_spec_decoder(
print(template.render(name=node.name, type=node.spec.type_name))
+def emit_union_arm_decoder(
+ environment: Environment, node: _XdrCaseSpec
+) -> None:
+ """Emit decoder for an XDR union's arm (data only, no case/break)"""
+
+ if isinstance(node.arm, _XdrVoid):
+ return
+ if isinstance(node.arm, _XdrString):
+ type_name = "char *"
+ classifier = ""
+ else:
+ type_name = node.arm.spec.type_name
+ classifier = node.arm.spec.c_classifier
+
+ assert isinstance(node.arm, (_XdrBasic, _XdrString))
+ template = get_jinja2_template(environment, "decoder", node.arm.template)
+ print(
+ template.render(
+ name=node.arm.name,
+ type=type_name,
+ classifier=classifier,
+ )
+ )
+
+
def emit_union_case_spec_decoder(
environment: Environment, node: _XdrCaseSpec, big_endian_discriminant: bool
) -> None:
@@ -151,19 +176,33 @@ def emit_union_decoder(environment: Environment, node: _XdrUnion) -> None:
template = get_jinja2_template(environment, "decoder", "open")
print(template.render(name=node.name))
- emit_union_switch_spec_decoder(environment, node.discriminant)
+ # For boolean discriminants, use if statement instead of switch
+ if node.discriminant.spec.type_name == "bool":
+ template = get_jinja2_template(environment, "decoder", "bool_spec")
+ print(template.render(name=node.discriminant.name, type=node.discriminant.spec.type_name))
- for case in node.cases:
- emit_union_case_spec_decoder(
- environment,
- case,
- node.discriminant.spec.type_name in big_endian,
- )
+ # Find and emit the TRUE case
+ for case in node.cases:
+ if case.values and case.values[0] == "TRUE":
+ emit_union_arm_decoder(environment, case)
+ break
- emit_union_default_spec_decoder(environment, node)
+ template = get_jinja2_template(environment, "decoder", "close")
+ print(template.render())
+ else:
+ emit_union_switch_spec_decoder(environment, node.discriminant)
- template = get_jinja2_template(environment, "decoder", "close")
- print(template.render())
+ for case in node.cases:
+ emit_union_case_spec_decoder(
+ environment,
+ case,
+ node.discriminant.spec.type_name in big_endian,
+ )
+
+ emit_union_default_spec_decoder(environment, node)
+
+ template = get_jinja2_template(environment, "decoder", "close")
+ print(template.render())
def emit_union_switch_spec_encoder(
@@ -175,6 +214,28 @@ def emit_union_switch_spec_encoder(
print(template.render(name=node.name, type=node.spec.type_name))
+def emit_union_arm_encoder(
+ environment: Environment, node: _XdrCaseSpec
+) -> None:
+ """Emit encoder for an XDR union's arm (data only, no case/break)"""
+
+ if isinstance(node.arm, _XdrVoid):
+ return
+ if isinstance(node.arm, _XdrString):
+ type_name = "char *"
+ else:
+ type_name = node.arm.spec.type_name
+
+ assert isinstance(node.arm, (_XdrBasic, _XdrString))
+ template = get_jinja2_template(environment, "encoder", node.arm.template)
+ print(
+ template.render(
+ name=node.arm.name,
+ type=type_name,
+ )
+ )
+
+
def emit_union_case_spec_encoder(
environment: Environment, node: _XdrCaseSpec, big_endian_discriminant: bool
) -> None:
@@ -235,19 +296,33 @@ def emit_union_encoder(environment, node: _XdrUnion) -> None:
template = get_jinja2_template(environment, "encoder", "open")
print(template.render(name=node.name))
- emit_union_switch_spec_encoder(environment, node.discriminant)
+ # For boolean discriminants, use if statement instead of switch
+ if node.discriminant.spec.type_name == "bool":
+ template = get_jinja2_template(environment, "encoder", "bool_spec")
+ print(template.render(name=node.discriminant.name, type=node.discriminant.spec.type_name))
- for case in node.cases:
- emit_union_case_spec_encoder(
- environment,
- case,
- node.discriminant.spec.type_name in big_endian,
- )
+ # Find and emit the TRUE case
+ for case in node.cases:
+ if case.values and case.values[0] == "TRUE":
+ emit_union_arm_encoder(environment, case)
+ break
- emit_union_default_spec_encoder(environment, node)
+ template = get_jinja2_template(environment, "encoder", "close")
+ print(template.render())
+ else:
+ emit_union_switch_spec_encoder(environment, node.discriminant)
- template = get_jinja2_template(environment, "encoder", "close")
- print(template.render())
+ for case in node.cases:
+ emit_union_case_spec_encoder(
+ environment,
+ case,
+ node.discriminant.spec.type_name in big_endian,
+ )
+
+ emit_union_default_spec_encoder(environment, node)
+
+ template = get_jinja2_template(environment, "encoder", "close")
+ print(template.render())
def emit_union_maxsize(environment: Environment, node: _XdrUnion) -> None:
diff --git a/tools/net/sunrpc/xdrgen/grammars/xdr.lark b/tools/net/sunrpc/xdrgen/grammars/xdr.lark
index 7c2c1b8c86d1..1d2afff98ac5 100644
--- a/tools/net/sunrpc/xdrgen/grammars/xdr.lark
+++ b/tools/net/sunrpc/xdrgen/grammars/xdr.lark
@@ -20,9 +20,11 @@ constant : decimal_constant | hexadecimal_constant | octal_consta
type_specifier : unsigned_hyper
| unsigned_long
| unsigned_int
+ | unsigned_short
| hyper
| long
| int
+ | short
| float
| double
| quadruple
@@ -35,9 +37,11 @@ type_specifier : unsigned_hyper
unsigned_hyper : "unsigned" "hyper"
unsigned_long : "unsigned" "long"
unsigned_int : "unsigned" "int"
+unsigned_short : "unsigned" "short"
hyper : "hyper"
long : "long"
int : "int"
+short : "short"
float : "float"
double : "double"
quadruple : "quadruple"
@@ -74,6 +78,9 @@ definition : constant_def
| type_def
| program_def
| pragma_def
+ | passthru_def
+
+passthru_def : PASSTHRU
//
// RPC program definitions not specified in RFC 4506
@@ -111,8 +118,7 @@ decimal_constant : /[\+-]?(0|[1-9][0-9]*)/
hexadecimal_constant : /0x([a-f]|[A-F]|[0-9])+/
octal_constant : /0[0-7]+/
-PASSTHRU : "%" | "%" /.+/
-%ignore PASSTHRU
+PASSTHRU : /%.*/
%import common.C_COMMENT
%ignore C_COMMENT
diff --git a/tools/net/sunrpc/xdrgen/subcmds/declarations.py b/tools/net/sunrpc/xdrgen/subcmds/declarations.py
index c5e8d79986ef..ed83d48d1f68 100644
--- a/tools/net/sunrpc/xdrgen/subcmds/declarations.py
+++ b/tools/net/sunrpc/xdrgen/subcmds/declarations.py
@@ -8,9 +8,8 @@ import logging
from argparse import Namespace
from lark import logger
-from lark.exceptions import UnexpectedInput
+from lark.exceptions import VisitError
-from generators.constant import XdrConstantGenerator
from generators.enum import XdrEnumGenerator
from generators.header_bottom import XdrHeaderBottomGenerator
from generators.header_top import XdrHeaderTopGenerator
@@ -21,9 +20,10 @@ from generators.struct import XdrStructGenerator
from generators.union import XdrUnionGenerator
from xdr_ast import transform_parse_tree, _RpcProgram, Specification
-from xdr_ast import _XdrConstant, _XdrEnum, _XdrPointer
-from xdr_ast import _XdrTypedef, _XdrStruct, _XdrUnion
+from xdr_ast import _XdrEnum, _XdrPointer, _XdrTypedef, _XdrStruct, _XdrUnion
from xdr_parse import xdr_parser, set_xdr_annotate
+from xdr_parse import make_error_handler, XdrParseError
+from xdr_parse import handle_transform_error
logger.setLevel(logging.INFO)
@@ -50,20 +50,24 @@ def emit_header_declarations(
gen.emit_declaration(definition.value)
-def handle_parse_error(e: UnexpectedInput) -> bool:
- """Simple parse error reporting, no recovery attempted"""
- print(e)
- return True
-
-
def subcmd(args: Namespace) -> int:
"""Generate definitions and declarations"""
set_xdr_annotate(args.annotate)
parser = xdr_parser()
with open(args.filename, encoding="utf-8") as f:
- parse_tree = parser.parse(f.read(), on_error=handle_parse_error)
- ast = transform_parse_tree(parse_tree)
+ source = f.read()
+ try:
+ parse_tree = parser.parse(
+ source, on_error=make_error_handler(source, args.filename)
+ )
+ except XdrParseError:
+ return 1
+ try:
+ ast = transform_parse_tree(parse_tree)
+ except VisitError as e:
+ handle_transform_error(e, source, args.filename)
+ return 1
gen = XdrHeaderTopGenerator(args.language, args.peer)
gen.emit_declaration(args.filename, ast)
diff --git a/tools/net/sunrpc/xdrgen/subcmds/definitions.py b/tools/net/sunrpc/xdrgen/subcmds/definitions.py
index c956e27f37c0..a48ca0549382 100644
--- a/tools/net/sunrpc/xdrgen/subcmds/definitions.py
+++ b/tools/net/sunrpc/xdrgen/subcmds/definitions.py
@@ -8,12 +8,13 @@ import logging
from argparse import Namespace
from lark import logger
-from lark.exceptions import UnexpectedInput
+from lark.exceptions import VisitError
from generators.constant import XdrConstantGenerator
from generators.enum import XdrEnumGenerator
from generators.header_bottom import XdrHeaderBottomGenerator
from generators.header_top import XdrHeaderTopGenerator
+from generators.passthru import XdrPassthruGenerator
from generators.pointer import XdrPointerGenerator
from generators.program import XdrProgramGenerator
from generators.typedef import XdrTypedefGenerator
@@ -21,9 +22,11 @@ from generators.struct import XdrStructGenerator
from generators.union import XdrUnionGenerator
from xdr_ast import transform_parse_tree, Specification
-from xdr_ast import _RpcProgram, _XdrConstant, _XdrEnum, _XdrPointer
+from xdr_ast import _RpcProgram, _XdrConstant, _XdrEnum, _XdrPassthru, _XdrPointer
from xdr_ast import _XdrTypedef, _XdrStruct, _XdrUnion
from xdr_parse import xdr_parser, set_xdr_annotate
+from xdr_parse import make_error_handler, XdrParseError
+from xdr_parse import handle_transform_error
logger.setLevel(logging.INFO)
@@ -45,6 +48,8 @@ def emit_header_definitions(root: Specification, language: str, peer: str) -> No
gen = XdrStructGenerator(language, peer)
elif isinstance(definition.value, _XdrUnion):
gen = XdrUnionGenerator(language, peer)
+ elif isinstance(definition.value, _XdrPassthru):
+ gen = XdrPassthruGenerator(language, peer)
else:
continue
gen.emit_definition(definition.value)
@@ -64,25 +69,31 @@ def emit_header_maxsize(root: Specification, language: str, peer: str) -> None:
gen = XdrStructGenerator(language, peer)
elif isinstance(definition.value, _XdrUnion):
gen = XdrUnionGenerator(language, peer)
+ elif isinstance(definition.value, _RpcProgram):
+ gen = XdrProgramGenerator(language, peer)
else:
continue
gen.emit_maxsize(definition.value)
-def handle_parse_error(e: UnexpectedInput) -> bool:
- """Simple parse error reporting, no recovery attempted"""
- print(e)
- return True
-
-
def subcmd(args: Namespace) -> int:
"""Generate definitions"""
set_xdr_annotate(args.annotate)
parser = xdr_parser()
with open(args.filename, encoding="utf-8") as f:
- parse_tree = parser.parse(f.read(), on_error=handle_parse_error)
- ast = transform_parse_tree(parse_tree)
+ source = f.read()
+ try:
+ parse_tree = parser.parse(
+ source, on_error=make_error_handler(source, args.filename)
+ )
+ except XdrParseError:
+ return 1
+ try:
+ ast = transform_parse_tree(parse_tree)
+ except VisitError as e:
+ handle_transform_error(e, source, args.filename)
+ return 1
gen = XdrHeaderTopGenerator(args.language, args.peer)
gen.emit_definition(args.filename, ast)
diff --git a/tools/net/sunrpc/xdrgen/subcmds/lint.py b/tools/net/sunrpc/xdrgen/subcmds/lint.py
index 36cc43717d30..e1da49632e62 100644
--- a/tools/net/sunrpc/xdrgen/subcmds/lint.py
+++ b/tools/net/sunrpc/xdrgen/subcmds/lint.py
@@ -8,26 +8,31 @@ import logging
from argparse import Namespace
from lark import logger
-from lark.exceptions import UnexpectedInput
+from lark.exceptions import VisitError
-from xdr_parse import xdr_parser
+from xdr_parse import xdr_parser, make_error_handler, XdrParseError
+from xdr_parse import handle_transform_error
from xdr_ast import transform_parse_tree
logger.setLevel(logging.DEBUG)
-def handle_parse_error(e: UnexpectedInput) -> bool:
- """Simple parse error reporting, no recovery attempted"""
- print(e)
- return True
-
-
def subcmd(args: Namespace) -> int:
"""Lexical and syntax check of an XDR specification"""
parser = xdr_parser()
with open(args.filename, encoding="utf-8") as f:
- parse_tree = parser.parse(f.read(), on_error=handle_parse_error)
- transform_parse_tree(parse_tree)
+ source = f.read()
+ try:
+ parse_tree = parser.parse(
+ source, on_error=make_error_handler(source, args.filename)
+ )
+ except XdrParseError:
+ return 1
+ try:
+ transform_parse_tree(parse_tree)
+ except VisitError as e:
+ handle_transform_error(e, source, args.filename)
+ return 1
return 0
diff --git a/tools/net/sunrpc/xdrgen/subcmds/source.py b/tools/net/sunrpc/xdrgen/subcmds/source.py
index 2024954748f0..27e8767b1b58 100644
--- a/tools/net/sunrpc/xdrgen/subcmds/source.py
+++ b/tools/net/sunrpc/xdrgen/subcmds/source.py
@@ -8,10 +8,11 @@ import logging
from argparse import Namespace
from lark import logger
-from lark.exceptions import UnexpectedInput
+from lark.exceptions import VisitError
from generators.source_top import XdrSourceTopGenerator
from generators.enum import XdrEnumGenerator
+from generators.passthru import XdrPassthruGenerator
from generators.pointer import XdrPointerGenerator
from generators.program import XdrProgramGenerator
from generators.typedef import XdrTypedefGenerator
@@ -19,10 +20,12 @@ from generators.struct import XdrStructGenerator
from generators.union import XdrUnionGenerator
from xdr_ast import transform_parse_tree, _RpcProgram, Specification
-from xdr_ast import _XdrAst, _XdrEnum, _XdrPointer
+from xdr_ast import _XdrAst, _XdrEnum, _XdrPassthru, _XdrPointer
from xdr_ast import _XdrStruct, _XdrTypedef, _XdrUnion
-from xdr_parse import xdr_parser, set_xdr_annotate
+from xdr_parse import xdr_parser, set_xdr_annotate, set_xdr_enum_validation
+from xdr_parse import make_error_handler, XdrParseError
+from xdr_parse import handle_transform_error
logger.setLevel(logging.INFO)
@@ -72,40 +75,54 @@ def generate_server_source(filename: str, root: Specification, language: str) ->
gen.emit_source(filename, root)
for definition in root.definitions:
- emit_source_decoder(definition.value, language, "server")
+ if isinstance(definition.value, _XdrPassthru):
+ passthru_gen = XdrPassthruGenerator(language, "server")
+ passthru_gen.emit_decoder(definition.value)
+ else:
+ emit_source_decoder(definition.value, language, "server")
for definition in root.definitions:
- emit_source_encoder(definition.value, language, "server")
+ if not isinstance(definition.value, _XdrPassthru):
+ emit_source_encoder(definition.value, language, "server")
def generate_client_source(filename: str, root: Specification, language: str) -> None:
- """Generate server-side source code"""
+ """Generate client-side source code"""
gen = XdrSourceTopGenerator(language, "client")
gen.emit_source(filename, root)
- print("")
for definition in root.definitions:
- emit_source_encoder(definition.value, language, "client")
+ if isinstance(definition.value, _XdrPassthru):
+ passthru_gen = XdrPassthruGenerator(language, "client")
+ passthru_gen.emit_decoder(definition.value)
+ else:
+ emit_source_encoder(definition.value, language, "client")
for definition in root.definitions:
- emit_source_decoder(definition.value, language, "client")
+ if not isinstance(definition.value, _XdrPassthru):
+ emit_source_decoder(definition.value, language, "client")
# cel: todo: client needs PROC macros
-def handle_parse_error(e: UnexpectedInput) -> bool:
- """Simple parse error reporting, no recovery attempted"""
- print(e)
- return True
-
-
def subcmd(args: Namespace) -> int:
"""Generate encoder and decoder functions"""
set_xdr_annotate(args.annotate)
+ set_xdr_enum_validation(not args.no_enum_validation)
parser = xdr_parser()
with open(args.filename, encoding="utf-8") as f:
- parse_tree = parser.parse(f.read(), on_error=handle_parse_error)
- ast = transform_parse_tree(parse_tree)
+ source = f.read()
+ try:
+ parse_tree = parser.parse(
+ source, on_error=make_error_handler(source, args.filename)
+ )
+ except XdrParseError:
+ return 1
+ try:
+ ast = transform_parse_tree(parse_tree)
+ except VisitError as e:
+ handle_transform_error(e, source, args.filename)
+ return 1
match args.peer:
case "server":
generate_server_source(args.filename, ast, args.language)
diff --git a/tools/net/sunrpc/xdrgen/templates/C/enum/declaration/enum.j2 b/tools/net/sunrpc/xdrgen/templates/C/enum/declaration/enum.j2
index d1405c7c5354..c7ae506076bb 100644
--- a/tools/net/sunrpc/xdrgen/templates/C/enum/declaration/enum.j2
+++ b/tools/net/sunrpc/xdrgen/templates/C/enum/declaration/enum.j2
@@ -1,4 +1,3 @@
{# SPDX-License-Identifier: GPL-2.0 #}
-
bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ name }} *ptr);
bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, {{ name }} value);
diff --git a/tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum.j2 b/tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum.j2
index 6482984f1cb7..735a34157fdf 100644
--- a/tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum.j2
+++ b/tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum.j2
@@ -14,6 +14,17 @@ xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ name }} *ptr)
if (xdr_stream_decode_u32(xdr, &val) < 0)
return false;
+{% if validate and enumerators %}
+ /* Compiler may optimize to a range check for dense enums */
+ switch (val) {
+{% for e in enumerators %}
+ case {{ e.name }}:
+{% endfor %}
+ break;
+ default:
+ return false;
+ }
+{% endif %}
*ptr = val;
return true;
}
diff --git a/tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum_be.j2 b/tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum_be.j2
index 44c391c10b42..82782a510d47 100644
--- a/tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum_be.j2
+++ b/tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum_be.j2
@@ -10,5 +10,25 @@ static bool __maybe_unused
{% endif %}
xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ name }} *ptr)
{
+{% if validate and enumerators %}
+ __be32 raw;
+ u32 val;
+
+ if (xdr_stream_decode_be32(xdr, &raw) < 0)
+ return false;
+ val = be32_to_cpu(raw);
+ /* Compiler may optimize to a range check for dense enums */
+ switch (val) {
+{% for e in enumerators %}
+ case {{ e.name }}:
+{% endfor %}
+ break;
+ default:
+ return false;
+ }
+ *ptr = raw;
+ return true;
+{% else %}
return xdr_stream_decode_be32(xdr, ptr) == 0;
+{% endif %}
}
diff --git a/tools/net/sunrpc/xdrgen/templates/C/enum/definition/close.j2 b/tools/net/sunrpc/xdrgen/templates/C/enum/definition/close.j2
index a07586cbee17..446266ad6d17 100644
--- a/tools/net/sunrpc/xdrgen/templates/C/enum/definition/close.j2
+++ b/tools/net/sunrpc/xdrgen/templates/C/enum/definition/close.j2
@@ -1,3 +1,4 @@
{# SPDX-License-Identifier: GPL-2.0 #}
};
+
typedef enum {{ name }} {{ name }};
diff --git a/tools/net/sunrpc/xdrgen/templates/C/enum/definition/close_be.j2 b/tools/net/sunrpc/xdrgen/templates/C/enum/definition/close_be.j2
index 2c18948bddf7..cfeee2287e68 100644
--- a/tools/net/sunrpc/xdrgen/templates/C/enum/definition/close_be.j2
+++ b/tools/net/sunrpc/xdrgen/templates/C/enum/definition/close_be.j2
@@ -1,3 +1,4 @@
{# SPDX-License-Identifier: GPL-2.0 #}
};
+
typedef __be32 {{ name }};
diff --git a/tools/net/sunrpc/xdrgen/templates/C/passthru/definition.j2 b/tools/net/sunrpc/xdrgen/templates/C/passthru/definition.j2
new file mode 100644
index 000000000000..900c7516a29c
--- /dev/null
+++ b/tools/net/sunrpc/xdrgen/templates/C/passthru/definition.j2
@@ -0,0 +1,3 @@
+{# SPDX-License-Identifier: GPL-2.0 #}
+
+{{ content }}
diff --git a/tools/net/sunrpc/xdrgen/templates/C/passthru/source.j2 b/tools/net/sunrpc/xdrgen/templates/C/passthru/source.j2
new file mode 100644
index 000000000000..900c7516a29c
--- /dev/null
+++ b/tools/net/sunrpc/xdrgen/templates/C/passthru/source.j2
@@ -0,0 +1,3 @@
+{# SPDX-License-Identifier: GPL-2.0 #}
+
+{{ content }}
diff --git a/tools/net/sunrpc/xdrgen/templates/C/program/decoder/argument.j2 b/tools/net/sunrpc/xdrgen/templates/C/program/decoder/argument.j2
index 0b1709cca0d4..19b219dd276d 100644
--- a/tools/net/sunrpc/xdrgen/templates/C/program/decoder/argument.j2
+++ b/tools/net/sunrpc/xdrgen/templates/C/program/decoder/argument.j2
@@ -14,7 +14,11 @@ bool {{ program }}_svc_decode_{{ argument }}(struct svc_rqst *rqstp, struct xdr_
{% if argument == 'void' %}
return xdrgen_decode_void(xdr);
{% else %}
+{% if argument in structs %}
struct {{ argument }} *argp = rqstp->rq_argp;
+{% else %}
+ {{ argument }} *argp = rqstp->rq_argp;
+{% endif %}
return xdrgen_decode_{{ argument }}(xdr, argp);
{% endif %}
diff --git a/tools/net/sunrpc/xdrgen/templates/C/program/definition/program.j2 b/tools/net/sunrpc/xdrgen/templates/C/program/definition/program.j2
new file mode 100644
index 000000000000..320663ffc37f
--- /dev/null
+++ b/tools/net/sunrpc/xdrgen/templates/C/program/definition/program.j2
@@ -0,0 +1,5 @@
+{# SPDX-License-Identifier: GPL-2.0 #}
+
+#ifndef {{ name }}
+#define {{ name }} ({{ value }})
+#endif
diff --git a/tools/net/sunrpc/xdrgen/templates/C/program/encoder/result.j2 b/tools/net/sunrpc/xdrgen/templates/C/program/encoder/result.j2
index 6fc61a5d47b7..746592cfda56 100644
--- a/tools/net/sunrpc/xdrgen/templates/C/program/encoder/result.j2
+++ b/tools/net/sunrpc/xdrgen/templates/C/program/encoder/result.j2
@@ -14,8 +14,14 @@ bool {{ program }}_svc_encode_{{ result }}(struct svc_rqst *rqstp, struct xdr_st
{% if result == 'void' %}
return xdrgen_encode_void(xdr);
{% else %}
+{% if result in structs %}
struct {{ result }} *resp = rqstp->rq_resp;
return xdrgen_encode_{{ result }}(xdr, resp);
+{% else %}
+ {{ result }} *resp = rqstp->rq_resp;
+
+ return xdrgen_encode_{{ result }}(xdr, *resp);
+{% endif %}
{% endif %}
}
diff --git a/tools/net/sunrpc/xdrgen/templates/C/program/maxsize/max_args.j2 b/tools/net/sunrpc/xdrgen/templates/C/program/maxsize/max_args.j2
new file mode 100644
index 000000000000..9f3bfb47d2f4
--- /dev/null
+++ b/tools/net/sunrpc/xdrgen/templates/C/program/maxsize/max_args.j2
@@ -0,0 +1,3 @@
+{# SPDX-License-Identifier: GPL-2.0 #}
+#define {{ '{:<31}'.format(macro) }} \
+ ({{ width }})
diff --git a/tools/net/sunrpc/xdrgen/templates/C/source_top/client.j2 b/tools/net/sunrpc/xdrgen/templates/C/source_top/client.j2
index c5518c519854..df3598c38b2c 100644
--- a/tools/net/sunrpc/xdrgen/templates/C/source_top/client.j2
+++ b/tools/net/sunrpc/xdrgen/templates/C/source_top/client.j2
@@ -8,6 +8,5 @@
#include <linux/sunrpc/xdr.h>
#include <linux/sunrpc/xdrgen/_defs.h>
#include <linux/sunrpc/xdrgen/_builtins.h>
-#include <linux/sunrpc/xdrgen/nlm4.h>
#include <linux/sunrpc/clnt.h>
diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/decoder/bool_spec.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/bool_spec.j2
new file mode 100644
index 000000000000..05ad491f74af
--- /dev/null
+++ b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/bool_spec.j2
@@ -0,0 +1,7 @@
+{# SPDX-License-Identifier: GPL-2.0 #}
+{% if annotate %}
+ /* discriminant {{ name }} */
+{% endif %}
+ if (!xdrgen_decode_{{ type }}(xdr, &ptr->{{ name }}))
+ return false;
+ if (ptr->{{ name }}) {
diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/definition/close.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/definition/close.j2
index 01d716d0099e..5fc1937ba774 100644
--- a/tools/net/sunrpc/xdrgen/templates/C/union/definition/close.j2
+++ b/tools/net/sunrpc/xdrgen/templates/C/union/definition/close.j2
@@ -3,6 +3,7 @@
};
{%- if name in public_apis %}
+
bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, struct {{ name }} *ptr);
bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const struct {{ name }} *ptr);
{%- endif -%}
diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/encoder/bool_spec.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/encoder/bool_spec.j2
new file mode 100644
index 000000000000..e5135ed6471c
--- /dev/null
+++ b/tools/net/sunrpc/xdrgen/templates/C/union/encoder/bool_spec.j2
@@ -0,0 +1,7 @@
+{# SPDX-License-Identifier: GPL-2.0 #}
+{% if annotate %}
+ /* discriminant {{ name }} */
+{% endif %}
+ if (!xdrgen_encode_{{ type }}(xdr, ptr->{{ name }}))
+ return false;
+ if (ptr->{{ name }}) {
diff --git a/tools/net/sunrpc/xdrgen/xdr_ast.py b/tools/net/sunrpc/xdrgen/xdr_ast.py
index 5233e73c7046..14bff9477473 100644
--- a/tools/net/sunrpc/xdrgen/xdr_ast.py
+++ b/tools/net/sunrpc/xdrgen/xdr_ast.py
@@ -34,6 +34,8 @@ def xdr_quadlen(val: str) -> int:
symbolic_widths = {
"void": ["XDR_void"],
"bool": ["XDR_bool"],
+ "short": ["XDR_short"],
+ "unsigned_short": ["XDR_unsigned_short"],
"int": ["XDR_int"],
"unsigned_int": ["XDR_unsigned_int"],
"long": ["XDR_long"],
@@ -48,6 +50,8 @@ symbolic_widths = {
max_widths = {
"void": 0,
"bool": 1,
+ "short": 1,
+ "unsigned_short": 1,
"int": 1,
"unsigned_int": 1,
"long": 1,
@@ -326,8 +330,6 @@ class _XdrEnum(_XdrAst):
"""An XDR enum definition"""
name: str
- minimum: int
- maximum: int
enumerators: List[_XdrEnumerator]
def max_width(self) -> int:
@@ -515,6 +517,13 @@ class _Pragma(_XdrAst):
@dataclass
+class _XdrPassthru(_XdrAst):
+ """Passthrough line to emit verbatim in output"""
+
+ content: str
+
+
+@dataclass
class Definition(_XdrAst, ast_utils.WithMeta):
"""Corresponds to 'definition' in the grammar"""
@@ -568,8 +577,6 @@ class ParseToAst(Transformer):
value = children[1].value
return _XdrConstant(name, value)
- # cel: Python can compute a min() and max() for the enumerator values
- # so that the generated code can perform proper range checking.
def enum(self, children):
"""Instantiate one _XdrEnum object"""
enum_name = children[0].symbol
@@ -583,7 +590,7 @@ class ParseToAst(Transformer):
enumerators.append(_XdrEnumerator(name, value))
i = i + 2
- return _XdrEnum(enum_name, 0, 0, enumerators)
+ return _XdrEnum(enum_name, enumerators)
def fixed_length_opaque(self, children):
"""Instantiate one _XdrFixedLengthOpaque declaration object"""
@@ -738,14 +745,42 @@ class ParseToAst(Transformer):
raise NotImplementedError("Directive not supported")
return _Pragma()
+ def passthru_def(self, children):
+ """Instantiate one _XdrPassthru object"""
+ token = children[0]
+ content = token.value[1:]
+ return _XdrPassthru(content)
+
transformer = ast_utils.create_transformer(this_module, ParseToAst())
+def _merge_consecutive_passthru(definitions: List[Definition]) -> List[Definition]:
+ """Merge consecutive passthru definitions into single nodes"""
+ result = []
+ i = 0
+ while i < len(definitions):
+ if isinstance(definitions[i].value, _XdrPassthru):
+ lines = [definitions[i].value.content]
+ meta = definitions[i].meta
+ j = i + 1
+ while j < len(definitions) and isinstance(definitions[j].value, _XdrPassthru):
+ lines.append(definitions[j].value.content)
+ j += 1
+ merged = _XdrPassthru("\n".join(lines))
+ result.append(Definition(meta, merged))
+ i = j
+ else:
+ result.append(definitions[i])
+ i += 1
+ return result
+
+
def transform_parse_tree(parse_tree):
"""Transform productions into an abstract syntax tree"""
-
- return transformer.transform(parse_tree)
+ ast = transformer.transform(parse_tree)
+ ast.definitions = _merge_consecutive_passthru(ast.definitions)
+ return ast
def get_header_name() -> str:
diff --git a/tools/net/sunrpc/xdrgen/xdr_parse.py b/tools/net/sunrpc/xdrgen/xdr_parse.py
index 964b44e675df..241e96c1fdd9 100644
--- a/tools/net/sunrpc/xdrgen/xdr_parse.py
+++ b/tools/net/sunrpc/xdrgen/xdr_parse.py
@@ -3,12 +3,43 @@
"""Common parsing code for xdrgen"""
+import sys
+from typing import Callable
+
from lark import Lark
+from lark.exceptions import UnexpectedInput, UnexpectedToken, VisitError
# Set to True to emit annotation comments in generated source
annotate = False
+# Set to True to emit enum value validation in decoders
+enum_validation = True
+
+# Map internal Lark token names to human-readable names
+TOKEN_NAMES = {
+ "__ANON_0": "identifier",
+ "__ANON_1": "number",
+ "SEMICOLON": "';'",
+ "LBRACE": "'{'",
+ "RBRACE": "'}'",
+ "LPAR": "'('",
+ "RPAR": "')'",
+ "LSQB": "'['",
+ "RSQB": "']'",
+ "LESSTHAN": "'<'",
+ "MORETHAN": "'>'",
+ "EQUAL": "'='",
+ "COLON": "':'",
+ "COMMA": "','",
+ "STAR": "'*'",
+ "$END": "end of file",
+}
+
+
+class XdrParseError(Exception):
+ """Raised when XDR parsing fails"""
+
def set_xdr_annotate(set_it: bool) -> None:
"""Set 'annotate' if --annotate was specified on the command line"""
@@ -21,6 +52,113 @@ def get_xdr_annotate() -> bool:
return annotate
+def set_xdr_enum_validation(set_it: bool) -> None:
+ """Set 'enum_validation' based on command line options"""
+ global enum_validation
+ enum_validation = set_it
+
+
+def get_xdr_enum_validation() -> bool:
+ """Return True when enum validation is enabled for decoder generation"""
+ return enum_validation
+
+
+def make_error_handler(source: str, filename: str) -> Callable[[UnexpectedInput], bool]:
+ """Create an error handler that reports the first parse error and aborts.
+
+ Args:
+ source: The XDR source text being parsed
+ filename: The name of the file being parsed
+
+ Returns:
+ An error handler function for use with Lark's on_error parameter
+ """
+ lines = source.splitlines()
+
+ def handle_parse_error(e: UnexpectedInput) -> bool:
+ """Report a parse error with context and abort parsing"""
+ line_num = e.line
+ column = e.column
+ line_text = lines[line_num - 1] if 0 < line_num <= len(lines) else ""
+
+ # Build the error message
+ msg_parts = [f"{filename}:{line_num}:{column}: parse error"]
+
+ # Show what was found vs what was expected
+ if isinstance(e, UnexpectedToken):
+ token = e.token
+ if token.type == "__ANON_0":
+ found = f"identifier '{token.value}'"
+ elif token.type == "__ANON_1":
+ found = f"number '{token.value}'"
+ else:
+ found = f"'{token.value}'"
+ msg_parts.append(f"Unexpected {found}")
+
+ # Provide helpful expected tokens list
+ expected = e.expected
+ if expected:
+ readable = [
+ TOKEN_NAMES.get(exp, exp.lower().replace("_", " "))
+ for exp in sorted(expected)
+ ]
+ if len(readable) == 1:
+ msg_parts.append(f"Expected {readable[0]}")
+ elif len(readable) <= 4:
+ msg_parts.append(f"Expected one of: {', '.join(readable)}")
+ else:
+ msg_parts.append(str(e).split("\n")[0])
+
+ # Show the offending line with a caret pointing to the error
+ msg_parts.append("")
+ msg_parts.append(f" {line_text}")
+ prefix = line_text[: column - 1].expandtabs()
+ msg_parts.append(f" {' ' * len(prefix)}^")
+
+ sys.stderr.write("\n".join(msg_parts) + "\n")
+ raise XdrParseError()
+
+ return handle_parse_error
+
+
+def handle_transform_error(e: VisitError, source: str, filename: str) -> None:
+ """Report a transform error with context.
+
+ Args:
+ e: The VisitError from Lark's transformer
+ source: The XDR source text being parsed
+ filename: The name of the file being parsed
+ """
+ lines = source.splitlines()
+
+ # Extract position from the tree node if available
+ line_num = 0
+ column = 0
+ if hasattr(e.obj, "meta") and e.obj.meta:
+ line_num = e.obj.meta.line
+ column = e.obj.meta.column
+
+ line_text = lines[line_num - 1] if 0 < line_num <= len(lines) else ""
+
+ # Build the error message
+ msg_parts = [f"{filename}:{line_num}:{column}: semantic error"]
+
+ # The original exception is typically a KeyError for undefined types
+ if isinstance(e.orig_exc, KeyError):
+ msg_parts.append(f"Undefined type '{e.orig_exc.args[0]}'")
+ else:
+ msg_parts.append(str(e.orig_exc))
+
+ # Show the offending line with a caret pointing to the error
+ if line_text:
+ msg_parts.append("")
+ msg_parts.append(f" {line_text}")
+ prefix = line_text[: column - 1].expandtabs()
+ msg_parts.append(f" {' ' * len(prefix)}^")
+
+ sys.stderr.write("\n".join(msg_parts) + "\n")
+
+
def xdr_parser() -> Lark:
"""Return a Lark parser instance configured with the XDR language grammar"""
diff --git a/tools/net/sunrpc/xdrgen/xdrgen b/tools/net/sunrpc/xdrgen/xdrgen
index 3afd0547d67c..b2fb43f4a2ec 100755
--- a/tools/net/sunrpc/xdrgen/xdrgen
+++ b/tools/net/sunrpc/xdrgen/xdrgen
@@ -123,6 +123,12 @@ There is NO WARRANTY, to the extent permitted by law.""",
help="Generate code for client or server side",
type=str,
)
+ source_parser.add_argument(
+ "--no-enum-validation",
+ action="store_true",
+ default=False,
+ help="Disable enum value validation in decoders",
+ )
source_parser.add_argument("filename", help="File containing an XDR specification")
source_parser.set_defaults(func=source.subcmd)
@@ -133,7 +139,5 @@ There is NO WARRANTY, to the extent permitted by law.""",
try:
if __name__ == "__main__":
sys.exit(main())
-except SystemExit:
- sys.exit(0)
except (KeyboardInterrupt, BrokenPipeError):
sys.exit(1)