agora inbox for pgsql-hackers@postgresql.orghelp / color / mirror / Atom feed
[PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). 184+ messages / 1 participants [nested] [flat]
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
* [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). @ 2026-09-04 21:47 Nathan Bossart <nathan@postgresql.org> 0 siblings, 0 replies; 184+ messages in thread From: Nathan Bossart @ 2026-09-04 21:47 UTC (permalink / raw) The in-tree getopt_long() moves each non-option to the end of argv as soon as it finds one, which puts a non-option that preceded an option right where the option's argument lookup expects to find it. For example, "vacuumdb postgres --jobs" takes "postgres" as the number of jobs instead of complaining that --jobs is missing its argument. To fix, stop the argument lookups at the start of the moved non-options, which we already track to know when to stop scanning. Oversight in commit 411b720343. Author: Sehrope Sarkuni <sehrope@jackdb.com> Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com Backpatch-through: 17 --- src/bin/scripts/t/100_vacuumdb.pl | 4 ++++ src/port/getopt_long.c | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7c4e35a6717..b78fa2a38de 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -240,6 +240,10 @@ $node->command_fails_like( [ 'vacuumdb', '--all', 'postgres' ], qr/cannot vacuum all databases and a specific one at the same time/, 'cannot use option --all and a dbname as argument at the same time'); +$node->command_fails_like( + [ 'vacuumdb', 'postgres', '--jobs' ], + qr/requires an argument/, + 'option missing its argument after a non-option'); $node->safe_psql( 'postgres', q| diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 0a9a50189f1..f2edadb59d5 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -66,6 +66,9 @@ getopt_long(int argc, char *const argv[], static int nonopt_start = -1; static bool force_nonopt = false; + if (nonopt_start == -1) + nonopt_start = argc; + if (!*place) { /* update scanning pointer */ char **args = (char **) argv; @@ -75,7 +78,7 @@ retry: /* * If we are out of arguments or only non-options remain, return -1. */ - if (optind >= argc || optind == nonopt_start) + if (optind >= nonopt_start) { place = EMSG; nonopt_start = -1; @@ -99,10 +102,7 @@ retry: args[i] = args[i + 1]; args[argc - 1] = place; - if (nonopt_start == -1) - nonopt_start = argc - 1; - else - nonopt_start--; + nonopt_start--; goto retry; } @@ -139,7 +139,7 @@ retry: optarg = place + namelen + 1; else if (has_arg == optional_argument) optarg = NULL; - else if (optind < argc - 1) + else if (optind < nonopt_start - 1) { optind++; optarg = argv[optind]; @@ -222,7 +222,7 @@ retry: { /* need an argument */ if (*place) /* no white space */ optarg = place; - else if (argc <= ++optind) + else if (nonopt_start <= ++optind) { /* no arg */ place = EMSG; if (*optstring == ':') -- 2.55.0 --Zv9Xg0nwk4TTIGFg-- ^ permalink raw reply [nested|flat] 184+ messages in thread
end of thread, other threads:[~2026-09-04 21:47 UTC | newest] Thread overview: 184+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org> 2026-09-04 21:47 [PATCH v2 2/2] Fix option argument lookup in in-tree getopt_long(). Nathan Bossart <nathan@postgresql.org>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox