Commit 8a3ddcfc authored by Wayne Davison's avatar Wayne Davison

Added &include and &merge config-file directives that allow the

daemon's config file incorporate the contents of other files.
parent c9604e21
...@@ -154,6 +154,11 @@ typedef struct { ...@@ -154,6 +154,11 @@ typedef struct {
BOOL write_only; BOOL write_only;
} section; } section;
typedef struct {
global g;
section s;
} global_and_section;
/* This is a default section used to prime a sections structure. In order /* 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 * 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 * above, use the variable name in the leading comment, including a
...@@ -205,6 +210,7 @@ static section sDefault = { ...@@ -205,6 +210,7 @@ static section sDefault = {
/* local variables */ /* local variables */
static item_list section_list = EMPTY_ITEM_LIST; static item_list section_list = EMPTY_ITEM_LIST;
static item_list section_stack = EMPTY_ITEM_LIST;
static int iSectionIndex = -1; static int iSectionIndex = -1;
static BOOL bInGlobalSection = True; static BOOL bInGlobalSection = True;
...@@ -676,7 +682,29 @@ static BOOL do_parameter(char *parmname, char *parmvalue) ...@@ -676,7 +682,29 @@ static BOOL do_parameter(char *parmname, char *parmvalue)
* Returns True on success, False on failure. */ * Returns True on success, False on failure. */
static BOOL do_section(char *sectionname) 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 we were in a global section then do the local inits */
if (bInGlobalSection && !isglobal) if (bInGlobalSection && !isglobal)
...@@ -714,7 +742,7 @@ static BOOL do_section(char *sectionname) ...@@ -714,7 +742,7 @@ static BOOL do_section(char *sectionname)
/* Load the modules from the config file. Return True on success, /* Load the modules from the config file. Return True on success,
* False on failure. */ * False on failure. */
BOOL lp_load(char *pszFname, int globals_only) int lp_load(char *pszFname, int globals_only)
{ {
pstring n2; pstring n2;
......
...@@ -93,6 +93,8 @@ ...@@ -93,6 +93,8 @@
static char *bufr = NULL; static char *bufr = NULL;
static int bSize = 0; static int bSize = 0;
static BOOL (*the_sfunc)(char *);
static BOOL (*the_pfunc)(char *, char *);
/* -------------------------------------------------------------------------- ** /* -------------------------------------------------------------------------- **
* Functions... * Functions...
...@@ -406,7 +408,71 @@ static BOOL Parameter( FILE *InFile, BOOL (*pfunc)(char *, char *), int c ) ...@@ -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(). */ return( pfunc( bufr, &bufr[vstart] ) ); /* Pass name & value to pfunc(). */
} /* Parameter */ } /* 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 (*sfunc)(char *),
BOOL (*pfunc)(char *, char *) ) BOOL (*pfunc)(char *, char *) )
/* ------------------------------------------------------------------------ ** /* ------------------------------------------------------------------------ **
...@@ -418,7 +484,8 @@ static BOOL Parse( FILE *InFile, ...@@ -418,7 +484,8 @@ static BOOL Parse( FILE *InFile,
* pfunc - Function to be called when a parameter is scanned. * pfunc - Function to be called when a parameter is scanned.
* See Parameter(). * 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 * Notes: The input can be viewed in terms of 'lines'. There are four
* types of lines: * types of lines:
...@@ -448,9 +515,10 @@ static BOOL Parse( FILE *InFile, ...@@ -448,9 +515,10 @@ static BOOL Parse( FILE *InFile,
break; break;
case '[': /* Section Header. */ case '[': /* Section Header. */
if (!sfunc) return True; if (!sfunc)
return 2;
if( !Section( InFile, sfunc ) ) if( !Section( InFile, sfunc ) )
return( False ); return 0;
c = EatWhitespace( InFile ); c = EatWhitespace( InFile );
break; break;
...@@ -458,14 +526,24 @@ static BOOL Parse( FILE *InFile, ...@@ -458,14 +526,24 @@ static BOOL Parse( FILE *InFile,
c = EatWhitespace( InFile ); c = EatWhitespace( InFile );
break; 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. */ default: /* Parameter line. */
if( !Parameter( InFile, pfunc, c ) ) if( !Parameter( InFile, pfunc, c ) )
return( False ); return 0;
c = EatWhitespace( InFile ); c = EatWhitespace( InFile );
break; break;
} }
} }
return( True ); return 1;
} /* Parse */ } /* Parse */
static FILE *OpenConfFile( char *FileName ) static FILE *OpenConfFile( char *FileName )
...@@ -499,7 +577,7 @@ static FILE *OpenConfFile( char *FileName ) ...@@ -499,7 +577,7 @@ static FILE *OpenConfFile( char *FileName )
return( OpenedFile ); return( OpenedFile );
} /* OpenConfFile */ } /* OpenConfFile */
BOOL pm_process( char *FileName, int pm_process( char *FileName,
BOOL (*sfunc)(char *), BOOL (*sfunc)(char *),
BOOL (*pfunc)(char *, char *) ) BOOL (*pfunc)(char *, char *) )
/* ------------------------------------------------------------------------ ** /* ------------------------------------------------------------------------ **
...@@ -511,7 +589,8 @@ BOOL pm_process( char *FileName, ...@@ -511,7 +589,8 @@ BOOL pm_process( char *FileName,
* pfunc - A pointer to a function that will be called when * pfunc - A pointer to a function that will be called when
* a parameter name and value are discovered. * 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, ...@@ -549,10 +628,10 @@ BOOL pm_process( char *FileName,
if( !result ) /* Generic failure. */ if( !result ) /* Generic failure. */
{ {
rprintf(FLOG, "%s Failed. Error returned from params.c:parse().\n", func); rprintf(FLOG, "%s Failed. Error returned from params.c:parse().\n", func);
return( False ); return 0;
} }
return( True ); /* Generic success. */ return result;
} /* pm_process */ } /* pm_process */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
......
...@@ -616,6 +616,49 @@ module's uid/gid setting) without any chroot restrictions. ...@@ -616,6 +616,49 @@ module's uid/gid setting) without any chroot restrictions.
enddit() 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) manpagesection(AUTHENTICATION STRENGTH)
The authentication protocol used in rsync is a 128 bit MD4 based The authentication protocol used in rsync is a 128 bit MD4 based
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment