Diff for /embedaddon/rsync/loadparm.c between versions 1.1.1.1 and 1.1.1.4

version 1.1.1.1, 2012/02/17 15:09:30 version 1.1.1.4, 2021/03/17 00:32:36
Line 11 Line 11
  *   *
  * You should have received a copy of the GNU General Public License along   * You should have received a copy of the GNU General Public License along
  * with this program; if not, visit the http://fsf.org website.   * with this program; if not, visit the http://fsf.org website.
 */ *
 * This is based on loadparm.c from Samba, written by Andrew Tridgell
/* This is based on loadparm.c from Samba, written by Andrew Tridgell 
  * and Karl Auer.  Some of the changes are:   * and Karl Auer.  Some of the changes are:
  *   *
  * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>   * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
 * Copyright (C) 2003-2009 Wayne Davison <wayned@samba.org> * Copyright (C) 2003-2020 Wayne Davison
  */   */
   
 /* Load parameters.  /* Load parameters.
  *   *
  *  This module provides suitable callback functions for the params   *  This module provides suitable callback functions for the params
 *  module. It builds the internal table of service details which is *  module. It builds the internal table of section details which is
  *  then used by the rest of the server.   *  then used by the rest of the server.
  *   *
  * To add a parameter:   * To add a parameter:
  *   *
 * 1) add it to the global or service structure definition * 1) add it to the global_vars or local_vars structure definition
  * 2) add it to the parm_table   * 2) add it to the parm_table
  * 3) add it to the list of available functions (eg: using FN_GLOBAL_STRING())   * 3) add it to the list of available functions (eg: using FN_GLOBAL_STRING())
 * 4) If it's a global then initialise it in init_globals. If a local * 4) initialise it in the Defaults static structure
 *    (ie. service) parameter then initialise it in the sDefault structure 
  *   *
  *  
  * Notes:   * Notes:
 *   The configuration file is processed sequentially for speed. It is NOT *   The configuration file is processed sequentially for speed. For this
 *   accessed randomly as happens in 'real' Windows. For this reason, there *   reason, there is a fair bit of sequence-dependent code here - ie., code
 *   is a fair bit of sequence-dependent code here - ie., code which assumes *   which assumes that certain things happen before others. In particular, the
 *   that certain things happen before others. In particular, the code which *   code which happens at the boundary between sections is delicately poised,
 *   happens at the boundary between sections is delicately poised, so be *   so be careful!
 *   careful! 
 * 
  */   */
   
 /* TODO: Parameter to set debug level on server. */  
   
 #include "rsync.h"  #include "rsync.h"
   #include "itypes.h"
 #include "ifuncs.h"  #include "ifuncs.h"
#define PTR_DIFF(p1,p2) ((ptrdiff_t)(((char *)(p1)) - (char *)(p2)))#include "default-dont-compress.h"
#define strequal(a,b) (strcasecmp(a,b)==0) 
#define BOOLSTR(b) ((b) ? "Yes" : "No") 
typedef char pstring[1024]; 
#define pstrcpy(a,b) strlcpy(a,b,sizeof(pstring)) 
   
   extern item_list dparam_list;
   
   #define strequal(a, b) (strcasecmp(a, b)==0)
   
 #ifndef LOG_DAEMON  #ifndef LOG_DAEMON
 #define LOG_DAEMON 0  #define LOG_DAEMON 0
 #endif  #endif
   
 #define DEFAULT_DONT_COMPRESS "*.gz *.zip *.z *.rpm *.deb *.iso *.bz2" \  
         " *.t[gb]z *.7z *.mp[34] *.mov *.avi *.ogg *.jpg *.jpeg"  
   
 /* the following are used by loadparm for option lists */  /* the following are used by loadparm for option lists */
typedef enumtypedef enum {
{        P_BOOL, P_BOOLREV, P_BOOL3, P_CHAR, P_INTEGER,
        P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,        P_OCTAL, P_PATH, P_STRING, P_ENUM
        P_PATH,P_STRING,P_GSTRING,P_ENUM,P_SEP 
 } parm_type;  } parm_type;
   
