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

version 1.1.1.1, 2012/02/17 15:09:30 version 1.1.1.2, 2013/10/14 07:51:14
Line 17 Line 17
  * 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-2013 Wayne Davison <wayned@samba.org>
  */   */
   
 /* 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 stucture
 *    (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 "ifuncs.h"#include "itypes.h"
#define PTR_DIFF(p1,p2) ((ptrdiff_t)(((char *)(p1)) - (char *)(p2)))
#define strequal(a,b) (strcasecmp(a,b)==0)extern item_list dparam_list;
 
 #define strequal(a, b) (strcasecmp(a, b)==0)
 #define BOOLSTR(b) ((b) ? "Yes" : "No")  #define BOOLSTR(b) ((b) ? "Yes" : "No")
 typedef char pstring[1024];  
 #define pstrcpy(a,b) strlcpy(a,b,sizeof(pstring))  
   
 #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" \  #define DEFAULT_DONT_COMPRESS "*.gz *.zip *.z *.rpm *.deb *.iso *.bz2" \
        " *.t[gb]z *.7z *.mp[34] *.mov *.avi *.ogg *.jpg *.jpeg"        " *.t[gb]z *.7z *.mp[34] *.mov *.avi *.ogg *.jpg *.jpeg *.png" \
         " *.lzo *.rzip *.lzma *.rar *.ace *.gpg *.xz *.txz *.lz *.tlz"
   
 /* 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_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 72  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 86  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))
   
/*/* This structure describes global (ie., server-wide) parameters. */
 * This structure describes global (ie., server-wide) parameters.typedef struct {
 */ 
typedef struct 
{ 
         char *bind_address;          char *bind_address;
         char *motd_file;          char *motd_file;
         char *pid_file;          char *pid_file;
         char *socket_options;          char *socket_options;
   
           int listen_backlog;
         int rsync_port;          int rsync_port;
} global;} global_vars;
   
static global Globals;/* This structure describes a single section.  Their order must match the
 
 
/* 
 * This structure describes a single service.  Their order must match the 
  * initializers below, which you can accomplish by keeping each sub-section   * initializers below, which you can accomplish by keeping each sub-section
  * sorted.  (e.g. in vim, just visually select each subsection and use !sort.)   * sorted.  (e.g. in vim, just visually select each subsection and use !sort.)
 */ * NOTE: the char* variables MUST all remain at the start of the stuct! */
typedef structtypedef struct {
{ 
         char *auth_users;          char *auth_users;
         char *charset;          char *charset;
         char *comment;          char *comment;
Line 146  typedef struct Line 131  typedef struct
         char *secrets_file;          char *secrets_file;
         char *temp_dir;          char *temp_dir;
         char *uid;          char *uid;
   /* NOTE: update this macro if the last char* variable changes! */
   #define LOCAL_STRING_COUNT() (offsetof(local_vars, uid) / sizeof (char*) + 1)
   
         int max_connections;          int max_connections;
         int max_verbosity;          int max_verbosity;
Line 153  typedef struct Line 140  typedef struct
         int timeout;          int timeout;
   
         BOOL fake_super;          BOOL fake_super;
           BOOL forward_lookup;
         BOOL ignore_errors;          BOOL ignore_errors;
         BOOL ignore_nonreadable;          BOOL ignore_nonreadable;
         BOOL list;          BOOL list;
         BOOL munge_symlinks;          BOOL munge_symlinks;
         BOOL numeric_ids;          BOOL numeric_ids;
         BOOL read_only;          BOOL read_only;
           BOOL reverse_lookup;
         BOOL strict_modes;          BOOL strict_modes;
         BOOL transfer_logging;          BOOL transfer_logging;
         BOOL use_chroot;          BOOL use_chroot;
         BOOL write_only;          BOOL write_only;
} service;} local_vars;
   
   /* This structure describes the global variables (g) as well as the globally
    * specified values of the local variables (l), which are used when modules
    * don't specify their own values. */
   typedef struct {
           global_vars g;
           local_vars l;
   } all_vars;
   
/* This is a default service used to prime a services structure.  In order/* The application defaults for all the variables.  "Defaults" is
 * to make these easy to keep sorted in the same way as the variables * used to re-initialize "Vars" before each config-file read.
  *
  * In order to keep these sorted in the same way as the structure
  * above, use the variable name in the leading comment, including a   * above, use the variable name in the leading comment, including a
  * trailing ';' (to avoid a sorting problem with trailing digits). */   * trailing ';' (to avoid a sorting problem with trailing digits). */
static service sDefault =static const all_vars Defaults = {
{ /* ==== global_vars ==== */
  {
  /* bind_address; */            NULL,
  /* motd_file; */               NULL,
  /* pid_file; */                NULL,
  /* socket_options; */          NULL,
 
  /* listen_backlog; */          5,
  /* rsync_port; */              0,
  },
 
  /* ==== local_vars ==== */
  {
  /* auth_users; */              NULL,   /* auth_users; */              NULL,
  /* charset; */                 NULL,   /* charset; */                 NULL,
  /* comment; */                 NULL,   /* comment; */                 NULL,
Line 179  static service sDefault = Line 189  static service sDefault =
  /* exclude; */                 NULL,   /* exclude; */                 NULL,
  /* exclude_from; */            NULL,   /* exclude_from; */            NULL,
  /* filter; */                  NULL,   /* filter; */                  NULL,
 /* gid; */                     NOBODY_GROUP, /* gid; */                     NULL,
  /* hosts_allow; */             NULL,   /* hosts_allow; */             NULL,
  /* hosts_deny; */              NULL,   /* hosts_deny; */              NULL,
  /* include; */                 NULL,   /* include; */                 NULL,
Line 196  static service sDefault = Line 206  static service sDefault =
  /* refuse_options; */          NULL,   /* refuse_options; */          NULL,
  /* secrets_file; */            NULL,   /* secrets_file; */            NULL,
  /* temp_dir; */                NULL,   /* temp_dir; */                NULL,
 /* uid; */                     NOBODY_USER, /* uid; */                     NULL,
   
  /* max_connections; */         0,   /* max_connections; */         0,
  /* max_verbosity; */           1,   /* max_verbosity; */           1,
Line 204  static service sDefault = Line 214  static service sDefault =
  /* timeout; */                 0,   /* timeout; */                 0,
   
  /* fake_super; */              False,   /* fake_super; */              False,
    /* forward_lookup; */          True,
  /* ignore_errors; */           False,   /* ignore_errors; */           False,
  /* ignore_nonreadable; */      False,   /* ignore_nonreadable; */      False,
  /* list; */                    True,   /* list; */                    True,
  /* munge_symlinks; */          (BOOL)-1,   /* munge_symlinks; */          (BOOL)-1,
  /* numeric_ids; */             (BOOL)-1,   /* numeric_ids; */             (BOOL)-1,
  /* read_only; */               True,   /* read_only; */               True,
    /* reverse_lookup; */          True,
  /* strict_modes; */            True,   /* strict_modes; */            True,
  /* transfer_logging; */        False,   /* transfer_logging; */        False,
  /* use_chroot; */              True,   /* use_chroot; */              True,
  /* write_only; */              False,   /* write_only; */              False,
    }
 };  };
   
   /* The currently configured values for all the variables. */
   static all_vars Vars;
   
   /* Stack of "Vars" values used by the &include directive. */
   static item_list Vars_stack = EMPTY_ITEM_LIST;
   
/* local variables *//* The array of section values that holds all the defined modules. */
static service **ServicePtrs = NULL;static item_list section_list = EMPTY_ITEM_LIST;
static int iNumServices = 0;
static int iServiceIndex = 0;static int iSectionIndex = -1;
 static BOOL bInGlobalSection = True;  static BOOL bInGlobalSection = True;
   
