*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
***************
*** 5250,5256 **** readRecoveryCommandFile(void)
  	 * Since we're asking ParseConfigFp() to error out at FATAL, there's no
  	 * need to check the return value.
  	 */
! 	ParseConfigFp(fd, RECOVERY_COMMAND_FILE, 0, FATAL, &head, &tail);
  
  	for (item = head; item; item = item->next)
  	{
--- 5250,5256 ----
  	 * Since we're asking ParseConfigFp() to error out at FATAL, there's no
  	 * need to check the return value.
  	 */
! 	ParseConfigFp(fd, RECOVERY_COMMAND_FILE, 0, FATAL, 0, &head, &tail);
  
  	for (item = head; item; item = item->next)
  	{
*** a/src/backend/commands/extension.c
--- b/src/backend/commands/extension.c
***************
*** 477,483 **** parse_extension_control_file(ExtensionControlFile *control,
  	/*
  	 * Parse the file content, using GUC's file parsing code
  	 */
! 	ParseConfigFp(file, filename, 0, ERROR, &head, &tail);
  
  	FreeFile(file);
  
--- 477,483 ----
  	/*
  	 * Parse the file content, using GUC's file parsing code
  	 */
! 	ParseConfigFp(file, filename, 0, ERROR, 0, &head, &tail);
  
  	FreeFile(file);
  
*** a/src/backend/utils/misc/guc-file.l
--- b/src/backend/utils/misc/guc-file.l
***************
*** 43,48 **** int GUC_yylex(void);
--- 43,51 ----
  
  static char *GUC_scanstr(const char *s);
  
+ /* Maximum number of errors to report */
+ #define MAX_ERROR_REPORTS	100
+ 
  %}
  
  %option 8bit
***************
*** 111,135 **** ProcessConfigFile(GucContext context)
  	char	   *cvc = NULL;
  	struct config_string *cvc_struct;
  	int			i;
  
! 	Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP);
  
! 	if (context == PGC_SIGHUP)
! 	{
! 		/*
! 		 * To avoid cluttering the log, only the postmaster bleats loudly
! 		 * about problems with the config file.
! 		 */
! 		elevel = IsUnderPostmaster ? DEBUG2 : LOG;
! 	}
! 	else
! 		elevel = ERROR;
  
! 	/* Parse the file into a list of option names and values */
  	head = tail = NULL;
  
! 	if (!ParseConfigFile(ConfigFileName, NULL, 0, elevel, &head, &tail))
! 		goto cleanup_list;
  
  	/*
  	 * We need the proposed new value of custom_variable_classes to check
--- 114,142 ----
  	char	   *cvc = NULL;
  	struct config_string *cvc_struct;
  	int			i;
+ 	int			errorcount;
  
! 	/*
! 	 * Config files are only processes on startup (by the postmaster)
! 	 * and on SIGHUP (by the postmaster and backends)
! 	 */
! 	Assert((context == PGC_POSTMASTER && !IsUnderPostmaster) ||
! 		   context == PGC_SIGHUP);
  
! 	/*
! 	 * To avoid cluttering the log, only the postmaster bleats loudly
! 	 * about problems with the config file.
! 	 */
! 	elevel = IsUnderPostmaster ? DEBUG2 : LOG;
  
! 	/*
! 	 * Parse the file into a list of option names and values.  We continue even
! 	 * if we hit a parse error, because we also want to report invalid values in
! 	 * the parts we could parse.
! 	 */
  	head = tail = NULL;
  
! 	errorcount = ParseConfigFile(ConfigFileName, NULL, 0, elevel, 0, &head, &tail);
  
  	/*
  	 * We need the proposed new value of custom_variable_classes to check
***************
*** 201,207 **** ProcessConfigFile(GucContext context)
  						(errcode(ERRCODE_UNDEFINED_OBJECT),
  						 errmsg("unrecognized configuration parameter \"%s\"",
  								item->name)));
! 				goto cleanup_list;
  			}
  			/*
  			 * 2. There is no GUC entry.  If we called set_config_option then
--- 208,214 ----
  						(errcode(ERRCODE_UNDEFINED_OBJECT),
  						 errmsg("unrecognized configuration parameter \"%s\"",
  								item->name)));
! 				errorcount++;
  			}
  			/*
  			 * 2. There is no GUC entry.  If we called set_config_option then
***************
*** 221,228 **** ProcessConfigFile(GucContext context)
  
  		if (!set_config_option(item->name, item->value, context,
  							   PGC_S_FILE, GUC_ACTION_SET, false))
! 			goto cleanup_list;
  	}
  
  	/*
  	 * Check for variables having been removed from the config file, and
--- 228,247 ----
  
  		if (!set_config_option(item->name, item->value, context,
  							   PGC_S_FILE, GUC_ACTION_SET, false))
! 			errorcount++;
! 
! 		if (errorcount >= MAX_ERROR_REPORTS)
! 		{
! 			ereport(elevel,
! 					(errcode(ERRCODE_SYNTAX_ERROR),
! 					 errmsg("too many errors found, stopped processing file \"%s\"",
! 							ConfigFileName)));
! 			break;
! 		}
  	}
+ 	/* Don't change configuration options if errors were detected earlier */
+ 	if (errorcount > 0)
+ 		goto cleanup_list;
  
  	/*
  	 * Check for variables having been removed from the config file, and
***************
*** 345,363 **** ProcessConfigFile(GucContext context)
  	FreeConfigVariables(head);
  	if (cvc)
  		free(cvc);
  }
  
  /*
!  * See next function for details. This one will just work with a config_file
   * name rather than an already opened File Descriptor
   */
! bool
  ParseConfigFile(const char *config_file, const char *calling_file,
! 				int depth, int elevel,
  				ConfigVariable **head_p,
  				ConfigVariable **tail_p)
  {
! 	bool		OK = true;
  	FILE	   *fp;
  	char		abs_path[MAXPGPATH];
  
--- 364,390 ----
  	FreeConfigVariables(head);
  	if (cvc)
  		free(cvc);
+ 
+ 	/* If we got errors during postmaster start, complain and bail out */
+ 	if (errorcount > 0 && !IsUnderPostmaster)
+ 		ereport(ERROR,
+ 				(errmsg("errors detected while parsing configuration files")));
  }
  
  /*
!  * See ParseConfigFp for details. This one will just work with a config_file
   * name rather than an already opened File Descriptor
+  *
+  * The return convention is the same as ParseConfigFp; additionally, file not
+  * found or file not accessible conditions are considered a single error.
   */
! int
  ParseConfigFile(const char *config_file, const char *calling_file,
! 				int depth, int elevel, int nerrors,
  				ConfigVariable **head_p,
  				ConfigVariable **tail_p)
  {
! 	int			errorcount = 0;
  	FILE	   *fp;
  	char		abs_path[MAXPGPATH];
  
***************
*** 372,378 **** ParseConfigFile(const char *config_file, const char *calling_file,
  				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
  				 errmsg("could not open configuration file \"%s\": maximum nesting depth exceeded",
  						config_file)));
! 		return false;
  	}
  
  	/*
--- 399,405 ----
  				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
  				 errmsg("could not open configuration file \"%s\": maximum nesting depth exceeded",
  						config_file)));
! 		return 1;
  	}
  
  	/*
***************
*** 407,420 **** ParseConfigFile(const char *config_file, const char *calling_file,
  				(errcode_for_file_access(),
  				 errmsg("could not open configuration file \"%s\": %m",
  						config_file)));
! 		return false;
  	}
  
! 	OK = ParseConfigFp(fp, config_file, depth, elevel, head_p, tail_p);
  
  	FreeFile(fp);
  
! 	return OK;
  }
  
  /*
--- 434,447 ----
  				(errcode_for_file_access(),
  				 errmsg("could not open configuration file \"%s\": %m",
  						config_file)));
! 		return 1;
  	}
  
! 	errorcount = ParseConfigFp(fp, config_file, depth, elevel, nerrors, head_p, tail_p);
  
  	FreeFile(fp);
  
! 	return errorcount;
  }
  
  /*
***************
*** 426,431 **** ParseConfigFile(const char *config_file, const char *calling_file,
--- 453,459 ----
   *	config_file: absolute or relative path of file to read
   *	depth: recursion depth (used only to prevent infinite recursion)
   *	elevel: error logging level determined by ProcessConfigFile()
+  *	nerrors: number of errors already seen while parsing previous config files
   * Output parameters:
   *	head_p, tail_p: head and tail of linked list of name/value pairs
   *
***************
*** 433,455 **** ParseConfigFile(const char *config_file, const char *calling_file,
   * recursion level.  On exit, they contain a list of name-value pairs read
   * from the input file(s).
   *
!  * Returns TRUE if successful, FALSE if an error occurred.  The error has
!  * already been ereport'd, it is only necessary for the caller to clean up
!  * its own state and release the name/value pairs list.
   *
   * Note: if elevel >= ERROR then an error will not return control to the
   * caller, and internal state such as open files will not be cleaned up.
   * This case occurs only during postmaster or standalone-backend startup,
   * where an error will lead to immediate process exit anyway; so there is
   * no point in contorting the code so it can clean up nicely.
   */
