Repository navigation
nvme: split command lookup and config parsing for privsep - #4185
Merged
Merged
Conversation
This was referenced Oct 15, 2026
igaw
marked this pull request as ready for review
October 20, 2026 06:39
There was a problem hiding this comment.
🟡 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-optionsparsing 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
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

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.
handle_plugin()is split intoplugin_lookup(), which parses the global options and finds what to do for a command line, andplugin_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()callsplugin_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--verbosestill 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 withopterr = 0is gone: the new parser has no quiet mode, and a second parse is not needed.)shr_ini_read_file()reads and checks a file likeshr_ini_parse_file(), andshr_ini_parse_inplace()parses a buffer without copying it, so the strings point into the buffer.strdup()per value.Testing:
plugin_lookup()picks the commandhandle_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()--werror), every commit on its own