#define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))#define NUMPARAMETERS (sizeof (parm_table) / sizeof (struct parm_struct))
   
 static struct enum_list enum_facilities[] = {  static struct enum_list enum_facilities[] = {
 #ifdef LOG_AUTH  #ifdef LOG_AUTH
Line 290  static struct enum_list enum_facilities[] = { Line 307  static struct enum_list enum_facilities[] = {
 #ifdef LOG_LOCAL7  #ifdef LOG_LOCAL7
         { LOG_LOCAL7, "local7" },          { LOG_LOCAL7, "local7" },
 #endif  #endif
        { -1, NULL }};        { -1, NULL }
 };
   
   
 /* note that we do not initialise the defaults union - it is not allowed in ANSI C */  
 static struct parm_struct parm_table[] =  static struct parm_struct parm_table[] =
 {  {
 {"address",           P_STRING, P_GLOBAL,&Globals.bind_address,       NULL,0}, {"address",           P_STRING, P_GLOBAL,&Vars.g.bind_address,        NULL,0},
 {"motd file",         P_STRING, P_GLOBAL,&Globals.motd_file,          NULL,0}, {"listen backlog",    P_INTEGER,P_GLOBAL,&Vars.g.listen_backlog,      NULL,0},
 {"pid file",          P_STRING, P_GLOBAL,&Globals.pid_file,           NULL,0}, {"motd file",         P_STRING, P_GLOBAL,&Vars.g.motd_file,           NULL,0},
 {"port",              P_INTEGER,P_GLOBAL,&Globals.rsync_port,         NULL,0}, {"pid file",          P_STRING, P_GLOBAL,&Vars.g.pid_file,            NULL,0},
 {"socket options",    P_STRING, P_GLOBAL,&Globals.socket_options,     NULL,0}, {"port",              P_INTEGER,P_GLOBAL,&Vars.g.rsync_port,          NULL,0},
  {"socket options",    P_STRING, P_GLOBAL,&Vars.g.socket_options,      NULL,0},
   
 {"auth users",        P_STRING, P_LOCAL, &sDefault.auth_users,        NULL,0}, {"auth users",        P_STRING, P_LOCAL, &Vars.l.auth_users,          NULL,0},
 {"charset",           P_STRING, P_LOCAL, &sDefault.charset,           NULL,0}, {"charset",           P_STRING, P_LOCAL, &Vars.l.charset,             NULL,0},
 {"comment",           P_STRING, P_LOCAL, &sDefault.comment,           NULL,0}, {"comment",           P_STRING, P_LOCAL, &Vars.l.comment,             NULL,0},
 {"dont compress",     P_STRING, P_LOCAL, &sDefault.dont_compress,     NULL,0}, {"dont compress",     P_STRING, P_LOCAL, &Vars.l.dont_compress,       NULL,0},
 {"exclude from",      P_STRING, P_LOCAL, &sDefault.exclude_from,      NULL,0}, {"exclude from",      P_STRING, P_LOCAL, &Vars.l.exclude_from,        NULL,0},
 {"exclude",           P_STRING, P_LOCAL, &sDefault.exclude,           NULL,0}, {"exclude",           P_STRING, P_LOCAL, &Vars.l.exclude,             NULL,0},
 {"fake super",        P_BOOL,   P_LOCAL, &sDefault.fake_super,        NULL,0}, {"fake super",        P_BOOL,   P_LOCAL, &Vars.l.fake_super,          NULL,0},
 {"filter",            P_STRING, P_LOCAL, &sDefault.filter,            NULL,0}, {"filter",            P_STRING, P_LOCAL, &Vars.l.filter,              NULL,0},
 {"gid",               P_STRING, P_LOCAL, &sDefault.gid,               NULL,0}, {"forward lookup",    P_BOOL,   P_LOCAL, &Vars.l.forward_lookup,      NULL,0},
 {"hosts allow",       P_STRING, P_LOCAL, &sDefault.hosts_allow,       NULL,0}, {"gid",               P_STRING, P_LOCAL, &Vars.l.gid,                 NULL,0},
 {"hosts deny",        P_STRING, P_LOCAL, &sDefault.hosts_deny,        NULL,0}, {"hosts allow",       P_STRING, P_LOCAL, &Vars.l.hosts_allow,         NULL,0},
 {"ignore errors",     P_BOOL,   P_LOCAL, &sDefault.ignore_errors,     NULL,0}, {"hosts deny",        P_STRING, P_LOCAL, &Vars.l.hosts_deny,          NULL,0},
 {"ignore nonreadable",P_BOOL,   P_LOCAL, &sDefault.ignore_nonreadable,NULL,0}, {"ignore errors",     P_BOOL,   P_LOCAL, &Vars.l.ignore_errors,       NULL,0},
 {"include from",      P_STRING, P_LOCAL, &sDefault.include_from,      NULL,0}, {"ignore nonreadable",P_BOOL,   P_LOCAL, &Vars.l.ignore_nonreadable,  NULL,0},
 {"include",           P_STRING, P_LOCAL, &sDefault.include,           NULL,0}, {"include from",      P_STRING, P_LOCAL, &Vars.l.include_from,        NULL,0},
 {"incoming chmod",    P_STRING, P_LOCAL, &sDefault.incoming_chmod,    NULL,0}, {"include",           P_STRING, P_LOCAL, &Vars.l.include,             NULL,0},
 {"list",              P_BOOL,   P_LOCAL, &sDefault.list,              NULL,0}, {"incoming chmod",    P_STRING, P_LOCAL, &Vars.l.incoming_chmod,      NULL,0},
 {"lock file",         P_STRING, P_LOCAL, &sDefault.lock_file,         NULL,0}, {"list",              P_BOOL,   P_LOCAL, &Vars.l.list,                NULL,0},
 {"log file",          P_STRING, P_LOCAL, &sDefault.log_file,          NULL,0}, {"lock file",         P_STRING, P_LOCAL, &Vars.l.lock_file,           NULL,0},
 {"log format",        P_STRING, P_LOCAL, &sDefault.log_format,        NULL,0}, {"log file",          P_STRING, P_LOCAL, &Vars.l.log_file,            NULL,0},
 {"max connections",   P_INTEGER,P_LOCAL, &sDefault.max_connections,   NULL,0}, {"log format",        P_STRING, P_LOCAL, &Vars.l.log_format,          NULL,0},
 {"max verbosity",     P_INTEGER,P_LOCAL, &sDefault.max_verbosity,     NULL,0}, {"max connections",   P_INTEGER,P_LOCAL, &Vars.l.max_connections,     NULL,0},
 {"munge symlinks",    P_BOOL,   P_LOCAL, &sDefault.munge_symlinks,    NULL,0}, {"max verbosity",     P_INTEGER,P_LOCAL, &Vars.l.max_verbosity,       NULL,0},
 {"name",              P_STRING, P_LOCAL, &sDefault.name,              NULL,0}, {"munge symlinks",    P_BOOL,   P_LOCAL, &Vars.l.munge_symlinks,      NULL,0},
 {"numeric ids",       P_BOOL,   P_LOCAL, &sDefault.numeric_ids,       NULL,0}, {"name",              P_STRING, P_LOCAL, &Vars.l.name,                NULL,0},
 {"outgoing chmod",    P_STRING, P_LOCAL, &sDefault.outgoing_chmod,    NULL,0}, {"numeric ids",       P_BOOL,   P_LOCAL, &Vars.l.numeric_ids,         NULL,0},
 {"path",              P_PATH,   P_LOCAL, &sDefault.path,              NULL,0}, {"outgoing chmod",    P_STRING, P_LOCAL, &Vars.l.outgoing_chmod,      NULL,0},
  {"path",              P_PATH,   P_LOCAL, &Vars.l.path,                NULL,0},
 #ifdef HAVE_PUTENV  #ifdef HAVE_PUTENV
 {"post-xfer exec",    P_STRING, P_LOCAL, &sDefault.postxfer_exec,     NULL,0}, {"post-xfer exec",    P_STRING, P_LOCAL, &Vars.l.postxfer_exec,       NULL,0},
 {"pre-xfer exec",     P_STRING, P_LOCAL, &sDefault.prexfer_exec,      NULL,0}, {"pre-xfer exec",     P_STRING, P_LOCAL, &Vars.l.prexfer_exec,        NULL,0},
 #endif  #endif
 {"read only",         P_BOOL,   P_LOCAL, &sDefault.read_only,         NULL,0}, {"read only",         P_BOOL,   P_LOCAL, &Vars.l.read_only,           NULL,0},
 {"refuse options",    P_STRING, P_LOCAL, &sDefault.refuse_options,    NULL,0}, {"refuse options",    P_STRING, P_LOCAL, &Vars.l.refuse_options,      NULL,0},
 {"secrets file",      P_STRING, P_LOCAL, &sDefault.secrets_file,      NULL,0}, {"reverse lookup",    P_BOOL,   P_LOCAL, &Vars.l.reverse_lookup,      NULL,0},
 {"strict modes",      P_BOOL,   P_LOCAL, &sDefault.strict_modes,      NULL,0}, {"secrets file",      P_STRING, P_LOCAL, &Vars.l.secrets_file,        NULL,0},
 {"syslog facility",   P_ENUM,   P_LOCAL, &sDefault.syslog_facility,enum_facilities,0}, {"strict modes",      P_BOOL,   P_LOCAL, &Vars.l.strict_modes,        NULL,0},
 {"temp dir",          P_PATH,   P_LOCAL, &sDefault.temp_dir,          NULL,0}, {"syslog facility",   P_ENUM,   P_LOCAL, &Vars.l.syslog_facility,     enum_facilities,0},
 {"timeout",           P_INTEGER,P_LOCAL, &sDefault.timeout,           NULL,0}, {"temp dir",          P_PATH,   P_LOCAL, &Vars.l.temp_dir,            NULL,0},
 {"transfer logging",  P_BOOL,   P_LOCAL, &sDefault.transfer_logging,  NULL,0}, {"timeout",           P_INTEGER,P_LOCAL, &Vars.l.timeout,             NULL,0},
 {"uid",               P_STRING, P_LOCAL, &sDefault.uid,               NULL,0}, {"transfer logging",  P_BOOL,   P_LOCAL, &Vars.l.transfer_logging,    NULL,0},
 {"use chroot",        P_BOOL,   P_LOCAL, &sDefault.use_chroot,        NULL,0}, {"uid",               P_STRING, P_LOCAL, &Vars.l.uid,                 NULL,0},
 {"write only",        P_BOOL,   P_LOCAL, &sDefault.write_only,        NULL,0}, {"use chroot",        P_BOOL,   P_LOCAL, &Vars.l.use_chroot,          NULL,0},
  {"write only",        P_BOOL,   P_LOCAL, &Vars.l.write_only,          NULL,0},
  {NULL,                P_BOOL,   P_NONE,  NULL,                        NULL,0}   {NULL,                P_BOOL,   P_NONE,  NULL,                        NULL,0}
 };  };
   
/* Initialise the Default all_vars structure. */
/***************************************************************************static void reset_all_vars(void)
* Initialise the global parameter structure. 
***************************************************************************/ 
static void init_globals(void) 
 {  {
        memset(&Globals, 0, sizeof Globals);        memcpy(&Vars, &Defaults, sizeof Vars);
 }  }
   
/***************************************************************************/* Expand %VAR% references.  Any unknown vars or unrecognized
* Initialise the sDefault parameter structure. * syntax leaves the raw chars unchanged. */
***************************************************************************/static char *expand_vars(char *str)
static void init_locals(void) 
 {  {
}        char *buf, *t, *f;
         int bufsize;
   
           if (strchr(str, '%') == NULL)
                   return str;
   
/*        bufsize = strlen(str) + 2048;
   In this section all the functions that are used to access the        if ((buf = new_array(char, bufsize+1)) == NULL) /* +1 for trailing '\0' */
   parameters from the rest of the program are defined                out_of_memory("expand_vars");
*/ 
   
#define FN_GLOBAL_STRING(fn_name,ptr) \        for (t = buf, f = str; bufsize && *f; ) {
 char *fn_name(void) {return(*(char **)(ptr) ? *(char **)(ptr) : "");}                if (*f == '%' && *++f != '%') {
#define FN_GLOBAL_BOOL(fn_name,ptr) \                        char *percent = strchr(f, '%');
 BOOL fn_name(void) {return(*(BOOL *)(ptr));}                        if (percent) {
#define FN_GLOBAL_CHAR(fn_name,ptr) \                                char *val;
 char fn_name(void) {return(*(char *)(ptr));}                                *percent = '\0';
#define FN_GLOBAL_INTEGER(fn_name,ptr) \                                val = getenv(f);
 int fn_name(void) {return(*(int *)(ptr));}                                *percent = '%';
                                 if (val) {
                                         int len = strlcpy(t, val, bufsize+1);
                                         if (len > bufsize)
                                                 break;
                                         bufsize -= len;
                                         t += len;
                                         f = percent + 1;
                                         continue;
                                 }
                         }
                         f--;
                 }
                 *t++ = *f++;
                 bufsize--;
         }
         *t = '\0';
   
#define FN_LOCAL_STRING(fn_name,val) \        if (*f) {
 char *fn_name(int i) {return((LP_SNUM_OK(i)&&pSERVICE(i)->val)?pSERVICE(i)->val : (sDefault.val?sDefault.val:""));}                rprintf(FLOG, "Overflowed buf in expand_vars() trying to expand: %s\n", str);
#define FN_LOCAL_BOOL(fn_name,val) \                exit_cleanup(RERR_MALLOC);
 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);} 
   
           if (bufsize && (buf = realloc(buf, t - buf + 1)) == NULL)
                   out_of_memory("expand_vars");
   
