Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 76fd342

Browse files
Provide a better error message for misplaced dispatch options.
Before this patch, misplacing a special must-be-first option for dispatching to a subprogram (e.g., postgres -D . --single) would fail with an error like FATAL: --single requires a value This patch adjusts this error to more accurately complain that the special option wasn't listed first. The aforementioned error message now looks like FATAL: --single must be first argument The dispatch option parsing code has been refactored for use wherever ParseLongOption() is called. Beyond the obvious advantage of avoiding code duplication, this should prevent similar problems when new dispatch options are added. Note that we assume that none of the dispatch option names match another valid command-line argument, such as the name of a configuration parameter. Ideally, we'd remove this must-be-first requirement for these options, but after some investigation, we decided that wasn't worth the added complexity and behavior changes. Author: Nathan Bossart, Greg Sabino Mullane Reviewed-by: Greg Sabino Mullane, Peter Eisentraut, Álvaro Herrera, Tom Lane Discussion: https://postgr.es/m/CAKAnmmJkZtZAiSryho%3DgYpbvC7H-HNjEDAh16F3SoC9LPu8rqQ%40mail.gmail.com
1 parent 24c1c63 commit 76fd342

File tree

6 files changed

+133
-16
lines changed

6 files changed

+133
-16
lines changed

src/backend/bootstrap/bootstrap.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,8 +224,21 @@ BootstrapModeMain(int argc, char *argv[], bool check_only)
224224
case 'B':
225225
SetConfigOption("shared_buffers", optarg, PGC_POSTMASTER, PGC_S_ARGV);
226226
break;
227-
case 'c':
228227
case '-':
228+
229+
/*
230+
* Error if the user misplaced a special must-be-first option
231+
* for dispatching to a subprogram. parse_dispatch_option()
232+
* returns DISPATCH_POSTMASTER if it doesn't find a match, so
233+
* error for anything else.
234+
*/
235+
if (parse_dispatch_option(optarg) != DISPATCH_POSTMASTER)
236+
ereport(ERROR,
237+
(errcode(ERRCODE_SYNTAX_ERROR),
238+
errmsg("--%s must be first argument", optarg)));
239+
240+
/* FALLTHROUGH */
241+
case 'c':
229242
{
230243
char *name,
231244
*value;

src/backend/main/main.c

Lines changed: 73 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,19 @@
4343
const char *progname;
4444
static bool reached_main = false;
4545

46+
/* names of special must-be-first options for dispatching to subprograms */
47+
static const char *const DispatchOptionNames[] =
48+
{
49+
[DISPATCH_CHECK] = "check",
50+
[DISPATCH_BOOT] = "boot",
51+
[DISPATCH_FORKCHILD] = "forkchild",
52+
[DISPATCH_DESCRIBE_CONFIG] = "describe-config",
53+
[DISPATCH_SINGLE] = "single",
54+
/* DISPATCH_POSTMASTER has no name */
55+
};
56+
57+
StaticAssertDecl(lengthof(DispatchOptionNames) == DISPATCH_POSTMASTER,
58+
"array length mismatch");
4659

4760
static void startup_hacks(const char *progname);
4861
static void init_locale(const char *categoryname, int category, const char *locale);
@@ -57,6 +70,7 @@ int
5770
main(int argc, char *argv[])
5871
{
5972
bool do_check_root = true;
73+
DispatchOption dispatch_option = DISPATCH_POSTMASTER;
6074

6175
reached_main = true;
6276

@@ -179,26 +193,72 @@ main(int argc, char *argv[])
179193
* Dispatch to one of various subprograms depending on first argument.
180194
*/
181195

182-
if (argc > 1 && strcmp(argv[1], "--check") == 0)
183-
BootstrapModeMain(argc, argv, true);
184-
else if (argc > 1 && strcmp(argv[1], "--boot") == 0)
185-
BootstrapModeMain(argc, argv, false);
196+
if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '-')
197+
dispatch_option = parse_dispatch_option(&argv[1][2]);
198+
199+
switch (dispatch_option)
200+
{
201+
case DISPATCH_CHECK:
202+
BootstrapModeMain(argc, argv, true);
203+
break;
204+
case DISPATCH_BOOT:
205+
BootstrapModeMain(argc, argv, false);
206+
break;
207+
case DISPATCH_FORKCHILD:
186208
#ifdef EXEC_BACKEND
187-
else if (argc > 1 && strncmp(argv[1], "--forkchild", 11) == 0)
188-
SubPostmasterMain(argc, argv);
209+
SubPostmasterMain(argc, argv);
210+
#else
211+
Assert(false); /* should never happen */
189212
#endif
190-
else if (argc > 1 && strcmp(argv[1], "--describe-config") == 0)
191-
GucInfoMain();
192-
else if (argc > 1 && strcmp(argv[1], "--single") == 0)
193-
PostgresSingleUserMain(argc, argv,
194-
strdup(get_user_name_or_exit(progname)));
195-
else
196-
PostmasterMain(argc, argv);
213+
break;
214+
case DISPATCH_DESCRIBE_CONFIG:
215+
GucInfoMain();
216+
break;
217+
case DISPATCH_SINGLE:
218+
PostgresSingleUserMain(argc, argv,
219+
strdup(get_user_name_or_exit(progname)));
220+
break;
221+
case DISPATCH_POSTMASTER:
222+
PostmasterMain(argc, argv);
223+
break;
224+
}
225+
197226
/* the functions above should not return */
198227
abort();
199228
}
200229