typedef enumtypedef enum {
{        P_LOCAL, P_GLOBAL, P_NONE
        P_LOCAL,P_GLOBAL,P_SEPARATOR,P_NONE 
 } parm_class;  } parm_class;
   
 struct enum_list {  struct enum_list {
Line 79  struct enum_list { Line 68  struct enum_list {
         char *name;          char *name;
 };  };
   
struct parm_structstruct parm_struct {
{ 
         char *label;          char *label;
         parm_type type;          parm_type type;
         parm_class class;          parm_class class;
Line 94  struct parm_struct Line 82  struct parm_struct
 #endif  #endif
   
 /* some helpful bits */  /* some helpful bits */
#define pSERVICE(i) ServicePtrs[i]#define iSECTION(i) ((local_vars*)section_list.items)[i]
#define iSERVICE(i) (*pSERVICE(i))#define LP_SNUM_OK(i) ((i) >= 0 && (i) < (int)section_list.count)
#define LP_SNUM_OK(iService) (((iService) >= 0) && ((iService) < iNumServices))#define SECTION_PTR(s, p) (((char*)(s)) + (ptrdiff_t)(((char*)(p))-(char*)&Vars.l))
   
/*/* Stack of "Vars" values used by the &include directive. */
 * This structure describes global (ie., server-wide) parameters.static item_list Vars_stack = EMPTY_ITEM_LIST;
 */ 
typedef struct 
{ 
        char *bind_address; 
        char *motd_file; 
        char *pid_file; 
        char *socket_options; 
   
        int rsync_port;/* The array of section values that holds all the defined modules. */
} global;static item_list section_list = EMPTY_ITEM_LIST;
   
static global Globals;static int iSectionIndex = -1;
 
 
/* 
 * This structure describes a single service.  Their order must match the 
 * initializers below, which you can accomplish by keeping each sub-section 
 * sorted.  (e.g. in vim, just visually select each subsection and use !sort.) 
 */ 
typedef struct 
{ 
        char *auth_users; 
        char *charset; 
        char *comment; 
        char *dont_compress; 
        char *exclude; 
        char *exclude_from; 
        char *filter; 
        char *gid; 
        char *hosts_allow; 
        char *hosts_deny; 
        char *include; 
        char *include_from; 
        char *incoming_chmod; 
        char *lock_file; 
        char *log_file; 
        char *log_format; 
        char *name; 
        char *outgoing_chmod; 
        char *path; 
        char *postxfer_exec; 
        char *prexfer_exec; 
        char *refuse_options; 
        char *secrets_file; 
        char *temp_dir; 
        char *uid; 
 
        int max_connections; 
        int max_verbosity; 
        int syslog_facility; 
        int timeout; 
 
        BOOL fake_super; 
        BOOL ignore_errors; 
        BOOL ignore_nonreadable; 
        BOOL list; 
        BOOL munge_symlinks; 
        BOOL numeric_ids; 
        BOOL read_only; 
        BOOL strict_modes; 
        BOOL transfer_logging; 
        BOOL use_chroot; 
        BOOL write_only; 
} service; 
 
 
/* This is a default service used to prime a services 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 
 * trailing ';' (to avoid a sorting problem with trailing digits). */ 
static service sDefault = 
{ 
 /* auth_users; */              NULL, 
 /* charset; */                 NULL, 
 /* comment; */                 NULL, 
 /* dont_compress; */           DEFAULT_DONT_COMPRESS, 
 /* exclude; */                 NULL, 
 /* exclude_from; */            NULL, 
 /* filter; */                  NULL, 
 /* gid; */                     NOBODY_GROUP, 
 /* hosts_allow; */             NULL, 
 /* hosts_deny; */              NULL, 
 /* include; */                 NULL, 
 /* include_from; */            NULL, 
 /* incoming_chmod; */          NULL, 
 /* lock_file; */               DEFAULT_LOCK_FILE, 
 /* log_file; */                NULL, 
 /* log_format; */              "%o %h [%a] %m (%u) %f %l", 
 /* name; */                    NULL, 
 /* outgoing_chmod; */          NULL, 
 /* path; */                    NULL, 
 /* postxfer_exec; */           NULL, 
 /* prexfer_exec; */            NULL, 
 /* refuse_options; */          NULL, 
 /* secrets_file; */            NULL, 
 /* temp_dir; */                NULL, 
 /* uid; */                     NOBODY_USER, 
 
 /* max_connections; */         0, 
 /* max_verbosity; */           1, 
 /* syslog_facility; */         LOG_DAEMON, 
 /* timeout; */                 0, 
 
 /* fake_super; */              False, 
 /* ignore_errors; */           False, 
 /* ignore_nonreadable; */      False, 
 /* list; */                    True, 
 /* munge_symlinks; */          (BOOL)-1, 
 /* numeric_ids; */             (BOOL)-1, 
 /* read_only; */               True, 
 /* strict_modes; */            True, 
 /* transfer_logging; */        False, 
 /* use_chroot; */              True, 
 /* write_only; */              False, 
}; 
 
 
 
/* local variables */ 
static service **ServicePtrs = NULL; 
static int iNumServices = 0; 
static int iServiceIndex = 0; 
 static BOOL bInGlobalSection = True;  static BOOL bInGlobalSection = True;
   
#define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))static struct enum_list enum_syslog_facility[] = {
 
static struct enum_list enum_facilities[] = { 
 #ifdef LOG_AUTH  #ifdef LOG_AUTH
         { LOG_AUTH, "auth" },          { LOG_AUTH, "auth" },
 #endif  #endif
Line 290  static struct enum_list enum_facilities[] = { Line 159  static struct enum_list enum_facilities[] = {
 #ifdef LOG_LOCAL7  #ifdef LOG_LOCAL7
         { LOG_LOCAL7, "local7" },          { LOG_LOCAL7, "local7" },
 #endif  #endif
        { -1, NULL }};        { -1, NULL }
 };
   
static struct enum_list enum_checksum_files[] = {
/* note that we do not initialise the defaults union - it is not allowed in ANSI C */        { CSF_IGNORE_FILES, "none" },
static struct parm_struct parm_table[] =        { CSF_LAX_MODE, "lax" },
{        { CSF_STRICT_MODE, "strict" },
 {"address",           P_STRING, P_GLOBAL,&Globals.bind_address,       NULL,0},        { CSF_LAX_MODE|CSF_UPDATE, "+lax" },
 {"motd file",         P_STRING, P_GLOBAL,&Globals.motd_file,          NULL,0},        { CSF_STRICT_MODE|CSF_UPDATE, "+strict" },
 {"pid file",          P_STRING, P_GLOBAL,&Globals.pid_file,           NULL,0},        { CSF_LAX_MODE|CSF_UPDATE|CSF_AFFECT_DRYRUN, "++lax" },
 {"port",              P_INTEGER,P_GLOBAL,&Globals.rsync_port,         NULL,0},        { CSF_STRICT_MODE|CSF_UPDATE|CSF_AFFECT_DRYRUN, "++strict" },
 {"socket options",    P_STRING, P_GLOBAL,&Globals.socket_options,     NULL,0},        { -1, NULL }
 
 {"auth users",        P_STRING, P_LOCAL, &sDefault.auth_users,        NULL,0}, 
 {"charset",           P_STRING, P_LOCAL, &sDefault.charset,           NULL,0}, 
 {"comment",           P_STRING, P_LOCAL, &sDefault.comment,           NULL,0}, 
 {"dont compress",     P_STRING, P_LOCAL, &sDefault.dont_compress,     NULL,0}, 
 {"exclude from",      P_STRING, P_LOCAL, &sDefault.exclude_from,      NULL,0}, 
 {"exclude",           P_STRING, P_LOCAL, &sDefault.exclude,           NULL,0}, 
 {"fake super",        P_BOOL,   P_LOCAL, &sDefault.fake_super,        NULL,0}, 
 {"filter",            P_STRING, P_LOCAL, &sDefault.filter,            NULL,0}, 
 {"gid",               P_STRING, P_LOCAL, &sDefault.gid,               NULL,0}, 
 {"hosts allow",       P_STRING, P_LOCAL, &sDefault.hosts_allow,       NULL,0}, 
 {"hosts deny",        P_STRING, P_LOCAL, &sDefault.hosts_deny,        NULL,0}, 
 {"ignore errors",     P_BOOL,   P_LOCAL, &sDefault.ignore_errors,     NULL,0}, 
 {"ignore nonreadable",P_BOOL,   P_LOCAL, &sDefault.ignore_nonreadable,NULL,0}, 
 {"include from",      P_STRING, P_LOCAL, &sDefault.include_from,      NULL,0}, 
 {"include",           P_STRING, P_LOCAL, &sDefault.include,           NULL,0}, 
 {"incoming chmod",    P_STRING, P_LOCAL, &sDefault.incoming_chmod,    NULL,0}, 
 {"list",              P_BOOL,   P_LOCAL, &sDefault.list,              NULL,0}, 
 {"lock file",         P_STRING, P_LOCAL, &sDefault.lock_file,         NULL,0}, 
 {"log file",          P_STRING, P_LOCAL, &sDefault.log_file,          NULL,0}, 
 {"log format",        P_STRING, P_LOCAL, &sDefault.log_format,        NULL,0}, 
 {"max connections",   P_INTEGER,P_LOCAL, &sDefault.max_connections,   NULL,0}, 
 {"max verbosity",     P_INTEGER,P_LOCAL, &sDefault.max_verbosity,     NULL,0}, 
 {"munge symlinks",    P_BOOL,   P_LOCAL, &sDefault.munge_symlinks,    NULL,0}, 
 {"name",              P_STRING, P_LOCAL, &sDefault.name,              NULL,0}, 
 {"numeric ids",       P_BOOL,   P_LOCAL, &sDefault.numeric_ids,       NULL,0}, 
 {"outgoing chmod",    P_STRING, P_LOCAL, &sDefault.outgoing_chmod,    NULL,0}, 
 {"path",              P_PATH,   P_LOCAL, &sDefault.path,              NULL,0}, 
#ifdef HAVE_PUTENV 
 {"post-xfer exec",    P_STRING, P_LOCAL, &sDefault.postxfer_exec,     NULL,0}, 
 {"pre-xfer exec",     P_STRING, P_LOCAL, &sDefault.prexfer_exec,      NULL,0}, 
#endif 
 {"read only",         P_BOOL,   P_LOCAL, &sDefault.read_only,         NULL,0}, 
 {"refuse options",    P_STRING, P_LOCAL, &sDefault.refuse_options,    NULL,0}, 
 {"secrets file",      P_STRING, P_LOCAL, &sDefault.secrets_file,      NULL,0}, 
 {"strict modes",      P_BOOL,   P_LOCAL, &sDefault.strict_modes,      NULL,0}, 
 {"syslog facility",   P_ENUM,   P_LOCAL, &sDefault.syslog_facility,enum_facilities,0}, 
 {"temp dir",          P_PATH,   P_LOCAL, &sDefault.temp_dir,          NULL,0}, 
 {"timeout",           P_INTEGER,P_LOCAL, &sDefault.timeout,           NULL,0}, 
 {"transfer logging",  P_BOOL,   P_LOCAL, &sDefault.transfer_logging,  NULL,0}, 
 {"uid",               P_STRING, P_LOCAL, &sDefault.uid,               NULL,0}, 
 {"use chroot",        P_BOOL,   P_LOCAL, &sDefault.use_chroot,        NULL,0}, 
 {"write only",        P_BOOL,   P_LOCAL, &sDefault.write_only,        NULL,0}, 
 {NULL,                P_BOOL,   P_NONE,  NULL,                        NULL,0} 
 };  };
   
/* Expand %VAR% references.  Any unknown vars or unrecognized
/*************************************************************************** * syntax leaves the raw chars unchanged. */
* Initialise the global parameter structure.static char *expand_vars(const char *str)
***************************************************************************/ 
static void init_globals(void) 
 {  {
        memset(&Globals, 0, sizeof Globals);        char *buf, *t;
}        const char *f;
         int bufsize;
   
/***************************************************************************        if (!str || !strchr(str, '%'))
* Initialise the sDefault parameter structure.                return (char *)str; /* TODO change return value to const char* at some point. */
***************************************************************************/ 
static void init_locals(void) 
{ 
} 
   
           bufsize = strlen(str) + 2048;
           buf = new_array(char, bufsize+1); /* +1 for trailing '\0' */
   
/*        for (t = buf, f = str; bufsize && *f; ) {
   In this section all the functions that are used to access the                if (*f == '%' && isUpper(f+1)) {
   parameters from the rest of the program are defined                        char *percent = strchr(f+1, '%');
*/                        if (percent && percent - f < bufsize) {
                                 char *val;
                                 strlcpy(t, f+1, percent - f);
                                 val = getenv(t);
                                 if (val) {
                                         int len = strlcpy(t, val, bufsize+1);
                                         if (len > bufsize)
                                                 break;
                                         bufsize -= len;
                                         t += len;
                                         f = percent + 1;
                                         continue;
                                 }
                         }
                 }
                 *t++ = *f++;
                 bufsize--;
         }
         *t = '\0';
   
#define FN_GLOBAL_STRING(fn_name,ptr) \        if (*f) {
 char *fn_name(void) {return(*(char **)(ptr) ? *(char **)(ptr) : "");}                rprintf(FLOG, "Overflowed buf in expand_vars() trying to expand: %s\n", str);
#define FN_GLOBAL_BOOL(fn_name,ptr) \                exit_cleanup(RERR_MALLOC);
 BOOL fn_name(void) {return(*(BOOL *)(ptr));}        }
#define FN_GLOBAL_CHAR(fn_name,ptr) \ 
 char fn_name(void) {return(*(char *)(ptr));} 
#define FN_GLOBAL_INTEGER(fn_name,ptr) \ 
 int fn_name(void) {return(*(int *)(ptr));} 
   
#define FN_LOCAL_STRING(fn_name,val) \        if (bufsize && (buf = realloc(buf, t - buf + 1)) == NULL)
 char *fn_name(int i) {return((LP_SNUM_OK(i)&&pSERVICE(i)->val)?pSERVICE(i)->val : (sDefault.val?sDefault.val:""));}                out_of_memory("expand_vars");
#define FN_LOCAL_BOOL(fn_name,val) \ 
 BOOL fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);} 
#define FN_LOCAL_CHAR(fn_name,val) \ 
 char fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);} 