FN_GLOBAL_STRING(lp_bind_address, &Globals.bind_address)        return buf;
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)/* In this section all the functions that are used to access the
  * parameters from the rest of the program are defined. */
   
   #define FN_GLOBAL_STRING(fn_name, ptr) \
    char *fn_name(void) {return expand_vars(*(char **)(ptr) ? *(char **)(ptr) : "");}
   #define FN_GLOBAL_BOOL(fn_name, ptr) \
    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) \
    char *fn_name(int i) {return expand_vars(LP_SNUM_OK(i) && iSECTION(i).val ? iSECTION(i).val : Vars.l.val ? Vars.l.val : "");}
   #define FN_LOCAL_BOOL(fn_name, val) \
    BOOL fn_name(int i) {return LP_SNUM_OK(i)? iSECTION(i).val : Vars.l.val;}
   #define FN_LOCAL_CHAR(fn_name, val) \
    char fn_name(int i) {return LP_SNUM_OK(i)? iSECTION(i).val : Vars.l.val;}
   #define FN_LOCAL_INTEGER(fn_name, val) \
    int fn_name(int i) {return LP_SNUM_OK(i)? iSECTION(i).val : Vars.l.val;}
   
   FN_GLOBAL_STRING(lp_bind_address, &Vars.g.bind_address)
   FN_GLOBAL_STRING(lp_motd_file, &Vars.g.motd_file)
   FN_GLOBAL_STRING(lp_pid_file, &Vars.g.pid_file)
   FN_GLOBAL_STRING(lp_socket_options, &Vars.g.socket_options)
   
   FN_GLOBAL_INTEGER(lp_listen_backlog, &Vars.g.listen_backlog)
   FN_GLOBAL_INTEGER(lp_rsync_port, &Vars.g.rsync_port)
   
 FN_LOCAL_STRING(lp_auth_users, auth_users)  FN_LOCAL_STRING(lp_auth_users, auth_users)
 FN_LOCAL_STRING(lp_charset, charset)  FN_LOCAL_STRING(lp_charset, charset)
 FN_LOCAL_STRING(lp_comment, comment)  FN_LOCAL_STRING(lp_comment, comment)
