@@ -362,6 +362,39 @@ ProcessConfigFile(GucContext context)
362
362
}
363
363
}
364
364
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
+
365
398
/*
366
399
* Read and parse a single configuration file. This function recurses
367
400
* to handle "include" directives.
@@ -378,7 +411,6 @@ ParseConfigFile(const char *config_file, const char *calling_file, bool strict,
378
411
{
379
412
bool OK = true ;
380
413
FILE *fp;
381
- char abs_path[MAXPGPATH];
382
414
383
415
/*
384
416
* 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,
394
426
return false ;
395
427
}
396
428
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);
422
430
fp = AllocateFile (config_file, " r" );
423
431
if (!fp)
424
432
{
@@ -563,20 +571,35 @@ ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
563
571
}
564
572
565
573
/* 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 )
567
575
{
568
576
/*
569
- * An include_if_exists directive isn't a variable and should be
577
+ * An include_dir directive isn't a variable and should be
570
578
* processed immediately.
571
579
*/
572
- if (!ParseConfigFile (opt_value, config_file, false ,
580
+ if (!ParseConfigDirectory (opt_value, config_file,
573
581
depth + 1 , elevel,
574
582
head_p, tail_p))
575
583
OK = false ;
576
584
yy_switch_to_buffer (lex_buffer);
585
+ ConfigFileLineno = save_ConfigFileLineno;
577
586
pfree (opt_name);
578
587
pfree (opt_value);
579
588
}
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
+ }
580
603
else if (guc_name_compare (opt_name, " include" ) == 0 )
581
604
{
582
605
/*
@@ -665,6 +688,111 @@ cleanup:
665
688
return OK;
666
689
}
667
690
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
+ }
668
796
669
797
/*
670
798
* Free a list of ConfigVariables, including the names and the values
0 commit comments