! bool
  ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
! 			  ConfigVariable **head_p, ConfigVariable **tail_p)
  {
- 	bool		OK = true;
  	YY_BUFFER_STATE lex_buffer;
! 	int			token;
  
  	/*
  	 * Parse
--- 461,490 ----
   * recursion level.  On exit, they contain a list of name-value pairs read
   * from the input file(s).
   *
!  * Returns 0 if successful, or the number of parsing errors found if any
!  * occurred.  The error(s) have already been ereport'd, it is only necessary
!  * for the caller to clean up its own state and release the name/value pairs
!  * list.
!  *
!  * If elevel < ERROR then we don't return immediately on the first error,
!  * although we do return after coming across 100 of them. This is to prevent
!  * trashing out logs when parsing a completely bogus file.
   *
   * Note: if elevel >= ERROR then an error will not return control to the
   * caller, and internal state such as open files will not be cleaned up.
   * This case occurs only during postmaster or standalone-backend startup,
   * where an error will lead to immediate process exit anyway; so there is
   * no point in contorting the code so it can clean up nicely.
+  *
+  * We use nerrors to break out early in case too many errors are found.
   */
! int
  ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
! 			  int nerrors, ConfigVariable **head_p, ConfigVariable **tail_p)
  {
  	YY_BUFFER_STATE lex_buffer;
! 	int			token,
! 				errorcount;
  
  	/*
  	 * Parse
***************
*** 458,463 **** ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
--- 493,499 ----
  	yy_switch_to_buffer(lex_buffer);
  
  	ConfigFileLineno = 1;
+ 	errorcount = 0;
  
  	/* This loop iterates once per logical line */
  	while ((token = yylex()))
***************
*** 509,523 **** ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
  			 */
  			unsigned int save_ConfigFileLineno = ConfigFileLineno;
  
! 			if (!ParseConfigFile(opt_value, config_file,
! 								 depth + 1, elevel,
! 								 head_p, tail_p))
! 			{
! 				pfree(opt_name);
! 				pfree(opt_value);
! 				OK = false;
! 				goto cleanup_exit;
! 			}
  			yy_switch_to_buffer(lex_buffer);
  			ConfigFileLineno = save_ConfigFileLineno;
  			pfree(opt_name);
--- 545,552 ----
  			 */
  			unsigned int save_ConfigFileLineno = ConfigFileLineno;
  
! 			errorcount += ParseConfigFile(opt_value, config_file, depth + 1,
! 										  elevel, errorcount, head_p, tail_p);
  			yy_switch_to_buffer(lex_buffer);
  			ConfigFileLineno = save_ConfigFileLineno;
  			pfree(opt_name);
***************
*** 576,602 **** ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
  		/* break out of loop if read EOF, else loop for next line */
  		if (token == 0)
  			break;
  	}
  
  	/* successful completion of parsing */