Line 427  FN_LOCAL_INTEGER(lp_syslog_facility, syslog_facility) Line 483  FN_LOCAL_INTEGER(lp_syslog_facility, syslog_facility)
 FN_LOCAL_INTEGER(lp_timeout, timeout)  FN_LOCAL_INTEGER(lp_timeout, timeout)
   
 FN_LOCAL_BOOL(lp_fake_super, fake_super)  FN_LOCAL_BOOL(lp_fake_super, fake_super)
   FN_LOCAL_BOOL(lp_forward_lookup, forward_lookup)
 FN_LOCAL_BOOL(lp_ignore_errors, ignore_errors)  FN_LOCAL_BOOL(lp_ignore_errors, ignore_errors)
 FN_LOCAL_BOOL(lp_ignore_nonreadable, ignore_nonreadable)  FN_LOCAL_BOOL(lp_ignore_nonreadable, ignore_nonreadable)
 FN_LOCAL_BOOL(lp_list, list)  FN_LOCAL_BOOL(lp_list, list)
 FN_LOCAL_BOOL(lp_munge_symlinks, munge_symlinks)  FN_LOCAL_BOOL(lp_munge_symlinks, munge_symlinks)
 FN_LOCAL_BOOL(lp_numeric_ids, numeric_ids)  FN_LOCAL_BOOL(lp_numeric_ids, numeric_ids)
 FN_LOCAL_BOOL(lp_read_only, read_only)  FN_LOCAL_BOOL(lp_read_only, read_only)
   FN_LOCAL_BOOL(lp_reverse_lookup, reverse_lookup)
 FN_LOCAL_BOOL(lp_strict_modes, strict_modes)  FN_LOCAL_BOOL(lp_strict_modes, strict_modes)
 FN_LOCAL_BOOL(lp_transfer_logging, transfer_logging)  FN_LOCAL_BOOL(lp_transfer_logging, transfer_logging)
 FN_LOCAL_BOOL(lp_use_chroot, use_chroot)  FN_LOCAL_BOOL(lp_use_chroot, use_chroot)
 FN_LOCAL_BOOL(lp_write_only, write_only)  FN_LOCAL_BOOL(lp_write_only, write_only)
   