230+
/*
231+
* Returns the matching DispatchOption value for the given option name. If no
232+
* match is found, DISPATCH_POSTMASTER is returned.
233+
*/
234+
DispatchOption
235+
parse_dispatch_option(const char *name)
236+
{
237+
for (int i = 0; i < lengthof(DispatchOptionNames); i++)
238+
{
239+
/*
240+
* Unlike the other dispatch options, "forkchild" takes an argument,
241+
* so we just look for the prefix for that one. For non-EXEC_BACKEND
242+
* builds, we never want to return DISPATCH_FORKCHILD, so skip over it
243+
* in that case.
244+
*/
245+
if (i == DISPATCH_FORKCHILD)
246+
{
247+
#ifdef EXEC_BACKEND
248+
if (strncmp(DispatchOptionNames[DISPATCH_FORKCHILD], name,
249+
strlen(DispatchOptionNames[DISPATCH_FORKCHILD])) == 0)
250+
return DISPATCH_FORKCHILD;
251+
#endif
252+
continue;
253+
}
254+
255+
if (strcmp(DispatchOptionNames[i], name) == 0)
256+
return (DispatchOption) i;
257+
}
201258

259+
/* no match means this is a postmaster */
260+
return DISPATCH_POSTMASTER;
261+
}
202262

203263
/*
204264
* Place platform-specific startup hacks here. This is the right

src/backend/postmaster/postmaster.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -589,8 +589,21 @@ PostmasterMain(int argc, char *argv[])
589589
output_config_variable = strdup(optarg);
590590
break;
591591

592-
case 'c':
593592
case '-':
593+
594+
/*
595+
* Error if the user misplaced a special must-be-first option
596+
* for dispatching to a subprogram. parse_dispatch_option()
597+
* returns DISPATCH_POSTMASTER if it doesn't find a match, so
598+
* error for anything else.
599+
*/
600+
if (parse_dispatch_option(optarg) != DISPATCH_POSTMASTER)
601+
ereport(ERROR,
602+
(errcode(ERRCODE_SYNTAX_ERROR),
603+
errmsg("--%s must be first argument", optarg)));
604+
605+
/* FALLTHROUGH */
606+
case 'c':
594607
{
595608
char *name,
596609
*value;

src/backend/tcop/postgres.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3947,8 +3947,21 @@ process_postgres_switches(int argc, char *argv[], GucContext ctx,
39473947
/* ignored for consistency with the postmaster */
39483948
break;
39493949

3950-
case 'c':
39513950
case '-':
3951+
3952+
/*
3953+
* Error if the user misplaced a special must-be-first option
3954+
* for dispatching to a subprogram. parse_dispatch_option()
3955+
* returns DISPATCH_POSTMASTER if it doesn't find a match, so
3956+
* error for anything else.
3957+
*/
3958+
if (parse_dispatch_option(optarg) != DISPATCH_POSTMASTER)
3959+
ereport(ERROR,
3960+
(errcode(ERRCODE_SYNTAX_ERROR),
3961+
errmsg("--%s must be first argument", optarg)));
3962+
3963+
/* FALLTHROUGH */
3964+
case 'c':
39523965
{
39533966
char *name,
39543967
*value;

src/include/postmaster/postmaster.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,4 +138,21 @@ extern PMChild *FindPostmasterChildByPid(int pid);
138138
*/
139139
#define MAX_BACKENDS 0x3FFFF
140140

141+
/*
142+
* These values correspond to the special must-be-first options for dispatching
143+
* to various subprograms. parse_dispatch_option() can be used to convert an
144+
* option name to one of these values.
145+
*/
146+
typedef enum DispatchOption
147+
{
148+
DISPATCH_CHECK,
149+
DISPATCH_BOOT,
150+
DISPATCH_FORKCHILD,
151+
DISPATCH_DESCRIBE_CONFIG,
152+
DISPATCH_SINGLE,
153+
DISPATCH_POSTMASTER, /* must be last */
154+
} DispatchOption;
155+
156+
extern DispatchOption parse_dispatch_option(const char *name);
157+
141158
#endif /* _POSTMASTER_H */

src/tools/pgindent/typedefs.list

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,7 @@ DirectoryMethodFile
619619
DisableTimeoutParams
620620
DiscardMode
621621
DiscardStmt
622+
DispatchOption
622623
DistanceValue
623624
DistinctExpr
624625
DoState

0 commit comments

Comments
 (0)