#define FN_LOCAL_INTEGER(fn_name,val) \ 
 int fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);} 
   
           return buf;
   }
   
FN_GLOBAL_STRING(lp_bind_address, &Globals.bind_address)/* Each "char* foo" has an associated "BOOL foo_EXP" that tracks if the string has been expanded yet or not. */
FN_GLOBAL_STRING(lp_motd_file, &Globals.motd_file) 
FN_GLOBAL_STRING(lp_pid_file, &Globals.pid_file) 
FN_GLOBAL_STRING(lp_socket_options, &Globals.socket_options) 
   
FN_GLOBAL_INTEGER(lp_rsync_port, &Globals.rsync_port)/* NOTE: use this function and all the FN_{GLOBAL,LOCAL} ones WITHOUT a trailing semicolon! */
 #define RETURN_EXPANDED(val) {if (!val ## _EXP) {val = expand_vars(val); val ## _EXP = True;} return val ? val : "";}
   
FN_LOCAL_STRING(lp_auth_users, auth_users)/* In this section all the functions that are used to access the
FN_LOCAL_STRING(lp_charset, charset) * parameters from the rest of the program are defined. */
FN_LOCAL_STRING(lp_comment, comment) 
FN_LOCAL_STRING(lp_dont_compress, dont_compress) 
FN_LOCAL_STRING(lp_exclude, exclude) 
FN_LOCAL_STRING(lp_exclude_from, exclude_from) 
FN_LOCAL_STRING(lp_filter, filter) 
FN_LOCAL_STRING(lp_gid, gid) 
FN_LOCAL_STRING(lp_hosts_allow, hosts_allow) 
FN_LOCAL_STRING(lp_hosts_deny, hosts_deny) 
FN_LOCAL_STRING(lp_include, include) 
FN_LOCAL_STRING(lp_include_from, include_from) 
FN_LOCAL_STRING(lp_incoming_chmod, incoming_chmod) 
FN_LOCAL_STRING(lp_lock_file, lock_file) 
FN_LOCAL_STRING(lp_log_file, log_file) 
FN_LOCAL_STRING(lp_log_format, log_format) 
FN_LOCAL_STRING(lp_name, name) 
FN_LOCAL_STRING(lp_outgoing_chmod, outgoing_chmod) 
FN_LOCAL_STRING(lp_path, path) 
FN_LOCAL_STRING(lp_postxfer_exec, postxfer_exec) 
FN_LOCAL_STRING(lp_prexfer_exec, prexfer_exec) 
FN_LOCAL_STRING(lp_refuse_options, refuse_options) 
FN_LOCAL_STRING(lp_secrets_file, secrets_file) 
FN_LOCAL_STRING(lp_temp_dir, temp_dir) 
FN_LOCAL_STRING(lp_uid, uid) 
   