/* local prototypes *//* Assign a copy of v to *s.  Handles NULL strings.  We don't worry
static int    strwicmp(char *psz1, char *psz2); * about overwriting a malloc'd string because the long-running
static int    map_parameter(char *parmname); * (port-listening) daemon only loads the config file once, and the
static BOOL   set_boolean(BOOL *pb, char *parmvalue); * per-job (forked or xinitd-ran) daemon only re-reads the file at
static int    getservicebyname(char *name, service *pserviceDest); * the start, so any lost memory is inconsequential. */
static void   copy_service(service *pserviceDest, service *pserviceSource);static inline void string_set(char **s, const char *v)
static BOOL   do_parameter(char *parmname, char *parmvalue); 
static BOOL   do_section(char *sectionname); 
 
 
/*************************************************************************** 
* initialise a service to the defaults 
***************************************************************************/ 
static void init_service(service *pservice) 
 {  {
        memset((char *)pservice,0,sizeof(service));        if (!v)
        copy_service(pservice,&sDefault);                *s = NULL;
         else if (!(*s = strdup(v)))
                 out_of_memory("string_set");
 }  }
   
/* Copy the local_vars, strdup'ing any strings.  NOTE:  this depends on
/** * the structure starting with a contiguous list of the char* variables,
 * Assign a copy of @p v to @p *s.  Handles NULL strings.  @p *v must * and having an accurate count in the LOCAL_STRING_COUNT() macro. */
 * be initialized when this is called, either to NULL or a malloc'dstatic void copy_section(local_vars *psectionDest, local_vars *psectionSource)
 * string. 
 * 
 * @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) {        int count = LOCAL_STRING_COUNT();
                *s = NULL;        char **strings = (char**)psectionDest;
                return;
         memcpy(psectionDest, psectionSource, sizeof psectionDest[0]);
         while (count--) {
                 if (strings[count] && !(strings[count] = strdup(strings[count])))
                         out_of_memory("copy_section");
         }          }
         *s = strdup(v);  
         if (!*s)  
                 exit_cleanup(RERR_MALLOC);  
 }  }
   
