@@ -362,6 +362,39 @@ ProcessConfigFile(GucContext context)
362362}
363363}
364364
365+ /*
366+ * Given a configuration file or directory location that may be a relative
367+ * path, return an absolute one. We consider the location to be relative to
368+ * the directory holding the calling file.
369+ */
370+ static char *
371+ AbsoluteConfigLocation (const char *location,const char *calling_file)
372+ {
373+ char abs_path[MAXPGPATH];
374+
375+ if (is_absolute_path (location))
376+ return pstrdup (location);
377+ else
378+ {
379+ if (calling_file !=NULL )
380+ {
381+ strlcpy (abs_path, calling_file,sizeof (abs_path));
382+ get_parent_directory (abs_path);
383+ join_path_components (abs_path, abs_path, location);
384+ canonicalize_path (abs_path);
385+ }
386+ else
387+ {
388+ /*
389+ * calling_file is NULL, we make an absolute path from $PGDATA
390+ */
391+ join_path_components (abs_path, data_directory, location);
392+ canonicalize_path (abs_path);
393+ }
394+ return pstrdup (abs_path);
395+ }
396+ }
397+
365398/*
366399 * Read and parse a single configuration file. This function recurses
367400 * to handle "include" directives.
@@ -378,7 +411,6 @@ ParseConfigFile(const char *config_file, const char *calling_file, bool strict,
378411{
379412bool OK =true ;
380413FILE *fp;
381- char abs_path[MAXPGPATH];
382414
383415/*
384416 * Reject too-deep include nesting depth. This is just a safety check
@@ -394,31 +426,7 @@ ParseConfigFile(const char *config_file, const char *calling_file, bool strict,
394426return false ;
395427}
396428
397- /*
398- * If config_file is a relative path, convert to absolute. We consider
399- * it to be relative to the directory holding the calling file.
400- */
401- if (!is_absolute_path (config_file))
402- {
403- if (calling_file !=NULL )
404- {
405- strlcpy (abs_path, calling_file,sizeof (abs_path));
406- get_parent_directory (abs_path);
407- join_path_components (abs_path, abs_path, config_file);
408- canonicalize_path (abs_path);
409- config_file = abs_path;
410- }
411- else
412- {
413- /*
414- * calling_file is NULL, we make an absolute path from $PGDATA
415- */
416- join_path_components (abs_path, data_directory, config_file);
417- canonicalize_path (abs_path);
418- config_file = abs_path;
419- }
420- }
421-
429+ config_file =AbsoluteConfigLocation (config_file,calling_file);
422430fp =AllocateFile (config_file," r" );
423431if (!fp)
424432{
@@ -563,20 +571,35 @@ ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
563571}
564572
565573/* OK, process the option name and value */
566- if (guc_name_compare (opt_name," include_if_exists " ) ==0 )
574+ if (guc_name_compare (opt_name," include_dir " ) ==0 )
567575{
568576/*
569- * Aninclude_if_exists directive isn't a variable and should be
577+ * Aninclude_dir directive isn't a variable and should be
570578 * processed immediately.
571579 */
572- if (!ParseConfigFile (opt_value, config_file, false ,
580+ if (!ParseConfigDirectory (opt_value, config_file,
573581 depth +1 , elevel,
574582 head_p, tail_p))
575583OK =false ;
576584yy_switch_to_buffer (lex_buffer);
585+ ConfigFileLineno = save_ConfigFileLineno;
577586pfree (opt_name);
578587pfree (opt_value);
579588}
589+ else if (guc_name_compare (opt_name," include_if_exists" ) ==0 )
590+ {
591+ /*
592+ * An include_if_exists directive isn't a variable and should be
593+ * processed immediately.
594+ */
595+ if (!ParseConfigFile (opt_value, config_file,false ,
596+ depth +1 , elevel,
597+ head_p, tail_p))
598+ OK =false ;
599+ yy_switch_to_buffer (lex_buffer);
600+ pfree (opt_name);
601+ pfree (opt_value);
602+ }
580603else if (guc_name_compare (opt_name," include" ) ==0 )
581604{
582605/*
@@ -665,6 +688,111 @@ cleanup:
665688return OK;
666689}
667690
691+ /*
692+ * Read and parse all config files in a subdirectory in alphabetical order
693+ */
694+ bool
695+ ParseConfigDirectory (const char *includedir,
696+ const char *calling_file,
697+ int depth,int elevel,
698+ ConfigVariable **head_p,
699+ ConfigVariable **tail_p)
700+ {
701+ char *directory;
702+ DIR *d;
703+ struct dirent *de;
704+ char **filenames =NULL ;
705+ int num_filenames =0 ;
706+ int size_filenames =0 ;
707+ bool status;
708+
709+ directory =AbsoluteConfigLocation (includedir, calling_file);
710+ d =AllocateDir (directory);
711+ if (d ==NULL )
712+ {
713+ ereport (elevel,
714+ (errcode_for_file_access (),
715+ errmsg (" could not open configuration directory\" %s\" : %m" ,
716+ directory)));
717+ return false ;
718+ }
719+
720+ /*
721+ * Read the directory and put the filenames in an array, so we can sort
722+ * them prior to processing the contents.
723+ */
724+ while ((de =ReadDir (d, directory)) !=NULL )
725+ {
726+ struct stat st;
727+ char filename[MAXPGPATH];
728+
729+ /*
730+ * Only parse files with names ending in ".conf". Explicitly reject
731+ * files starting with ".". This excludes things like "." and "..",
732+ * as well as typical hidden files, backup files, and editor debris.
733+ */
734+ if (strlen (de->d_name ) <6 )
735+ continue ;
736+ if (de->d_name [0 ] ==' .' )
737+ continue ;
738+ if (strcmp (de->d_name +strlen (de->d_name ) -5 ," .conf" ) !=0 )
739+ continue ;
740+
741+ join_path_components (filename, directory, de->d_name );
742+ canonicalize_path (filename);
743+ if (stat (filename, &st) ==0 )
744+ {
745+ if (!S_ISDIR (st.st_mode ))
746+ {
747+ /* Add file to list, increasing its size in blocks of 32 */
748+ if (num_filenames == size_filenames)
749+ {
750+ size_filenames +=32 ;
751+ if (num_filenames ==0 )
752+ /* Must initialize, repalloc won't take NULL input */
753+ filenames =palloc (size_filenames *sizeof (char *));
754+ else
755+ filenames =repalloc (filenames, size_filenames *sizeof (char *));
756+ }
757+ filenames[num_filenames] =pstrdup (filename);
758+ num_filenames++;
759+ }
760+ }
761+ else
762+ {
763+ /*
764+ * stat does not care about permissions, so the most likely reason
765+ * a file can't be accessed now is if it was removed between the
766+ * directory listing and now.
767+ */
768+ ereport (elevel,
769+ (errcode_for_file_access (),
770+ errmsg (" could not stat file\" %s\" : %m" ,
771+ filename)));
772+ return false ;
773+ }
774+ }
775+
776+ if (num_filenames >0 )
777+ {
778+ int i;
779+ qsort (filenames, num_filenames,sizeof (char *), pg_qsort_strcmp);
780+ for (i =0 ; i < num_filenames; i++)
781+ {
782+ if (!ParseConfigFile (filenames[i],NULL ,true ,
783+ depth, elevel, head_p, tail_p))
784+ {
785+ status =false ;
786+ goto cleanup;
787+ }
788+ }
789+ }
790+ status =true ;
791+
792+ cleanup:
793+ FreeDir (d);
794+ return status;
795+ }
668796
669797/*
670798 * Free a list of ConfigVariables, including the names and the values