FN_LOCAL_INTEGER(lp_max_connections, max_connections)#define FN_GLOBAL_STRING(fn_name, val) \
FN_LOCAL_INTEGER(lp_max_verbosity, max_verbosity) char *fn_name(void) RETURN_EXPANDED(Vars.g.val)
FN_LOCAL_INTEGER(lp_syslog_facility, syslog_facility)#define FN_GLOBAL_BOOL(fn_name, val) \
FN_LOCAL_INTEGER(lp_timeout, timeout) BOOL fn_name(void) {return Vars.g.val;}
 #define FN_GLOBAL_CHAR(fn_name, val) \
  char fn_name(void) {return Vars.g.val;}
 #define FN_GLOBAL_INTEGER(fn_name, val) \
  int fn_name(void) {return Vars.g.val;}
   
FN_LOCAL_BOOL(lp_fake_super, fake_super)#define FN_LOCAL_STRING(fn_name, val) \
FN_LOCAL_BOOL(lp_ignore_errors, ignore_errors) char *fn_name(int i) {if (LP_SNUM_OK(i) && iSECTION(i).val) RETURN_EXPANDED(iSECTION(i).val) else RETURN_EXPANDED(Vars.l.val)}
FN_LOCAL_BOOL(lp_ignore_nonreadable, ignore_nonreadable)#define FN_LOCAL_BOOL(fn_name, val) \
FN_LOCAL_BOOL(lp_list, list) BOOL fn_name(int i) {return LP_SNUM_OK(i)? iSECTION(i).val : Vars.l.val;}
FN_LOCAL_BOOL(lp_munge_symlinks, munge_symlinks)#define FN_LOCAL_CHAR(fn_name, val) \
FN_LOCAL_BOOL(lp_numeric_ids, numeric_ids) char fn_name(int i) {return LP_SNUM_OK(i)? iSECTION(i).val : Vars.l.val;}
FN_LOCAL_BOOL(lp_read_only, read_only)#define FN_LOCAL_INTEGER(fn_name, val) \
FN_LOCAL_BOOL(lp_strict_modes, strict_modes) int fn_name(int i) {return LP_SNUM_OK(i)? iSECTION(i).val : Vars.l.val;}
FN_LOCAL_BOOL(lp_transfer_logging, transfer_logging) 
FN_LOCAL_BOOL(lp_use_chroot, use_chroot) 
FN_LOCAL_BOOL(lp_write_only, write_only) 
   
/* local prototypes *//* The following include file contains:
static int    strwicmp(char *psz1, char *psz2); *
static int    map_parameter(char *parmname); * typedef global_vars - describes global (ie., server-wide) parameters.
static BOOL   set_boolean(BOOL *pb, char *parmvalue); * typedef local_vars - describes a single section.
static int    getservicebyname(char *name, service *pserviceDest); * typedef all_vars - a combination of global_vars & local_vars.
static void   copy_service(service *pserviceDest, service *pserviceSource); * all_vars Defaults - the default values for all the variables.
static BOOL   do_parameter(char *parmname, char *parmvalue); * all_vars Vars - the currently configured values for all the variables.
static BOOL   do_section(char *sectionname); * struct parm_struct parm_table - the strings & variables for the parser.
  * FN_{LOCAL,GLOBAL}_{TYPE}() definition for all the lp_var_name() accessors.
  */
   
   #include "daemon-parm.h"
   
/***************************************************************************/* Initialise the Default all_vars structure. */
* initialise a service to the defaultsvoid reset_daemon_vars(void)
***************************************************************************/ 
static void init_service(service *pservice) 
 {  {
        memset((char *)pservice,0,sizeof(service));        memcpy(&Vars, &Defaults, sizeof Vars);
        copy_service(pservice,&sDefault); 
 }  }
   
/* Assign a copy of v to *s.  Handles NULL strings.  We don't worry
/** * about overwriting a malloc'd string because the long-running
 * Assign a copy of @p v to @p *s.  Handles NULL strings.  @p *v must * (port-listening) daemon only loads the config file once, and the
 * be initialized when this is called, either to NULL or a malloc'd * per-job (forked or xinitd-ran) daemon only re-reads the file at
 * string. * the start, so any lost memory is inconsequential. */
 *static inline void string_set(char **s, const char *v)
 * @fixme There is a small leak here in that sometimes the existing 
 * value will be dynamically allocated, and the old copy is lost. 
 * However, we can't always deallocate the old value, because in the 
 * case of sDefault, it points to a static string.  It would be nice 
 * to have either all-strdup'd values, or to never need to free 
 * memory. 
 **/ 
static void string_set(char **s, const char *v) 
 {  {
        if (!v) {        *s = v ? strdup(v) : NULL;
                *s = NULL; 
                return; 
        } 
        *s = strdup(v); 
        if (!*s) 
                exit_cleanup(RERR_MALLOC); 
 }  }
   
/* Copy local_vars into a new section. No need to strdup since we don't free. */
/***************************************************************************static void copy_section(local_vars *psectionDest, local_vars *psectionSource)
* add a new service to the services array initialising it with the given 
* service 
***************************************************************************/ 
static int add_a_service(service *pservice, char *name) 
 {  {
  int i;        memcpy(psectionDest, psectionSource, sizeof psectionDest[0]);
  service tservice;}
  int num_to_alloc = iNumServices+1; 
   
  tservice = *pservice;/* Initialise a section to the defaults. */
static void init_section(local_vars *psection)
  /* it might already exist */{
  if (name)        memset(psection, 0, sizeof (local_vars));
    {        copy_section(psection, &Vars.l);
      i = getservicebyname(name,NULL); 
      if (i >= 0) 
        return(i); 
    } 
 
  i = iNumServices; 
 
  ServicePtrs = realloc_array(ServicePtrs, service *, num_to_alloc); 
 
  if (ServicePtrs) 
          pSERVICE(iNumServices) = new(service); 
 
  if (!ServicePtrs || !pSERVICE(iNumServices)) 
          return(-1); 
 
  iNumServices++; 
 
  init_service(pSERVICE(i)); 
  copy_service(pSERVICE(i),&tservice); 
  if (name) 
    string_set(&iSERVICE(i).name,name); 
 
  return(i); 
 }  }
   
/***************************************************************************/* Do a case-insensitive, whitespace-ignoring string equality check. */
* Do a case-insensitive, whitespace-ignoring string compare.static int strwiEQ(char *psz1, char *psz2)
***************************************************************************/ 
static int strwicmp(char *psz1, char *psz2) 
 {  {
   /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */        /* If one or both strings are NULL, we return equality right away. */
   /* appropriate value. */        if (psz1 == psz2)
   if (psz1 == psz2)                return 1;
      return (0);        if (psz1 == NULL || psz2 == NULL)
   else                return 0;
      if (psz1 == NULL) 
         return (-1); 
      else 
          if (psz2 == NULL) 
              return (1); 
   
   /* sync the strings on first non-whitespace */        /* sync the strings on first non-whitespace */
   while (1)        while (1) {
   {                while (isSpace(psz1))
      while (isSpace(psz1))                        psz1++;
         psz1++;                while (isSpace(psz2))
      while (isSpace(psz2))                        psz2++;
         psz2++;                if (*psz1 == '\0' || *psz2 == '\0')
      if (toUpper(psz1) != toUpper(psz2) || *psz1 == '\0' || *psz2 == '\0')                        break;
         break;                if (toUpper(psz1) != toUpper(psz2))
      psz1++;                        break;
      psz2++;                psz1++;
   }                psz2++;
   return (*psz1 - *psz2);        }
         return *psz1 == *psz2;
 }  }
   
