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 {
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;
......
......@@ -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 */
/* -------------------------------------------------------------------------- */
......
......@@ -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
......
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