/* Initialise a section to the defaults. */
/***************************************************************************static void init_section(local_vars *psection)
* 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;        memset(psection, 0, sizeof (local_vars));
  service tservice;        copy_section(psection, &Vars.l);
  int num_to_alloc = iNumServices+1; 
 
  tservice = *pservice; 
 
  /* it might already exist */ 
  if (name) 
    { 
      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 compare. */
* Do a case-insensitive, whitespace-ignoring string compare. 
***************************************************************************/ 
 static int strwicmp(char *psz1, char *psz2)  static int strwicmp(char *psz1, char *psz2)
 {  {
   /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */        /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
   /* appropriate value. */        /* appropriate value. */
   if (psz1 == psz2)        if (psz1 == psz2)
      return (0);                return 0;
   else 
      if (psz1 == NULL) 
         return (-1); 
      else 
          if (psz2 == NULL) 
              return (1); 
   
   /* sync the strings on first non-whitespace */        if (psz1 == NULL)
   while (1)                return -1;
   {
      while (isSpace(psz1))        if (psz2 == NULL)
         psz1++;                return 1;
      while (isSpace(psz2))
         psz2++;        /* sync the strings on first non-whitespace */
      if (toUpper(psz1) != toUpper(psz2) || *psz1 == '\0' || *psz2 == '\0')        while (1) {
         break;                while (isSpace(psz1))
      psz1++;                        psz1++;
      psz2++;                while (isSpace(psz2))
   }                        psz2++;
   return (*psz1 - *psz2);                if (toUpper(psz1) != toUpper(psz2) || *psz1 == '\0' || *psz2 == '\0')
                         break;
                 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 (strwicmp(iSECTION(i).name, name) == 0)
                         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 (strwicmp(parm_table[iIndex].label, parmname) == 0)
          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)
          case P_PATH:{
          case P_STRING:        if (strwicmp(parmvalue, "yes") == 0
            string_set(dest_ptr,*(char **)src_ptr);         || strwicmp(parmvalue, "true") == 0
            break;         || strwicmp(parmvalue, "1") == 0)
                *pb = True;
          default:        else if (strwicmp(parmvalue, "no") == 0
            break;              || strwicmp(parmvalue, "False") == 0
          }              || strwicmp(parmvalue, "0") == 0)
      }                *pb = False;
         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 vars */
       break;                break;
         default:
                 /* expand any %VARS% 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);
       break;                break;
   
     case P_INTEGER:        case P_BOOLREV:
       *(int *)parm_ptr = atoi(parmvalue);                set_boolean(parm_ptr, parmvalue);
       break;                *(BOOL *)parm_ptr = ! *(BOOL *)parm_ptr;
                 break;
   
     case P_CHAR:        case P_INTEGER:
       *(char *)parm_ptr = *parmvalue;                *(int *)parm_ptr = atoi(parmvalue);
       break;                break;
   
     case P_OCTAL:        case P_CHAR:
       sscanf(parmvalue,"%o",(int *)parm_ptr);                *(char *)parm_ptr = *parmvalue;
       break;                break;
   
     case P_PATH:        case P_OCTAL:
       string_set(parm_ptr,parmvalue);                sscanf(parmvalue, "%o", (int *)parm_ptr);
       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_PATH:
       string_set(parm_ptr,parmvalue);                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_GSTRING:        case P_STRING:
       strlcpy((char *)parm_ptr,parmvalue,sizeof(pstring));                string_set(parm_ptr, parmvalue);
       break;                break;
   
     case P_ENUM:        case P_ENUM:
             for (i=0;parm_table[parmnum].enum_list[i].name;i++) {                for (i=0; parm_table[parmnum].enum_list[i].name; i++) {
                     if (strequal(parmvalue, parm_table[parmnum].enum_list[i].name)) {                        if (strequal(parmvalue, parm_table[parmnum].enum_list[i].name)) {
                             *(int *)parm_ptr = parm_table[parmnum].enum_list[i].value;                                *(int *)parm_ptr = parm_table[parmnum].enum_list[i].value;
                             break;                                break;
                     }                        }
             }                }
             if (!parm_table[parmnum].enum_list[i].name) {                if (!parm_table[parmnum].enum_list[i].name) {
                     if (atoi(parmvalue) > 0)                        if (atoi(parmvalue) > 0)
                             *(int *)parm_ptr = atoi(parmvalue);                                *(int *)parm_ptr = atoi(parmvalue);
             }                }
             break;                break;
     case P_SEP:        }
             break; 
     } 
   
   return(True);        return True;
 }  }
   
/***************************************************************************/* Process a new section (rsync module).
* Process a parameter. * Returns True on success, False on failure. */
***************************************************************************/ 
static BOOL do_parameter(char *parmname, char *parmvalue) 
{ 
   return lp_do_parameter(bInGlobalSection?-2:iServiceIndex, parmname, parmvalue); 
} 
 
/*************************************************************************** 
* Process a new section (service). At this stage all sections are services. 
* 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 = strwicmp(sectionname, GLOBAL_NAME) == 0;
   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_all_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.2


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