/***************************************************************************/* Find a section by name. Otherwise works like get_section. */
* Map a parameter's string representation to something we can use.static int getsectionbyname(char *name)
* Returns False if the parameter string is not recognised, else TRUE. 
***************************************************************************/ 
static int map_parameter(char *parmname) 
 {  {
   int iIndex;        int i;
   
   if (*parmname == '-')        for (i = section_list.count - 1; i >= 0; i--) {
     return(-1);                if (strwiEQ(iSECTION(i).name, name))
                         break;
         }
   
   for (iIndex = 0; parm_table[iIndex].label; iIndex++)        return i;
      if (strwicmp(parm_table[iIndex].label, parmname) == 0) 
         return(iIndex); 
 
   rprintf(FLOG, "Unknown Parameter encountered: \"%s\"\n", parmname); 
   return(-1); 
 }  }
   
/* Add a new section to the sections array w/the default values. */
/***************************************************************************static int add_a_section(char *name)
* Set a boolean variable from the text value stored in the passed string. 
* Returns True in success, False if the passed string does not correctly 
* represent a boolean. 
***************************************************************************/ 
static BOOL set_boolean(BOOL *pb, char *parmvalue) 
 {  {
   BOOL bRetval;        int i;
         local_vars *s;
   
   bRetval = True;        /* it might already exist */
   if (strwicmp(parmvalue, "yes") == 0 ||        if (name) {
       strwicmp(parmvalue, "true") == 0 ||                i = getsectionbyname(name);
       strwicmp(parmvalue, "1") == 0)                if (i >= 0)
      *pb = True;                        return i;
   else        }
      if (strwicmp(parmvalue, "no") == 0 || 
          strwicmp(parmvalue, "False") == 0 || 
          strwicmp(parmvalue, "0") == 0) 
         *pb = False; 
      else 
      { 
         rprintf(FLOG, "Badly formed boolean in configuration file: \"%s\".\n", 
               parmvalue); 
         bRetval = False; 
      } 
   return (bRetval); 
} 
   
/***************************************************************************        i = section_list.count;
* Find a service by name. Otherwise works like get_service.        s = EXPAND_ITEM_LIST(&section_list, local_vars, 2);
***************************************************************************/ 
static int getservicebyname(char *name, service *pserviceDest) 
{ 
   int iService; 
   
   for (iService = iNumServices - 1; iService >= 0; iService--)        init_section(s);
      if (strwicmp(iSERVICE(iService).name, name) == 0)        if (name)
      {                string_set(&s->name, name);
         if (pserviceDest != NULL) 
           copy_service(pserviceDest, pSERVICE(iService)); 
         break; 
      } 
   
   return (iService);        return i;
 }  }
   
/* Map a parameter's string representation to something we can use.
 * Returns False if the parameter string is not recognised, else TRUE. */
/***************************************************************************static int map_parameter(char *parmname)
* Copy a service structure to another 
***************************************************************************/ 
static void copy_service(service *pserviceDest, 
                         service *pserviceSource) 
 {  {
  int i;        int iIndex;
   
  for (i=0;parm_table[i].label;i++)        if (*parmname == '-')
    if (parm_table[i].ptr && parm_table[i].class == P_LOCAL) {                return -1;
        void *def_ptr = parm_table[i].ptr; 
        void *src_ptr = 
          ((char *)pserviceSource) + PTR_DIFF(def_ptr,&sDefault); 
        void *dest_ptr = 
          ((char *)pserviceDest) + PTR_DIFF(def_ptr,&sDefault); 
   
        switch (parm_table[i].type)        for (iIndex = 0; parm_table[iIndex].label; iIndex++) {
          {                if (strwiEQ(parm_table[iIndex].label, parmname))
          case P_BOOL:                        return iIndex;
          case P_BOOLREV:        }
            *(BOOL *)dest_ptr = *(BOOL *)src_ptr; 
            break; 
   
          case P_INTEGER:        rprintf(FLOG, "Unknown Parameter encountered: \"%s\"\n", parmname);
          case P_ENUM:        return -1;
          case P_OCTAL:}
            *(int *)dest_ptr = *(int *)src_ptr; 
            break; 
   
          case P_CHAR:/* Set a boolean variable from the text value stored in the passed string.
            *(char *)dest_ptr = *(char *)src_ptr; * Returns True in success, False if the passed string does not correctly
            break; * represent a boolean. */
static BOOL set_boolean(BOOL *pb, char *parmvalue, int allow_unset)
          case P_PATH:{
          case P_STRING:        if (strwiEQ(parmvalue, "yes") || strwiEQ(parmvalue, "true") || strwiEQ(parmvalue, "1"))
            string_set(dest_ptr,*(char **)src_ptr);                *pb = True;
            break;        else if (strwiEQ(parmvalue, "no") || strwiEQ(parmvalue, "false") || strwiEQ(parmvalue, "0"))
                *pb = False;
          default:        else if (allow_unset && (strwiEQ(parmvalue, "unset") || strwiEQ(parmvalue, "-1")))
            break;                *pb = Unset;
          }        else {
      }                rprintf(FLOG, "Badly formed boolean in configuration file: \"%s\".\n", parmvalue);
                 return False;
         }
         return True;
 }  }
   
