Skip to content

nvme: split command lookup and config parsing for privsep - #4185

Merged
igaw merged 5 commits into
linux-nvme:masterfrom
dwsuse:cli-refactor
Oct 20, 2026
Merged

igaw merged 5 commits into
linux-nvme:masterfrom
dwsuse:cli-refactor

Conversation

@dwsuse

@dwsuse dwsuse commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Preparation for privilege separation (#3879) and the parser sandbox: no functional change. It restructures five places so that #4182 and #4183 can use the existing code paths instead of adding parallel ones. Rebased onto the new argconfig parser.

  • Command lookup: handle_plugin() is split into plugin_lookup(), which parses the global options and finds what to do for a command line, and plugin_call_run(), which does it. The lookup runs nothing and prints only the usage errors of the global options. It no longer modifies the caller's argv in the "plugin-command" form.
  • main() looks up first: main() calls plugin_lookup() once before it loads nvme-cli.conf and runs what it found afterwards. The config file skips the global options given on the command line, so the command line still wins; a count such as --verbose still adds up as if the file came first. nvme: drop root privileges through the privsep helper #4182 decides on the privileges between the lookup and the config file. (The old dry-run lookup with opterr = 0 is gone: the new parser has no quiet mode, and a second parse is not needed.)
  • INI files: shr_ini_read_file() reads and checks a file like shr_ini_parse_file(), and shr_ini_parse_inplace() parses a buffer without copying it, so the strings point into the buffer.
  • nvme-cli.conf: parsed in place; the strings of the global options point into the file buffer instead of one strdup() per value.
  • --set-options: parsed into a list first, which is then applied to the global context; the parser no longer prints, the error is reported after applying the valid options in front of it, as before.

Testing:

  • unit tests: plugin_lookup() picks the command handle_plugin() runs without running it or changing the arguments; the global options given on the command line win over the config file, counts add up, invalid values are still reported; shr_ini_read_file(), shr_ini_parse_inplace()
  • full test suite (gcc, clang, --werror), every commit on its own
  • FreeBSD and Windows (x86_64, aarch64) builds

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Repeated verbosity keys change existing behavior, and global-option lookup tests pass without exercising successful parsing.

2 open issues
What changed in this PR

Prepares nvme-cli for privilege separation and parser sandboxing by separating parsing from execution.

Changes:

  • Splits command lookup from execution and performs lookup before loading configuration.
  • Adds in-place INI parsing while preserving command-line option precedence.
  • Separates --set-options parsing from application and adds unit tests.
File Description
tests/​unit/​c/​test-plugin.c Tests lookup against command dispatch.
tests/​unit/​c/​test-global-config.c Tests command-line precedence and additive counts.
src/​plugin.h Declares lookup and execution interfaces.
src/​plugin.c Separates command selection from execution.
src/​nvme.c Performs lookup before configuration loading.
src/​global-ctx.c Separates option parsing from application.
src/​global-config.c Parses retained buffers and preserves CLI overrides.
src/​argconfig.c Resets option tracking on registration.
shared/​tests/​test-ini-util.c Tests file reading and in-place parsing.
shared/​ini-util.h Declares new INI interfaces.
shared/​ini-util.c Separates INI reading from parsing.

Review effort: Balanced

Comment thread src/global-config.c Outdated
Comment thread tests/unit/c/test-plugin.c
Split handle_plugin() into plugin_lookup(), which parses the global
options and finds what to do for a command line, and plugin_call_run(),
which does it. The lookup runs nothing and prints only the usage errors
of the global options. "nvme <plugin>-<command>" no longer modifies the
arguments of the caller.

No functional change. This allows to decide on the command before
running it, e.g. whether it needs root privileges, with the same code
which runs it.

Signed-off-by: Daniel Wagner <dwagner@suse.de>
Add shr_ini_read_file(), which reads and checks a file the way
shr_ini_parse_file() does and hands back its content, and
shr_ini_parse_inplace(), which parses a buffer without copying it, so
that the strings passed to the callback point into the buffer.

A caller can then keep the strings of a configuration file without
copying each of them, and read the file and parse its content in
different places.

Signed-off-by: Daniel Wagner <dwagner@suse.de>
Parse nvme-cli.conf in place and let the strings of nvme_args point into
the file buffer instead of duplicating each value. The buffer of every
loaded file is kept, as strings of nvme_args may point into it.

No functional change. The settings of the file are then held by
nvme_args and the file buffer alone.

Signed-off-by: Daniel Wagner <dwagner@suse.de>
Parse --set-options into a list of options up to the first invalid one,
and then apply the list to the global context and report the error.
The parser no longer prints anything.

No functional change: the valid options in front of an invalid one are
still applied before the error is reported.

Signed-off-by: Daniel Wagner <dwagner@suse.de>
main() looks up the command, including the global options in front of
it, before it loads nvme-cli.conf, and runs what it found afterwards.
The file skips the global options given on the command line, so the
command line still wins over the file; a count such as --verbose still
adds up as if the file came first. Registering the global options
forgets which ones were given, for the fuzz tests which run main() more
than once.

No functional change. This allows to decide on the command before
anything else runs, e.g. whether it needs root privileges.

Signed-off-by: Daniel Wagner <dwagner@suse.de>
@igaw
igaw merged commit 192bcce into linux-nvme:master Oct 20, 2026
34 checks passed
@dwsuse
dwsuse deleted the cli-refactor branch October 20, 2026 09:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants