summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--loadparm.c32
-rw-r--r--params.c107
-rw-r--r--rsyncd.conf.yo43
3 files changed, 166 insertions, 16 deletions
diff --git a/loadparm.c b/loadparm.c
index c5408409..4b3741f9 100644
--- a/loadparm.c
+++ b/loadparm.c
@@ -154,6 +154,11 @@ typedef struct {
BOOL write_only;
} section;
+typedef struct {
+ global g;
+ section s;
+} global_and_section;
+
/* This is a default section used to prime a sections structure. In order
* to make these easy to keep sorted in the same way as the variables
* above, use the variable name in the leading comment, including a
@@ -205,6 +210,7 @@ static section sDefault = {
/* local variables */
static item_list section_list = EMPTY_ITEM_LIST;
+static item_list section_stack = EMPTY_ITEM_LIST;
static int iSectionIndex = -1;
static BOOL bInGlobalSection = True;
@@ -676,7 +682,29 @@ static BOOL do_parameter(char *parmname, char *parmvalue)
* Returns True on success, False on failure. */
static BOOL do_section(char *sectionname)
{
- BOOL isglobal = strwicmp(sectionname, GLOBAL_NAME) == 0;
+ BOOL isglobal;
+
+ if (*sectionname == ']') { /* A special push/pop/reset directive from params.c */
+ bInGlobalSection = 1;
+ if (strcmp(sectionname+1, "push") == 0) {
+ global_and_section *gs = EXPAND_ITEM_LIST(&section_stack, global_and_section, 2);
+ memcpy(&gs->g, &Globals, sizeof Globals);
+ memcpy(&gs->s, &sDefault, sizeof sDefault);
+ } else if (strcmp(sectionname+1, "pop") == 0
+ || strcmp(sectionname+1, "reset") == 0) {
+ global_and_section *gs = ((global_and_section *)section_stack.items) + section_stack.count - 1;
+ if (!section_stack.count)
+ return False;
+ memcpy(&Globals, &gs->g, sizeof Globals);
+ memcpy(&sDefault, &gs->s, sizeof sDefault);
+ if (sectionname[1] == 'p')
+ section_stack.count--;
+ } else
+ return False;
+ return True;
+ }
+
+ isglobal = strwicmp(sectionname, GLOBAL_NAME) == 0;
/* if we were in a global section then do the local inits */
if (bInGlobalSection && !isglobal)
@@ -714,7 +742,7 @@ static BOOL do_section(char *sectionname)
/* Load the modules from the config file. Return True on success,
* False on failure. */
-BOOL lp_load(char *pszFname, int globals_only)
+int lp_load(char *pszFname, int globals_only)
{
pstring n2;
diff --git a/params.c b/params.c
index 7610ac78..5d7b00de 100644
--- a/params.c
+++ b/params.c
@@ -93,6 +93,8 @@
static char *bufr = NULL;
static int bSize = 0;
+static BOOL (*the_sfunc)(char *);
+static BOOL (*the_pfunc)(char *, char *);
/* -------------------------------------------------------------------------- **
* Functions...
@@ -406,7 +408,71 @@ static BOOL Parameter( FILE *InFile, BOOL (*pfunc)(char *, char *), int c )
return( pfunc( bufr, &bufr[vstart] ) ); /* Pass name & value to pfunc(). */
} /* Parameter */
-static BOOL Parse( FILE *InFile,
+static int name_cmp(const void *n1, const void *n2)
+{
+ return strcmp(*(char * const *)n1, *(char * const *)n2);
+}
+
+static int include_config(char *include, int manage_globals)
+{
+ item_list conf_list;
+ struct dirent *di;
+ char buf[MAXPATHLEN], **bpp;
+ int ret = 1;
+ size_t j;
+ DIR *d;
+
+ memset(&conf_list, 0, sizeof conf_list);
+
+ if ((d = opendir(include)) != NULL) {
+ while ((di = readdir(d)) != NULL) {
+ char *dname = d_name(di);
+ if (!wildmatch("*.conf", dname))
+ continue;
+ bpp = EXPAND_ITEM_LIST(&conf_list, char *, 32);
+ pathjoin(buf, sizeof buf, include, dname);
+ *bpp = strdup(buf);
+ }
+ closedir(d);
+ } else {
+ STRUCT_STAT sb;
+ if (stat(include, &sb) < 0)
+ return 0;
+ bpp = EXPAND_ITEM_LIST(&conf_list, char *, 1);
+ *bpp = strdup(include);
+ }
+
+ if (conf_list.count > 1)
+ qsort(conf_list.items, conf_list.count, sizeof (char *), name_cmp);
+
+ bpp = conf_list.items;
+ for (j = 0; j < conf_list.count; j++) {
+ if (manage_globals && the_sfunc)
+ the_sfunc(j == 0 ? "]push" : "]reset");
+ if ((ret = pm_process(bpp[j], the_sfunc, the_pfunc)) != 1)
+ break;
+ }
+
+ if (manage_globals && the_sfunc && conf_list.count)
+ the_sfunc("]pop");
+
+ for (j = 0; j < conf_list.count; j++)
+ free(bpp[j]);
+
+ return ret;
+}
+
+static int parse_directives(char *name, char *val)
+{
+ if (strcasecmp(name, "include") == 0)
+ return include_config(val, 1);
+ if (strcasecmp(name, "merge") == 0)
+ return include_config(val, 0);
+ rprintf(FLOG, "Unknown directive: &%s.\n", name);
+ return 0;
+}
+
+static int Parse( FILE *InFile,
BOOL (*sfunc)(char *),
BOOL (*pfunc)(char *, char *) )
/* ------------------------------------------------------------------------ **
@@ -418,7 +484,8 @@ static BOOL Parse( FILE *InFile,
* pfunc - Function to be called when a parameter is scanned.
* See Parameter().
*
- * Output: True if the file was successfully scanned, else False.
+ * Output: 1 if the file was successfully scanned, 2 if the file was
+ * scanned until a section header with no section function, else 0.
*
* Notes: The input can be viewed in terms of 'lines'. There are four
* types of lines:
@@ -427,7 +494,7 @@ static BOOL Parse( FILE *InFile,
* The remainder of the line is ignored.
* Section - First non-whitespace character is a '['.
* Parameter - The default case.
- *
+ *
* ------------------------------------------------------------------------ **
*/
{
@@ -448,24 +515,35 @@ static BOOL Parse( FILE *InFile,
break;
case '[': /* Section Header. */
- if (!sfunc) return True;
- if( !Section( InFile, sfunc ) )
- return( False );
- c = EatWhitespace( InFile );
- break;
+ if (!sfunc)
+ return 2;
+ if( !Section( InFile, sfunc ) )
+ return 0;
+ c = EatWhitespace( InFile );
+ break;
case '\\': /* Bogus backslash. */
c = EatWhitespace( InFile );
break;
+ case '&': /* Handle directives */
+ the_sfunc = sfunc;
+ the_pfunc = pfunc;
+ c = EatWhitespace( InFile );
+ c = Parameter( InFile, parse_directives, c );
+ if (c != 1)
+ return c;
+ c = EatWhitespace( InFile );
+ break;
+
default: /* Parameter line. */
if( !Parameter( InFile, pfunc, c ) )
- return( False );
+ return 0;
c = EatWhitespace( InFile );
break;
}
}
- return( True );
+ return 1;
} /* Parse */
static FILE *OpenConfFile( char *FileName )
@@ -499,7 +577,7 @@ static FILE *OpenConfFile( char *FileName )
return( OpenedFile );
} /* OpenConfFile */
-BOOL pm_process( char *FileName,
+int pm_process( char *FileName,
BOOL (*sfunc)(char *),
BOOL (*pfunc)(char *, char *) )
/* ------------------------------------------------------------------------ **
@@ -511,7 +589,8 @@ BOOL pm_process( char *FileName,
* pfunc - A pointer to a function that will be called when
* a parameter name and value are discovered.
*
- * Output: TRUE if the file was successfully parsed, else FALSE.
+ * Output: 1 if the file was successfully parsed, 2 if parsing ended at a
+ * section header w/o a section function, else 0.
*
* ------------------------------------------------------------------------ **
*/
@@ -549,10 +628,10 @@ BOOL pm_process( char *FileName,
if( !result ) /* Generic failure. */
{
rprintf(FLOG, "%s Failed. Error returned from params.c:parse().\n", func);
- return( False );
+ return 0;
}
- return( True ); /* Generic success. */
+ return result;
} /* pm_process */
/* -------------------------------------------------------------------------- */
diff --git a/rsyncd.conf.yo b/rsyncd.conf.yo
index b3ebd87e..9c94bbfa 100644
--- a/rsyncd.conf.yo
+++ b/rsyncd.conf.yo
@@ -616,6 +616,49 @@ module's uid/gid setting) without any chroot restrictions.
enddit()
+manpagesection(CONFIG DIRECTIVES)
+
+There are currently two config directives available that allow a config file to
+incorporate the contents of other files: bf(&include) and bf(&merge). Both
+allow a reference to either a file or a directory. They differ in how
+segregated the file's contents are considered to be. The bf(&include)
+directive treats each file as more distinct, with each one inheriting the
+defaults of the parent file, and starting the parameter parsing as
+globals/defaults. The bf(&merge) directive, on the other hand, treats the
+file's contents as if it were simply inserted in place of the directive, and
+thus it can contain parameters that can be set inside a parent file's module
+settings, or whatever you like.
+
+When an bf(&include) or bf(&merge) directive refers to a directory, it will read
+in all the bf(*.conf) files contained inside that directory (without any
+recursive scanning), with the files sorted into alpha order. So, if you have a
+directory named "rsyncd.d" with the files "foo.conf", "bar.conf", and
+"baz.conf" inside it, this directive:
+
+verb( &include = /path/rsyncd.d )
+
+would be the same as this set of directives:
+
+verb( &include = /path/rsyncd.d/bar.conf
+ &include = /path/rsyncd.d/baz.conf
+ &include = /path/rsyncd.d/foo.conf )
+
+except that it adjusts as files are added and removed from the directory.
+
+The advantage of the bf(&include) directive is that you can define one or more
+modules in a separate file with only the defaults you set in the parent file
+affecting it, so you don't need to worry about the settings of a prior include
+file changing a default. For instance, this is a useful /etc/rsyncd.conf file:
+
+verb( port = 873
+ log file = /path/rsync.log
+ pid file = /var/lock/rsync.lock
+
+ &include /etc/rsyncd.d )
+
+The advantage of the bf(&merge) directive is that you can load config snippets
+that can be included into multiple module definitions.
+
manpagesection(AUTHENTICATION STRENGTH)
The authentication protocol used in rsync is a 128 bit MD4 based