/* Process a parameter. */
/***************************************************************************static BOOL do_parameter(char *parmname, char *parmvalue)
* Process a parameter for a particular service number. If snum < 0 
* then assume we are in the globals 
***************************************************************************/ 
static BOOL lp_do_parameter(int snum, char *parmname, char *parmvalue) 
 {  {
   int parmnum, i;        int parmnum, i;
   void *parm_ptr=NULL; /* where we are going to store the result */        void *parm_ptr; /* where we are going to store the result */
   void *def_ptr=NULL;        void *def_ptr;
   char *cp;        char *cp;
   
   parmnum = map_parameter(parmname);        parmnum = map_parameter(parmname);
   
   if (parmnum < 0)        if (parmnum < 0) {
     {                rprintf(FLOG, "IGNORING unknown parameter \"%s\"\n", parmname);
       rprintf(FLOG, "IGNORING unknown parameter \"%s\"\n", parmname);                return True;
       return(True);        }
     } 
   
   def_ptr = parm_table[parmnum].ptr;        def_ptr = parm_table[parmnum].ptr;
   
   /* we might point at a service, the default service or a global */        if (bInGlobalSection)
   if (snum < 0) {                parm_ptr = def_ptr;
     parm_ptr = def_ptr;        else {
   } else {                if (parm_table[parmnum].class == P_GLOBAL) {
       if (parm_table[parmnum].class == P_GLOBAL) {                        rprintf(FLOG, "Global parameter %s found in module section!\n", parmname);
           rprintf(FLOG, "Global parameter %s found in service section!\n",parmname);                        return True;
           return(True);                }
         }                parm_ptr = SECTION_PTR(&iSECTION(iSectionIndex), def_ptr);
       parm_ptr = ((char *)pSERVICE(snum)) + PTR_DIFF(def_ptr,&sDefault);        }
   } 
   
   /* now switch on the type of variable it is */        /* now switch on the type of variable it is */
   switch (parm_table[parmnum].type)        switch (parm_table[parmnum].type) {
     {        case P_PATH:
     case P_BOOL:        case P_STRING:
       set_boolean(parm_ptr,parmvalue);                /* delay expansion of %VAR% strings */
       break;                break;
         default:
                 /* expand any %VAR% strings now */
                 parmvalue = expand_vars(parmvalue);
                 break;
         }
   
     case P_BOOLREV:        switch (parm_table[parmnum].type) {
       set_boolean(parm_ptr,parmvalue);        case P_BOOL:
       *(BOOL *)parm_ptr = ! *(BOOL *)parm_ptr;                set_boolean(parm_ptr, parmvalue, False);
       break;                break;
   
     case P_INTEGER:        case P_BOOL3:
       *(int *)parm_ptr = atoi(parmvalue);                set_boolean(parm_ptr, parmvalue, True);
       break;                break;
   
     case P_CHAR:        case P_BOOLREV:
       *(char *)parm_ptr = *parmvalue;                set_boolean(parm_ptr, parmvalue, False);
       break;                *(BOOL *)parm_ptr = ! *(BOOL *)parm_ptr;
                 break;
   
     case P_OCTAL:        case P_INTEGER:
       sscanf(parmvalue,"%o",(int *)parm_ptr);                *(int *)parm_ptr = atoi(parmvalue);
       break;                break;
   
     case P_PATH:        case P_CHAR:
       string_set(parm_ptr,parmvalue);                *(char *)parm_ptr = *parmvalue;
       if ((cp = *(char**)parm_ptr) != NULL) {                break;
           int len = strlen(cp); 
           while (len > 1 && cp[len-1] == '/') len--; 
           cp[len] = '\0'; 
       } 
       break; 
   
     case P_STRING:        case P_OCTAL:
       string_set(parm_ptr,parmvalue);                sscanf(parmvalue, "%o", (int *)parm_ptr);
       break;                break;
   
     case P_GSTRING:        case P_PATH:
       strlcpy((char *)parm_ptr,parmvalue,sizeof(pstring));                string_set(parm_ptr, parmvalue);
       break;                if ((cp = *(char**)parm_ptr) != NULL) {
                         int len = strlen(cp);
                         while (len > 1 && cp[len-1] == '/') len--;
                         cp[len] = '\0';
                 }
                 break;
   
     case P_ENUM:        case P_STRING:
             for (i=0;parm_table[parmnum].enum_list[i].name;i++) {                string_set(parm_ptr, parmvalue);
                     if (strequal(parmvalue, parm_table[parmnum].enum_list[i].name)) {                break;
                             *(int *)parm_ptr = parm_table[parmnum].enum_list[i].value; 
                             break; 
                     } 
             } 
             if (!parm_table[parmnum].enum_list[i].name) { 
                     if (atoi(parmvalue) > 0) 
                             *(int *)parm_ptr = atoi(parmvalue); 
             } 
             break; 
     case P_SEP: 
             break; 
     } 
   
   return(True);        case P_ENUM:
}                for (i=0; parm_table[parmnum].enum_list[i].name; i++) {
                         if (strequal(parmvalue, parm_table[parmnum].enum_list[i].name)) {
                                 *(int *)parm_ptr = parm_table[parmnum].enum_list[i].value;
                                 break;
                         }
                 }
                 if (!parm_table[parmnum].enum_list[i].name) {
                         if (atoi(parmvalue) > 0)
                                 *(int *)parm_ptr = atoi(parmvalue);
                 }
                 break;
         }
   
/***************************************************************************        return True;
* Process a parameter. 
***************************************************************************/ 
static BOOL do_parameter(char *parmname, char *parmvalue) 
{ 
   return lp_do_parameter(bInGlobalSection?-2:iServiceIndex, parmname, parmvalue); 
 }  }
   