- 	goto cleanup_exit;
- 
-  parse_error:
- 	if (token == GUC_EOL || token == 0)
- 		ereport(elevel,
- 				(errcode(ERRCODE_SYNTAX_ERROR),
- 				 errmsg("syntax error in file \"%s\" line %u, near end of line",
- 						config_file, ConfigFileLineno - 1)));
- 	else
- 		ereport(elevel,
- 				(errcode(ERRCODE_SYNTAX_ERROR),
- 				 errmsg("syntax error in file \"%s\" line %u, near token \"%s\"",
- 						config_file, ConfigFileLineno, yytext)));
- 	OK = false;
- 
- cleanup_exit:
  	yy_delete_buffer(lex_buffer);
! 	return OK;
  }
  
  
--- 605,647 ----
  		/* break out of loop if read EOF, else loop for next line */
  		if (token == 0)
  			break;
+ 		/* skip over parse_error if we made it this far without errors */
+ 		continue;
+ 
+ 	parse_error:
+ 		if (token == GUC_EOL || token == 0)
+ 			ereport(elevel,
+ 					(errcode(ERRCODE_SYNTAX_ERROR),
+ 					 errmsg("syntax error in file \"%s\" line %u, near end of line",
+ 							config_file, ConfigFileLineno - 1)));
+ 		else
+ 			ereport(elevel,
+ 					(errcode(ERRCODE_SYNTAX_ERROR),
+ 					 errmsg("syntax error in file \"%s\" line %u, near token \"%s\"",
+ 							config_file, ConfigFileLineno, yytext)));
+ 		errorcount++;
+ 		/* fast forward till the next EOL/EOF */
+ 		while (token != 0 && token != GUC_EOL)
+ 			token = yylex();
+ 		
+ 		/* break out of loop on EOF */
+ 		if (token == 0)
+ 			break;
+ 		
+ 		/* avoid producing too much noise when parsing a bogus file */
+ 		if (errorcount + nerrors >= MAX_ERROR_REPORTS)
+ 		{
+ 			ereport(elevel,
+ 					(errcode(ERRCODE_SYNTAX_ERROR),
+ 					 errmsg("too many errors found, stopped processing file \"%s\"",
+ 							config_file)));
+ 			break;
+ 		}
  	}
  
  	/* successful completion of parsing */
  	yy_delete_buffer(lex_buffer);