/***************************************************************************/* Process a new section (rsync module).
* Process a new section (service). At this stage all sections are services. * Returns True on success, False on failure. */
* Later we'll have special sections that permit server parameters to be set. 
* Returns True on success, False on failure. 
***************************************************************************/ 
 static BOOL do_section(char *sectionname)  static BOOL do_section(char *sectionname)
 {  {
   BOOL bRetval;        BOOL isglobal;
   BOOL isglobal = (strwicmp(sectionname, GLOBAL_NAME) == 0); 
   bRetval = False; 
   
   /* if we were in a global section then do the local inits */        if (*sectionname == ']') { /* A special push/pop/reset directive from params.c */
   if (bInGlobalSection && !isglobal)                bInGlobalSection = 1;
     init_locals();                if (strcmp(sectionname+1, "push") == 0) {
                         all_vars *vp = EXPAND_ITEM_LIST(&Vars_stack, all_vars, 2);
                         memcpy(vp, &Vars, sizeof Vars);
                 } else if (strcmp(sectionname+1, "pop") == 0
                  || strcmp(sectionname+1, "reset") == 0) {
                         all_vars *vp = ((all_vars*)Vars_stack.items) + Vars_stack.count - 1;
                         if (!Vars_stack.count)
                                 return False;
                         memcpy(&Vars, vp, sizeof Vars);
                         if (sectionname[1] == 'p')
                                 Vars_stack.count--;
                 } else
                         return False;
                 return True;
         }
   
   /* if we've just struck a global section, note the fact. */        isglobal = strwiEQ(sectionname, GLOBAL_NAME);
   bInGlobalSection = isglobal; 
   
   /* check for multiple global sections */        /* At the end of the global section, add any --dparam items. */
   if (bInGlobalSection)        if (bInGlobalSection && !isglobal) {
   {                if (!section_list.count)
     return(True);                        set_dparams(0);
   }        }
   
   if (strchr(sectionname, '/') != NULL) {        /* if we've just struck a global section, note the fact. */
     rprintf(FLOG, "Warning: invalid section name in configuration file: %s\n", sectionname);        bInGlobalSection = isglobal;
     return False; 
   } 
   
   /* if we have a current service, tidy it up before moving on */        /* check for multiple global sections */
   bRetval = True;        if (bInGlobalSection)
                 return True;
   
   if (iServiceIndex >= 0)#if 0
     bRetval = True;        /* If we have a current section, tidy it up before moving on. */
         if (iSectionIndex >= 0) {
                 /* Add any tidy work as needed ... */
                 if (problem)
                         return False;
         }
 #endif
   
   /* if all is still well, move to the next record in the services array */        if (strchr(sectionname, '/') != NULL) {
   if (bRetval)                rprintf(FLOG, "Warning: invalid section name in configuration file: %s\n", sectionname);
     {                return False;
       /* We put this here to avoid an odd message order if messages are */        }
       /* issued by the post-processing of a previous section. */ 
   
       if ((iServiceIndex=add_a_service(&sDefault,sectionname)) < 0)        if ((iSectionIndex = add_a_section(sectionname)) < 0) {
         {                rprintf(FLOG, "Failed to add a new module\n");
           rprintf(FLOG, "Failed to add a new service\n");                bInGlobalSection = True;
           return(False);                return False;
         }        }
     } 
   
   return (bRetval);        return True;
 }  }
   
/* Load the modules from the config file. Return True on success,
/*************************************************************************** * False on failure. */
* Load the services array from the services file. Return True on success,int lp_load(char *pszFname, int globals_only)
* False on failure. 
***************************************************************************/ 
BOOL lp_load(char *pszFname, int globals_only) 
 {  {
         pstring n2;  
         BOOL bRetval;  
   
         bRetval = False;  
   
         bInGlobalSection = True;          bInGlobalSection = True;
   
        init_globals();        reset_daemon_vars();
   
        pstrcpy(n2, pszFname);        /* We get sections first, so have to start 'behind' to make up. */
         iSectionIndex = -1;
         return pm_process(pszFname, globals_only ? NULL : do_section, do_parameter);
 }
   
        /* We get sections first, so have to start 'behind' to make up */BOOL set_dparams(int syntax_check_only)
        iServiceIndex = -1;{
        bRetval = pm_process(n2, globals_only?NULL:do_section, do_parameter);        char *equal, *val, **params = dparam_list.items;
         unsigned j;
   
        return (bRetval);        for (j = 0; j < dparam_list.count; j++) {
                 equal = strchr(params[j], '='); /* options.c verified this */
                 *equal = '\0';
                 if (syntax_check_only) {
                         if (map_parameter(params[j]) < 0) {
                                 rprintf(FERROR, "Unknown parameter \"%s\"\n", params[j]);
                                 *equal = '=';
                                 return False;
                         }
                 } else {
                         for (val = equal+1; isSpace(val); val++) {}
                         do_parameter(params[j], val);
                 }
                 *equal = '=';
         }
 
         return True;
 }  }
   
/* Return the max number of modules (sections). */
/***************************************************************************int lp_num_modules(void)
* return the max number of services 
***************************************************************************/ 
int lp_numservices(void) 
 {  {
  return(iNumServices);        return section_list.count;
 }  }
   
/***************************************************************************/* Return the number of the module with the given name, or -1 if it doesn't
* Return the number of the service with the given name, or -1 if it doesn't * exist. Note that this is a DIFFERENT ANIMAL from the internal function
* exist. Note that this is a DIFFERENT ANIMAL from the internal function * getsectionbyname()! This works ONLY if all sections have been loaded,
* getservicebyname()! This works ONLY if all services have been loaded, and * and does not copy the found section. */
* does not copy the found service. 
***************************************************************************/ 
 int lp_number(char *name)  int lp_number(char *name)
 {  {
   int iService;        int i;
   
   for (iService = iNumServices - 1; iService >= 0; iService--)        for (i = section_list.count - 1; i >= 0; i--) {
      if (strcmp(lp_name(iService), name) == 0)                if (strcmp(lp_name(i), name) == 0)
         break;                        break;
         }
   
   return (iService);        return i;
 }  }
   

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.4


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>