! 	return errorcount;
  }
  
  
*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
***************
*** 5047,5053 **** config_enum_get_options(struct config_enum * record, const char *prefix,
   *
   * If there is an error (non-existing option, invalid value) then an
   * ereport(ERROR) is thrown *unless* this is called in a context where we
!  * don't want to ereport (currently, startup or SIGHUP config file reread).
   * In that case we write a suitable error message via ereport(LOG) and
   * return false. This is working around the deficiencies in the ereport
   * mechanism, so don't blame me.  In all other cases, the function
--- 5047,5053 ----
   *
   * If there is an error (non-existing option, invalid value) then an
   * ereport(ERROR) is thrown *unless* this is called in a context where we
!  * don't want to ereport (currently, settings defaults and config file read).
   * In that case we write a suitable error message via ereport(LOG) and
   * return false. This is working around the deficiencies in the ereport
   * mechanism, so don't blame me.  In all other cases, the function
***************
*** 5066,5072 **** set_config_option(const char *name, const char *value,
  	bool		prohibitValueChange = false;
  	bool		makeDefault;
  
! 	if (context == PGC_SIGHUP || source == PGC_S_DEFAULT)
  	{
  		/*
  		 * To avoid cluttering the log, only the postmaster bleats loudly
--- 5066,5072 ----
  	bool		prohibitValueChange = false;
  	bool		makeDefault;
  
! 	if (source == PGC_S_FILE || source == PGC_S_DEFAULT)
  	{
  		/*
  		 * To avoid cluttering the log, only the postmaster bleats loudly
*** a/src/include/utils/guc.h
--- b/src/include/utils/guc.h
***************
*** 110,120 **** typedef struct ConfigVariable
  	struct ConfigVariable *next;
  } ConfigVariable;
  
! extern bool ParseConfigFile(const char *config_file, const char *calling_file,
! 				int depth, int elevel,
  				ConfigVariable **head_p, ConfigVariable **tail_p);
! extern bool ParseConfigFp(FILE *fp, const char *config_file,
! 			  int depth, int elevel,
  			  ConfigVariable **head_p, ConfigVariable **tail_p);
  extern void FreeConfigVariables(ConfigVariable *list);
  
--- 110,120 ----
  	struct ConfigVariable *next;
  } ConfigVariable;
  
! extern int ParseConfigFile(const char *config_file, const char *calling_file,
! 				int depth, int elevel, int nerrors,
  				ConfigVariable **head_p, ConfigVariable **tail_p);
! extern int ParseConfigFp(FILE *fp, const char *config_file,
! 			  int depth, int elevel, int nerrors,
  			  ConfigVariable **head_p, ConfigVariable **tail_p);
  extern void FreeConfigVariables(ConfigVariable *list);
  
